(folder, mode)
| 3311 | } |
| 3312 | |
| 3313 | export async function startFolderCryptoJobFlow(folder, mode) { |
| 3314 | try { |
| 3315 | const planUrl = withBase(`/api/folder/encryptionPlan.php?folder=${encodeURIComponent(folder)}&mode=${encodeURIComponent(mode)}`); |
| 3316 | const planRes = await fetch(planUrl, { credentials: 'include' }); |
| 3317 | const plan = await safeJson(planRes); |
| 3318 | if (!plan || plan.ok !== true) { |
| 3319 | showToast((plan && (plan.error || plan.message)) || t('folder_encryption_estimate_failed'), 'error'); |
| 3320 | return; |
| 3321 | } |
| 3322 | |
| 3323 | const totalFiles = Number(plan.totalFiles || 0); |
| 3324 | const totalBytes = Number(plan.totalBytes || 0); |
| 3325 | const truncated = !!plan.truncated; |
| 3326 | |
| 3327 | const label = mode === 'decrypt' ? 'decrypt' : 'encrypt'; |
| 3328 | const msg = |
| 3329 | `Are you sure you want to ${label} "${folder}"?\n\n` + |
| 3330 | `This will process ${totalFiles} file(s) (~${formatBytes(totalBytes)}).` + |
| 3331 | (truncated ? `\n\nNote: estimate was truncated for very large trees.` : '') + |
| 3332 | `\n\nThis may take a while. Progress will appear in the Transfer Center while you continue using FileRise.`; |
| 3333 | |
| 3334 | const ok = await showCustomConfirmModal(msg); |
| 3335 | if (!ok) return; |
| 3336 | |
| 3337 | const startRes = await fetchWithCsrf(withBase('/api/folder/encryptionJobStart.php'), { |
| 3338 | method: 'POST', |
| 3339 | headers: { 'Content-Type': 'application/json' }, |
| 3340 | body: JSON.stringify({ folder, mode, totalFiles, totalBytes }) |
| 3341 | }); |
| 3342 | let start = null; |
| 3343 | if (startRes.ok) { |
| 3344 | start = await safeJson(startRes); |
| 3345 | } else { |
| 3346 | // If a job is already running, reconnect to it. |
| 3347 | const body = await startRes.json().catch(() => ({})); |
| 3348 | if (startRes.status === 409 && body && body.job && body.job.id) { |
| 3349 | start = { ok: true, jobId: body.job.id, folder, mode }; |
| 3350 | } else { |
| 3351 | const msg = (body && (body.error || body.message)) || `HTTP ${startRes.status}`; |
| 3352 | showToast(msg, 'error'); |
| 3353 | return; |
| 3354 | } |
| 3355 | } |
| 3356 | |
| 3357 | // Update local UI immediately |
| 3358 | if (mode === 'encrypt') setEncryptedClassForRenderedSubtree(folder, true); |
| 3359 | try { await applyFolderCapabilities(folder); } catch (e) { } |
| 3360 | |
| 3361 | const st = { jobId: start.jobId, folder, mode, minimized: false }; |
| 3362 | try { localStorage.setItem(CRYPTO_JOB_STORAGE_KEY, JSON.stringify(st)); } catch (e) { } |
| 3363 | |
| 3364 | renderCryptoJobUi({ |
| 3365 | folder, |
| 3366 | mode, |
| 3367 | job: { state: 'running', totalFiles, totalBytes, doneFiles: 0, doneBytes: 0, createdAt: Math.floor(Date.now() / 1000) } |
| 3368 | }); |
| 3369 | |
| 3370 | await startCryptoRunner(st); |
no test coverage detected