From 17d49410890303386e92f0c2b0d2559aec195006 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Mon, 30 Mar 2026 10:45:57 -0400 Subject: [PATCH] refactor: asset select manager (#27330) --- .../components/memory-page/memory-viewer.svelte | 2 +- .../shared-components/map/MapTimelinePanel.svelte | 2 +- .../timeline/AssetSelectControlBar.svelte | 3 --- .../timeline/actions/ArchiveAction.svelte | 12 +++++------- .../timeline/actions/ChangeDateAction.svelte | 12 ++++++------ .../actions/ChangeDescriptionAction.svelte | 7 +++---- .../timeline/actions/ChangeLocationAction.svelte | 7 +++---- .../timeline/actions/CreateSharedLinkAction.svelte | 6 ++---- .../timeline/actions/DeleteAssetsAction.svelte | 8 +++----- .../timeline/actions/DownloadAction.svelte | 12 +++++------- .../timeline/actions/FavoriteAction.svelte | 8 +++----- .../timeline/actions/LinkLivePhotoAction.svelte | 14 ++++++-------- .../timeline/actions/RemoveFromAlbumAction.svelte | 10 ++++------ .../actions/RemoveFromSharedLinkAction.svelte | 8 +++----- .../timeline/actions/RestoreAction.svelte | 8 +++----- .../timeline/actions/SetVisibilityAction.svelte | 5 ++--- .../components/timeline/actions/StackAction.svelte | 13 +++++-------- .../components/timeline/actions/TagAction.svelte | 10 ++++------ .../managers/asset-multi-select-manager.svelte.ts | 13 +++++-------- web/src/lib/services/asset.service.ts | 8 ++++---- web/src/lib/utils/context.ts | 3 --- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 2 +- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 2 +- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 2 +- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 2 +- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 2 +- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 2 +- .../(user)/photos/[[assetId=id]]/+page.svelte | 2 +- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 2 +- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 2 +- 30 files changed, 77 insertions(+), 112 deletions(-) diff --git a/web/src/lib/components/memory-page/memory-viewer.svelte b/web/src/lib/components/memory-page/memory-viewer.svelte index f053164066..3aa68c5825 100644 --- a/web/src/lib/components/memory-page/memory-viewer.svelte +++ b/web/src/lib/components/memory-page/memory-viewer.svelte @@ -337,7 +337,7 @@ {#if assetMultiSelectManager.selectionActive}
- {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} {#if assetMultiSelectManager.selectionActive} - {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} diff --git a/web/src/lib/components/timeline/AssetSelectControlBar.svelte b/web/src/lib/components/timeline/AssetSelectControlBar.svelte index 8ebccd03b8..07fd1688a9 100644 --- a/web/src/lib/components/timeline/AssetSelectControlBar.svelte +++ b/web/src/lib/components/timeline/AssetSelectControlBar.svelte @@ -1,7 +1,6 @@ diff --git a/web/src/lib/components/timeline/actions/ChangeDescriptionAction.svelte b/web/src/lib/components/timeline/actions/ChangeDescriptionAction.svelte index 883e43aa50..2fb8dcc5a0 100644 --- a/web/src/lib/components/timeline/actions/ChangeDescriptionAction.svelte +++ b/web/src/lib/components/timeline/actions/ChangeDescriptionAction.svelte @@ -1,8 +1,8 @@ diff --git a/web/src/lib/components/timeline/actions/ChangeLocationAction.svelte b/web/src/lib/components/timeline/actions/ChangeLocationAction.svelte index 537d38586b..5d9fdc139d 100644 --- a/web/src/lib/components/timeline/actions/ChangeLocationAction.svelte +++ b/web/src/lib/components/timeline/actions/ChangeLocationAction.svelte @@ -1,9 +1,9 @@ diff --git a/web/src/lib/components/timeline/actions/DeleteAssetsAction.svelte b/web/src/lib/components/timeline/actions/DeleteAssetsAction.svelte index e643bae512..16fa72a75d 100644 --- a/web/src/lib/components/timeline/actions/DeleteAssetsAction.svelte +++ b/web/src/lib/components/timeline/actions/DeleteAssetsAction.svelte @@ -1,10 +1,10 @@ diff --git a/web/src/lib/components/timeline/actions/DownloadAction.svelte b/web/src/lib/components/timeline/actions/DownloadAction.svelte index 509aa3a0d7..0a9ab89df8 100644 --- a/web/src/lib/components/timeline/actions/DownloadAction.svelte +++ b/web/src/lib/components/timeline/actions/DownloadAction.svelte @@ -1,15 +1,15 @@ diff --git a/web/src/lib/components/timeline/actions/FavoriteAction.svelte b/web/src/lib/components/timeline/actions/FavoriteAction.svelte index d970a16b8d..b60740d471 100644 --- a/web/src/lib/components/timeline/actions/FavoriteAction.svelte +++ b/web/src/lib/components/timeline/actions/FavoriteAction.svelte @@ -1,7 +1,7 @@ diff --git a/web/src/lib/components/timeline/actions/RestoreAction.svelte b/web/src/lib/components/timeline/actions/RestoreAction.svelte index 48094825f6..946167fb61 100644 --- a/web/src/lib/components/timeline/actions/RestoreAction.svelte +++ b/web/src/lib/components/timeline/actions/RestoreAction.svelte @@ -1,6 +1,6 @@ diff --git a/web/src/lib/components/timeline/actions/TagAction.svelte b/web/src/lib/components/timeline/actions/TagAction.svelte index 63748cd214..e4887441e3 100644 --- a/web/src/lib/components/timeline/actions/TagAction.svelte +++ b/web/src/lib/components/timeline/actions/TagAction.svelte @@ -1,11 +1,11 @@ diff --git a/web/src/lib/managers/asset-multi-select-manager.svelte.ts b/web/src/lib/managers/asset-multi-select-manager.svelte.ts index eb75825102..6bdea33094 100644 --- a/web/src/lib/managers/asset-multi-select-manager.svelte.ts +++ b/web/src/lib/managers/asset-multi-select-manager.svelte.ts @@ -1,7 +1,6 @@ import { eventManager } from '$lib/managers/event-manager.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; import { user } from '$lib/stores/user.store'; -import type { AssetControlContext } from '$lib/types'; import { AssetVisibility, type UserAdminResponseDto } from '@immich/sdk'; import { SvelteMap, SvelteSet } from 'svelte/reactivity'; import { fromStore } from 'svelte/store'; @@ -22,7 +21,10 @@ export class AssetMultiSelectManager { candidates = $state([]); selectionActive = $derived(this.#selectedMap.size > 0); + assets = $derived(Array.from(this.#selectedMap.values())); + ownedAssets = $derived(this.#userId ? this.assets.filter((asset) => asset.ownerId === this.#userId) : this.assets); + isAllTrashed = $derived(this.assets.every((asset) => asset.isTrashed)); isAllArchived = $derived(this.assets.every((asset) => asset.visibility === AssetVisibility.Archive)); isAllFavorite = $derived(this.assets.every((asset) => asset.isFavorite)); @@ -41,13 +43,8 @@ export class AssetMultiSelectManager { this.#unsubscribe?.(); } - asControlContext(): AssetControlContext { - return { - getOwnedAssets: () => - this.#userId ? this.assets.filter((asset) => asset.ownerId === this.#userId) : this.assets, - getAssets: () => this.assets, - clearSelect: () => this.clear(), - }; + getOwnedAssets() { + return this.#userId ? this.assets.filter((asset) => asset.ownerId === this.#userId) : this.assets; } hasSelectedAsset(assetId: string) { diff --git a/web/src/lib/services/asset.service.ts b/web/src/lib/services/asset.service.ts index d2d847fc15..a5fd76983a 100644 --- a/web/src/lib/services/asset.service.ts +++ b/web/src/lib/services/asset.service.ts @@ -1,4 +1,5 @@ import { ProjectionType } from '$lib/constants'; +import { assetMultiSelectManager } from '$lib/managers/asset-multi-select-manager.svelte'; import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { eventManager } from '$lib/managers/event-manager.svelte'; @@ -6,7 +7,6 @@ import AssetAddToAlbumModal from '$lib/modals/AssetAddToAlbumModal.svelte'; import AssetTagModal from '$lib/modals/AssetTagModal.svelte'; import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte'; import { user as authUser, preferences } from '$lib/stores/user.store'; -import type { AssetControlContext } from '$lib/types'; import { getAssetMediaUrl, getSharedLink, sleep } from '$lib/utils'; import { downloadUrl } from '$lib/utils/asset-utils'; import { handleError } from '$lib/utils/handle-error'; @@ -48,14 +48,14 @@ import { import type { MessageFormatter } from 'svelte-i18n'; import { get } from 'svelte/store'; -export const getAssetBulkActions = ($t: MessageFormatter, ctx: AssetControlContext) => { - const ownedAssets = ctx.getOwnedAssets(); +export const getAssetBulkActions = ($t: MessageFormatter) => { + const ownedAssets = assetMultiSelectManager.ownedAssets; const assetIds = ownedAssets.map((asset) => asset.id); const isAllVideos = ownedAssets.every((asset) => asset.isVideo); const onAction = async (name: AssetJobName) => { await handleRunAssetJob({ name, assetIds }); - ctx.clearSelect(); + assetMultiSelectManager.clear(); }; const AddToAlbum: ActionItem = { diff --git a/web/src/lib/utils/context.ts b/web/src/lib/utils/context.ts index 080017a2d3..733b8e6eb9 100644 --- a/web/src/lib/utils/context.ts +++ b/web/src/lib/utils/context.ts @@ -1,4 +1,3 @@ -import type { AssetControlContext } from '$lib/types'; import { getContext, setContext } from 'svelte'; export function createContext(key: string | symbol = Symbol()) { @@ -7,5 +6,3 @@ export function createContext(key: string | symbol = Symbol()) { set: (context: T) => setContext(key, context), }; } - -export const { get: getAssetControlContext, set: setAssetControlContext } = createContext(); diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte index c4fb6e91f9..8e8eea13d8 100644 --- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -452,7 +452,7 @@ {#if assetMultiSelectManager.selectionActive} - {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} diff --git a/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte index c7d5d73f06..c89b4b7892 100644 --- a/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -60,7 +60,7 @@ {#if assetMultiSelectManager.selectionActive} - {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} {#if assetMultiSelectManager.selectionActive} - {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} timelineManager.removeAssets(assetIds)} /> diff --git a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte index 9299e9001b..59220b9113 100644 --- a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -111,7 +111,7 @@ {#if assetMultiSelectManager.selectionActive}
- {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} - {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} diff --git a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 9e5ddbb960..0ae1f8bb66 100644 --- a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -459,7 +459,7 @@
{#if assetMultiSelectManager.selectionActive} - {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} diff --git a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte index aa7ba28812..b1aaa69725 100644 --- a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte @@ -113,7 +113,7 @@ {#if assetMultiSelectManager.selectionActive} - {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} diff --git a/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte index 970d2f5886..cbdfa73b37 100644 --- a/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -319,7 +319,7 @@ {#if assetMultiSelectManager.selectionActive}
- {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)} diff --git a/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte index 56786821f6..90efd3bac8 100644 --- a/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -114,7 +114,7 @@ {#if assetMultiSelectManager.selectionActive}
- {@const Actions = getAssetBulkActions($t, assetMultiSelectManager.asControlContext())} + {@const Actions = getAssetBulkActions($t)}