feat(ui:delta upload): warn user if refresh page during upload

This commit is contained in:
Edouard Vanbelle
2026-08-14 01:00:50 +02:00
parent e357caf43b
commit ef465b99de
3 changed files with 185 additions and 0 deletions
+28
View File
@@ -15,6 +15,8 @@
import { hashUrlToPath } from '$lib/utils/hashRedirect';
import { killLegacyServiceWorker } from '$lib/utils/killLegacyServiceWorker';
import { getOidcProviders, type OidcProviders } from '$lib/api/endpoints/auth';
import { readAndClearInterrupted } from '$lib/upload/interruption';
import { t } from '$lib/i18n/index.svelte';
let { children } = $props();
@@ -156,6 +158,32 @@
// loading state) is already in the DOM behind it.
document.getElementById('app-splash')?.remove();
// If a page reload interrupted one or more uploads mid-flight, the
// registry in sessionStorage carries breadcrumbs into the next mount.
// Toast a resume hint — already-uploaded chunks reuse via delta's
// negotiate stage, so re-dropping the same file is fast, not from
// scratch. Reading the register clears it so a subsequent reload
// doesn't re-notify.
const interrupted = readAndClearInterrupted();
if (interrupted.length > 0) {
const one = interrupted.length === 1;
const msg = one
? t(
'files.upload_interrupted_one',
{ description: interrupted[0].description },
`Upload interrupted: ${interrupted[0].description}. Re-drop to resume — already-uploaded chunks are reused.`
)
: t(
'files.upload_interrupted_many',
{ n: interrupted.length },
`${interrupted.length} uploads interrupted. Re-drop the files to resume — already-uploaded chunks are reused.`
);
// 10 s dwell — same pattern as the other long-copy toasts
// (see profile SSO error). Info kind because the situation is
// recoverable and the user only needs to know how to resume.
ui.notify(msg, 'info', 10000);
}
// Redirect old `#/...` bookmarks to the new path before anything else.
if (typeof location !== 'undefined' && location.hash.startsWith('#/')) {
// hashUrlToPath returns a dynamic in-app path string; resolve() is typed
@@ -30,6 +30,12 @@
resolveOwnedHashes,
tryDeltaUpload
} from '$lib/api/endpoints/deltaUpload';
import {
acquireUploadGuard,
markUploadFinished,
markUploadStarted,
releaseUploadGuard
} from '$lib/upload/interruption';
import { addFavorite, removeFavorite } from '$lib/api/endpoints/favorites';
import { canEditWithWopi, getEditorUrlWithFallback } from '$lib/api/endpoints/wopi';
import { addTracks, createPlaylist, listPlaylists } from '$lib/api/endpoints/music';
@@ -710,6 +716,17 @@
async function uploadBatch(files: File[]) {
if (files.length === 0) return;
uploading = true;
// Arm the reload-guard + persist a "batch in flight" marker so a
// page refresh mid-upload (a) prompts the browser's "Leave site?"
// dialog and (b) leaves a breadcrumb the layout picks up on the
// next mount → toasts a "uploads were interrupted, re-drop to
// resume (chunks reuse)" hint.
acquireUploadGuard();
const batchDescription =
files.length === 1
? files[0].name
: t('files.n_files_batch', { n: files.length }, `${files.length} files`);
const batchHandle = markUploadStarted(batchDescription, currentId);
const nid = ui.startProgress(
t('files.uploading_n', { done: 0, total: files.length }, `Uploading 0/${files.length} files…`)
);
@@ -760,6 +777,8 @@
ui.finishProgress(nid, errorMessage(err), 'error');
} finally {
uploading = false;
markUploadFinished(batchHandle);
releaseUploadGuard();
}
}
@@ -1539,6 +1558,14 @@
async function uploadTree(entries: { file: File; relativePath: string }[]) {
if (entries.length === 0) return;
uploading = true;
// Same reload-guard + interrupted-uploads breadcrumb as uploadBatch —
// the browser prompts on refresh, and if the user reloads anyway
// the layout picks up the marker on next mount and toasts.
acquireUploadGuard();
const treeHandle = markUploadStarted(
t('files.n_files_batch', { n: entries.length }, `${entries.length} files`),
currentId
);
// Same bell progress notification as uploadBatch, so folder uploads show
// live progress + a final result instead of staying silent until the end.
const nid = ui.startProgress(
@@ -1594,6 +1621,8 @@
ui.finishProgress(nid, errorMessage(err), 'error');
} finally {
uploading = false;
markUploadFinished(treeHandle);
releaseUploadGuard();
}
}