diff --git a/web/src/lib/managers/upload-manager.svelte.ts b/web/src/lib/managers/upload-manager.svelte.ts index 18fab1158b..efc933f016 100644 --- a/web/src/lib/managers/upload-manager.svelte.ts +++ b/web/src/lib/managers/upload-manager.svelte.ts @@ -1,5 +1,6 @@ import { eventManager } from '$lib/managers/event-manager.svelte'; import { uploadAssetsStore } from '$lib/stores/upload'; +import { cancelUploadRequests } from '$lib/utils'; import { getSupportedMediaTypes, type ServerMediaTypesResponseDto } from '@immich/sdk'; class UploadManager { @@ -13,6 +14,7 @@ class UploadManager { } reset() { + cancelUploadRequests(); uploadAssetsStore.reset(); } diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index 9d0c32ae94..f5d46576cb 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -78,17 +78,40 @@ export const sleep = (ms: number) => { return new Promise((resolve) => setTimeout(resolve, ms)); }; +let unsubscribeId = 0; +const uploads: Record void> = {}; + +const trackUpload = (unsubscribe: () => void) => { + const id = unsubscribeId++; + uploads[id] = unsubscribe; + return () => { + delete uploads[id]; + }; +}; + +export const cancelUploadRequests = () => { + for (const unsubscribe of Object.values(uploads)) { + unsubscribe(); + } +}; + export const uploadRequest = async (options: UploadRequestOptions): Promise<{ data: T; status: number }> => { const { onUploadProgress: onProgress, data, url } = options; - return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); + const unsubscribe = trackUpload(() => xhr.abort()); + + xhr.addEventListener('error', (error) => { + unsubscribe(); + reject(error); + }); - xhr.addEventListener('error', (error) => reject(error)); xhr.addEventListener('load', () => { if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status < 300) { + unsubscribe(); resolve({ data: xhr.response as T, status: xhr.status }); } else { + unsubscribe(); reject(new ApiError(xhr.statusText, xhr.status, xhr.response)); } });