sort downloadmanager items correctly, improve performance more
Mwebclient/src/components/DownloadManager.tsx
@@ -36,8 +36,27 @@ export default function DownloadManager(props: DownloadManagerProps) {
props.setShowDownloadManager(false);
}
const downloadItems = createMemo(() => {
return Object.entries(downloadStatusMap).filter(([_path, status]) => isProgress(status));
const downloadKeys = createMemo(() => {
const keys = Object.keys(downloadStatusMap);
const progressKeys = keys.filter((key) => isProgress(downloadStatusMap[key]));
// Sort the keys: Running first (by path), then Failed (by path), then Aborted (by path)
progressKeys.sort((pathA, pathB) => {
const statusA = downloadStatusMap[pathA] as Progress;
const statusB = downloadStatusMap[pathB] as Progress;
// 0: Running, 1: Failed, 2: Aborted
const typeA = typeof statusA.status === "number" ? 0 : statusA.status === "Failed" ? 1 : 2;
const typeB = typeof statusB.status === "number" ? 0 : statusB.status === "Failed" ? 1 : 2;
if (typeA !== typeB) {
return typeA - typeB; // Sort by type first
}
// If types are the same, sort by path numerically/alphabetically
return pathA.localeCompare(pathB, undefined, { numeric: true });
});
return progressKeys;
});
function isProgress(status: DownloadStatus | undefined): status is Progress {
@@ -59,8 +78,9 @@ export default function DownloadManager(props: DownloadManagerProps) {
title="Retry all failed/aborted downloads"
onClick={() => {
batch(() => {
for (const [, status] of downloadItems()) {
if (isProgress(status) && "retry" in status) status.retry();
for (const path of downloadKeys()) {
const status = downloadStatusMap[path] as Progress;
if ("retry" in status) status.retry();
}
});
}}
@@ -71,8 +91,9 @@ export default function DownloadManager(props: DownloadManagerProps) {
title="stop all running downloads"
onClick={async () => {
batch(async () => {
for (const [, status] of downloadItems()) {
if (isProgress(status) && typeof status.status === "number") {
for (const path of downloadKeys()) {
const status = downloadStatusMap[path] as Progress;
if (typeof status.status === "number") {
status.abort();
}
}
@@ -85,9 +106,9 @@ export default function DownloadManager(props: DownloadManagerProps) {
title="Clear all failed/aborted downloads"
onClick={() => {
batch(() => {
for (const [path, status] of downloadItems()) {
if (isProgress(status) && (status.status === "Aborted" || status.status === "Failed"))
setDownloadStatusMap(path, undefined);
for (const path of downloadKeys()) {
const status = downloadStatusMap[path] as Progress;
if (status.status === "Aborted" || status.status === "Failed") setDownloadStatusMap(path, undefined);
}
});
}}
@@ -100,10 +121,10 @@ export default function DownloadManager(props: DownloadManagerProps) {
</div>
<hr />
<div class="downloadmanager-content">
<For each={downloadItems()}>
{([path, status]) => {
if (!isProgress(status)) return;
<For each={downloadKeys()}>
{(path) => {
const [showReason, setShowReason] = createSignal(false);
const status = downloadStatusMap[path] as Progress;
return (
<div
classList={{