diff --git a/web/src/lib/components/timeline/TimelineAssetViewer.svelte b/web/src/lib/components/timeline/TimelineAssetViewer.svelte index d718d2dd8..373ecef24 100644 --- a/web/src/lib/components/timeline/TimelineAssetViewer.svelte +++ b/web/src/lib/components/timeline/TimelineAssetViewer.svelte @@ -107,21 +107,12 @@ }; const onAlbumRemoveAssets = async ({ assetIds, albumIds }: { assetIds: string[]; albumIds: string[] }) => { - if (!album || !albumIds.includes(album.id)) { - return; + if (!!album && albumIds.includes(album.id) && assetIds.includes(assetCursor.current.id)) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + (await navigateToAsset(assetCursor?.nextAsset)) || + (await navigateToAsset(assetCursor?.previousAsset)) || + (await handleClose(assetCursor.current.id)); } - - timelineManager.removeAssets(assetIds); - - if (!assetIds.includes(assetCursor.current.id)) { - return; - } - - // keep the cleanup workflow in viewer by moving to adjacent asset first - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - (await navigateToAsset(assetCursor?.nextAsset)) || - (await navigateToAsset(assetCursor?.previousAsset)) || - (await handleClose(assetCursor.current.id)); }; const handlePreAction = async (action: Action) => { diff --git a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts index bc67e8365..187e04c63 100644 --- a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts +++ b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts @@ -123,6 +123,11 @@ export class TimelineManager extends VirtualScrollManager { } }, AssetsUnarchive: (assets) => this.upsertAssets(assets), + AlbumRemoveAssets: ({ assetIds, albumIds }) => { + if (this.#options.albumId && albumIds.includes(this.#options.albumId)) { + this.removeAssets(assetIds); + } + }, StackCreate: (stack) => { if (this.#options.withStacked) { updateStackedAssetInTimeline(this, stack); 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 5098c6ec2..e7dc3f96c 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 @@ -46,7 +46,7 @@ import { handlePromiseError } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; import { isAlbumsRoute, navigate, type AssetGridRouteSearchParams } from '$lib/utils/navigation'; - import { AlbumUserRole, AssetVisibility, getAlbumInfo, updateAlbumInfo, type AlbumResponseDto } from '@immich/sdk'; + import { AlbumUserRole, AssetVisibility, updateAlbumInfo, type AlbumResponseDto } from '@immich/sdk'; import { ActionButton, CommandPaletteDefaultProvider, Icon, IconButton, toastManager } from '@immich/ui'; import { mdiAccountEye, @@ -67,6 +67,7 @@ import AlbumDescription from './AlbumDescription.svelte'; import AlbumTitle from './AlbumTitle.svelte'; import ActionMenuItem from '$lib/components/ActionMenuItem.svelte'; + import { delay } from '$lib/utils/asset-utils'; interface Props { data: PageData; @@ -121,8 +122,17 @@ await goto(Route.albums()); }; - const refreshAlbum = async () => { - album = await getAlbumInfo({ id: album.id }); + const refreshAlbum = async (updated?: AlbumResponseDto) => { + if (updated) { + if (updated.id !== album.id) { + return; + } + album = updated; + } + + // invalidating during navigation causes an infinite page load + await navigating.complete; + await invalidate('album:data'); }; const setModeToView = async () => { @@ -145,9 +155,10 @@ assetMultiSelectManager.clear(); }; - const onAlbumRemoveAssets = async ({ assetIds, albumIds }: { assetIds: string[]; albumIds: string[] }) => { + const onAlbumRemoveAssets = async ({ albumIds }: { assetIds: string[]; albumIds: string[] }) => { if (albumIds.includes(album.id)) { - await handleRemoveAssets(assetIds); + await delay(1000); + await refreshAlbum(); } }; @@ -203,8 +214,8 @@ } }); - let album = $state(data.album); - let albumId = $derived(album.id); + let album = $derived(data.album); + const albumId = $derived(album.id); const albumHasViewers = $derived(album.albumUsers.some(({ role }) => role === AlbumUserRole.Viewer)); const containsEditors = $derived(album?.shared && album.albumUsers.some(({ role }) => role === AlbumUserRole.Editor)); @@ -300,15 +311,6 @@ album = { ...album, albumUsers }; }; - const onAlbumUpdate = async (newAlbum: AlbumResponseDto) => { - album = newAlbum; - - // invalidating during navigation causes an infinite page load - await navigating.complete; - - await invalidate('album:data'); - }; - const { Cast } = $derived(getGlobalActions($t)); const Actions = $derived(getAlbumActions($t, album)); const { AddAssets, Upload } = $derived(getAlbumAssetsActions($t, album, timelineMultiSelectManager.assets)); @@ -323,15 +325,16 @@ refreshAlbum(link.album)} + onSharedLinkDelete={() => refreshAlbum()} {onAlbumDelete} {onAlbumAddAssets} {onAlbumRemoveAssets} {onAlbumShare} {onAlbumUserUpdate} - onAlbumUserDelete={refreshAlbum} - {onAlbumUpdate} + onAlbumUserDelete={() => refreshAlbum()} + onAlbumUpdate={(album) => refreshAlbum(album)} + onAssetsDelete={() => refreshAlbum()} />