From ff7dca35f5c6af2a514b041a33fa4f2247aecfa0 Mon Sep 17 00:00:00 2001 From: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> Date: Sat, 14 Feb 2026 21:31:04 +0100 Subject: [PATCH] perf(web): speed up asset selection (#26216) --- .../lib/stores/asset-interaction.svelte.ts | 20 ++++++++----------- web/src/lib/utils/asset-utils.ts | 7 ++++--- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/web/src/lib/stores/asset-interaction.svelte.ts b/web/src/lib/stores/asset-interaction.svelte.ts index 9cfc1b2c8e..817354e619 100644 --- a/web/src/lib/stores/asset-interaction.svelte.ts +++ b/web/src/lib/stores/asset-interaction.svelte.ts @@ -1,14 +1,15 @@ import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; import { user } from '$lib/stores/user.store'; import { AssetVisibility, type UserAdminResponseDto } from '@immich/sdk'; -import { SvelteSet } from 'svelte/reactivity'; +import { SvelteMap, SvelteSet } from 'svelte/reactivity'; import { fromStore } from 'svelte/store'; export class AssetInteraction { - selectedAssets = $state([]); + private selectedAssetsMap = new SvelteMap(); + selectedAssets = $derived(Array.from(this.selectedAssetsMap.values())); selectAll = $state(false); hasSelectedAsset(assetId: string) { - return this.selectedAssets.some((asset) => asset.id === assetId); + return this.selectedAssetsMap.has(assetId); } selectedGroup = new SvelteSet(); assetSelectionCandidates = $state([]); @@ -16,7 +17,7 @@ export class AssetInteraction { return this.assetSelectionCandidates.some((asset) => asset.id === assetId); } assetSelectionStart = $state(null); - selectionActive = $derived(this.selectedAssets.length > 0); + selectionActive = $derived(this.selectedAssetsMap.size > 0); private user = fromStore(user); private userId = $derived(this.user.current?.id); @@ -27,9 +28,7 @@ export class AssetInteraction { isAllUserOwned = $derived(this.selectedAssets.every((asset) => asset.ownerId === this.userId)); selectAsset(asset: TimelineAsset) { - if (!this.hasSelectedAsset(asset.id)) { - this.selectedAssets.push(asset); - } + this.selectedAssetsMap.set(asset.id, asset); } selectAssets(assets: TimelineAsset[]) { @@ -39,10 +38,7 @@ export class AssetInteraction { } removeAssetFromMultiselectGroup(assetId: string) { - const index = this.selectedAssets.findIndex((a) => a.id == assetId); - if (index !== -1) { - this.selectedAssets.splice(index, 1); - } + this.selectedAssetsMap.delete(assetId); } addGroupToMultiselectGroup(group: string) { @@ -69,7 +65,7 @@ export class AssetInteraction { this.selectAll = false; // Multi-selection - this.selectedAssets = []; + this.selectedAssetsMap.clear(); this.selectedGroup.clear(); // Range selection diff --git a/web/src/lib/utils/asset-utils.ts b/web/src/lib/utils/asset-utils.ts index 84e386d620..47df967844 100644 --- a/web/src/lib/utils/asset-utils.ts +++ b/web/src/lib/utils/asset-utils.ts @@ -4,7 +4,6 @@ import { authManager } from '$lib/managers/auth-manager.svelte'; import { downloadManager } from '$lib/managers/download-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; -import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte'; import { Route } from '$lib/route'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; import { preferences } from '$lib/stores/user.store'; @@ -443,13 +442,15 @@ export const selectAllAssets = async (timelineManager: TimelineManager, assetInt try { for (const monthGroup of timelineManager.months) { - await timelineManager.loadMonthGroup(monthGroup.yearMonth); + if (!monthGroup.isLoaded) { + await timelineManager.loadMonthGroup(monthGroup.yearMonth); + } if (!assetInteraction.selectAll) { assetInteraction.clearMultiselect(); break; // Cancelled } - assetInteraction.selectAssets(assetsSnapshot([...monthGroup.assetsIterator()])); + assetInteraction.selectAssets([...monthGroup.assetsIterator()]); for (const dateGroup of monthGroup.dayGroups) { assetInteraction.addGroupToMultiselectGroup(dateGroup.groupTitle);