({ folder, mode, job })
| 3097 | } |
| 3098 | |
| 3099 | function renderCryptoJobUi({ folder, mode, job }) { |
| 3100 | ensureCryptoJobUi(); |
| 3101 | |
| 3102 | const folderLabel = folder || (job && job.folder) || 'root'; |
| 3103 | const state = String(job?.state || 'running').toLowerCase(); |
| 3104 | const totalFiles = Number(job?.totalFiles || 0); |
| 3105 | const totalBytes = Number(job?.totalBytes || 0); |
| 3106 | const doneFiles = Number(job?.doneFiles || 0); |
| 3107 | const doneBytes = Number(job?.doneBytes || 0); |
| 3108 | |
| 3109 | let actualPct = null; |
| 3110 | if (totalFiles > 0) { |
| 3111 | actualPct = Math.min(100, Math.round((doneFiles / Math.max(1, totalFiles)) * 100)); |
| 3112 | } |
| 3113 | if (totalBytes > 0) { |
| 3114 | const bytesPct = Math.min(100, Math.round((doneBytes / Math.max(1, totalBytes)) * 100)); |
| 3115 | actualPct = Number.isFinite(actualPct) ? Math.max(actualPct, bytesPct) : bytesPct; |
| 3116 | } |
| 3117 | |
| 3118 | const createdAtRaw = Number(job?.createdAt || job?.startedAt || 0); |
| 3119 | const createdAtMs = createdAtRaw > 0 ? (createdAtRaw > 1e12 ? createdAtRaw : createdAtRaw * 1000) : Date.now(); |
| 3120 | const elapsedMs = Math.max(0, Date.now() - createdAtMs); |
| 3121 | |
| 3122 | const est = (state === 'running' && totalBytes > 0) |
| 3123 | ? estimateCryptoProgress(totalBytes, doneBytes, elapsedMs) |
| 3124 | : null; |
| 3125 | let pct = Number.isFinite(actualPct) ? actualPct : 0; |
| 3126 | let usingEstimate = false; |
| 3127 | if (est && (!Number.isFinite(actualPct) || est.pct > actualPct + 1)) { |
| 3128 | pct = est.pct; |
| 3129 | usingEstimate = true; |
| 3130 | } |
| 3131 | pct = clampNum(pct, 0, 100); |
| 3132 | |
| 3133 | let displayDoneBytes = doneBytes; |
| 3134 | if (usingEstimate && est) { |
| 3135 | displayDoneBytes = Math.max(doneBytes, est.estDone); |
| 3136 | } |
| 3137 | if (state === 'done') { |
| 3138 | pct = 100; |
| 3139 | if (totalBytes > 0) { |
| 3140 | displayDoneBytes = Math.max(displayDoneBytes, totalBytes); |
| 3141 | } |
| 3142 | } |
| 3143 | |
| 3144 | const progressJob = ensureCryptoTransferUiJob(folderLabel, mode, totalFiles, totalBytes); |
| 3145 | if (!progressJob) return; |
| 3146 | |
| 3147 | const currentParts = []; |
| 3148 | if (state === 'running') { |
| 3149 | if (job?._tickPending) { |
| 3150 | currentParts.push('Processing current file'); |
| 3151 | } else if (usingEstimate) { |
| 3152 | currentParts.push('Estimated progress'); |
| 3153 | } |
| 3154 | if (usingEstimate && est && Number.isFinite(est.etaMs)) { |
| 3155 | currentParts.push(`ETA ${formatDuration(est.etaMs)}`); |
| 3156 | } |
no test coverage detected