Unify download progress presentation

This commit is contained in:
Dariusz L
2026-08-03 14:08:00 +02:00
parent c294d9d389
commit 8e7d14be6d
4 changed files with 86 additions and 21 deletions
@@ -3020,6 +3020,44 @@ test('native Xet progress bar uses live network bytes against the known final fi
}).percent, 20);
});
test('download progress presentation combines display and logical size labels', () => {
const getDownloadProgressPresentation = eval(
`(${extractMethod(renderFormatMethodsSource, 'getDownloadProgressPresentation')})`
);
const dialog = {
getDownloadDisplayProgress: () => ({
percent: 42.5,
downloaded: 100,
totalSize: 250,
isTransfer: true,
isFinalizing: false,
}),
formatBytes: value => `${value} B`,
formatDownloadProgressMeta: () => 'meta',
formatDownloadPercent: value => `${value}%`,
};
assert.deepEqual(
getDownloadProgressPresentation.call(dialog, {
downloaded: 80,
total_size: 200,
}, { unknownTotal: 'Unknown' }),
{
percent: 42.5,
downloaded: 100,
totalSize: 250,
isTransfer: true,
isFinalizing: false,
percentLabel: '42.5%',
downloadedText: '100 B',
totalText: '250 B',
progressMeta: 'meta',
logicalDownloadedText: '80 B',
logicalTotalText: '200 B',
}
);
});
test('base model alias resolves FLUX KREA as Flux.1 Krea', () => {
const {
normalizeBaseModelToken,
@@ -4025,6 +4063,9 @@ test('downloads tab shows active downloads from all workflow tabs', () => {
test('downloads tab renders workflow label for active downloads', () => {
const renderQueueDownloadsHtml = eval(`(${extractMethod(queueMethodsSource, 'renderQueueDownloadsHtml')})`);
const getDownloadProgressPresentation = eval(
`(${extractMethod(renderFormatMethodsSource, 'getDownloadProgressPresentation')})`
);
const dialog = {
escapeHtml(value) {
return String(value).replace(/[&<>\"]/g, char => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[char]));
@@ -4049,6 +4090,9 @@ test('downloads tab renders workflow label for active downloads', () => {
isFinalizing: false,
};
},
getDownloadProgressPresentation(progress, options) {
return getDownloadProgressPresentation.call(this, progress, options);
},
formatDownloadProgressMeta() {
return '';
},
+13 -11
View File
@@ -1144,8 +1144,16 @@ export const queueMethods = {
const progress = typeof this.applyPendingDownloadStatus === 'function'
? this.applyPendingDownloadStatus(info, info.lastProgress || {})
: (info.lastProgress || {});
const displayProgress = this.getDownloadDisplayProgress(progress);
const percent = displayProgress.percent;
const presentation = this.getDownloadProgressPresentation(progress);
const {
percent,
downloadedText: downloaded,
totalText: total,
progressMeta,
percentLabel,
logicalDownloadedText: logicalDownloaded,
logicalTotalText: logicalTotal,
} = presentation;
const filename = progress.filename
|| info.filename
|| info.missing?.download_source?.filename
@@ -1153,22 +1161,16 @@ export const queueMethods = {
|| 'model';
const category = this.getCategoryDisplayName?.(info.category || info.missing?.category || '') || info.category || '';
const nodeLabel = info.missing?.subgraph_name || info.missing?.node_type || (info.missing?.subgraph_id ? 'Subgraph' : 'Node');
const downloaded = this.formatBytes(displayProgress.downloaded);
const total = displayProgress.totalSize ? this.formatBytes(displayProgress.totalSize) : '';
const progressMeta = this.formatDownloadProgressMeta?.(progress) || '';
const status = progress.status || info.lastStatus || 'starting';
const backend = String(progress.download_backend || info.downloadBackend || '').toLowerCase();
const isAria2 = backend === 'aria2';
const isPaused = status === 'paused';
const percentLabel = this.formatDownloadPercent?.(percent) ?? String(Math.round(percent));
const statusLabel = status === 'downloading'
? (displayProgress.isFinalizing ? 'Finalizing' : `${percentLabel}%`)
? (presentation.isFinalizing ? 'Finalizing' : `${percentLabel}%`)
: (status === 'starting' ? 'Starting' : (isPaused ? 'Paused' : status.replace(/_/g, ' ')));
const logicalDownloaded = this.formatBytes(progress.downloaded || 0);
const logicalTotal = progress.total_size ? this.formatBytes(progress.total_size) : '';
const sizeText = displayProgress.isFinalizing && logicalTotal
const sizeText = presentation.isFinalizing && logicalTotal
? `Finalizing file: ${logicalDownloaded} / ${logicalTotal}`
: (total ? `${downloaded} / ${total}` : downloaded);
: (presentation.totalSize ? `${downloaded} / ${total}` : downloaded);
const targetPath = progress.directory || info.downloadDirectory || info.downloadPath || '';
const targetLabel = targetPath ? targetPath.split(/[/\\]/).filter(Boolean).pop() || targetPath : '';
const workflowLabel = this.getDownloadWorkflowLabel?.(info) || 'Unknown workflow';
@@ -1127,17 +1127,19 @@ export const resolveDownloadMethods = {
const backend = String(progress.download_backend || snapshot.downloadBackend || snapshot.download_backend || '').toLowerCase();
const isAria2 = backend === 'aria2';
const isPaused = status === 'paused';
const displayProgress = this.getDownloadDisplayProgress(progress);
const percent = displayProgress.percent;
const downloaded = this.formatBytes(displayProgress.downloaded);
const total = this.formatBytes(displayProgress.totalSize);
const progressMeta = this.formatDownloadProgressMeta(progress);
const percentLabel = this.formatDownloadPercent?.(percent) ?? String(Math.round(percent));
const logicalDownloaded = this.formatBytes(progress.downloaded || 0);
const logicalTotal = progress.total_size ? this.formatBytes(progress.total_size) : 'Unknown';
const leftText = displayProgress.isFinalizing
const presentation = this.getDownloadProgressPresentation(progress, { unknownTotal: 'Unknown' });
const {
percent,
downloadedText: downloaded,
totalText: total,
progressMeta,
percentLabel,
logicalDownloadedText: logicalDownloaded,
logicalTotalText: logicalTotal,
} = presentation;
const leftText = presentation.isFinalizing
? `Finalizing file: ${logicalDownloaded} / ${logicalTotal}`
: (displayProgress.totalSize
: (presentation.totalSize
? `${downloaded} / ${total} (${percentLabel}%)${isPaused ? ' - Paused' : ''}`
: '<span class="mr-info-accent-text">Connecting...</span>');
let actionClass = canCancel ? 'cancel-download-btn mr-btn mr-btn-danger mr-btn-sm' : '';
@@ -340,6 +340,23 @@ export const renderFormatMethods = {
};
},
getDownloadProgressPresentation(progress = {}, { unknownTotal = '' } = {}) {
const displayProgress = this.getDownloadDisplayProgress(progress);
const percent = displayProgress.percent;
return {
...displayProgress,
percentLabel: this.formatDownloadPercent?.(percent) ?? String(Math.round(percent)),
downloadedText: this.formatBytes(displayProgress.downloaded),
totalText: this.formatBytes(displayProgress.totalSize),
progressMeta: this.formatDownloadProgressMeta(progress),
logicalDownloadedText: this.formatBytes(progress.downloaded || 0),
logicalTotalText: progress.total_size
? this.formatBytes(progress.total_size)
: unknownTotal,
};
},
getDownloadEtaText(progress = {}) {
const backend = String(progress.download_backend || '').toLowerCase();
const totalSize = Number(progress.total_size) || 0;