fix(web): refresh recent albums sidebar after album changes (#26757)

This commit is contained in:
Michel Heusschen
2026-03-09 17:11:32 +01:00
committed by GitHub
parent df0c86920d
commit a47b232235
10 changed files with 37 additions and 21 deletions

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { shortcut } from '$lib/actions/shortcut'; import { shortcut } from '$lib/actions/shortcut';
import { eventManager } from '$lib/managers/event-manager.svelte';
import { handleError } from '$lib/utils/handle-error'; import { handleError } from '$lib/utils/handle-error';
import { updateAlbumInfo } from '@immich/sdk'; import { updateAlbumInfo } from '@immich/sdk';
import { Textarea } from '@immich/ui'; import { Textarea } from '@immich/ui';
@@ -16,12 +17,13 @@
const handleFocusOut = async () => { const handleFocusOut = async () => {
try { try {
await updateAlbumInfo({ const response = await updateAlbumInfo({
id, id,
updateAlbumDto: { updateAlbumDto: {
description, description,
}, },
}); });
eventManager.emit('AlbumUpdate', response);
} catch (error) { } catch (error) {
handleError(error, $t('errors.unable_to_save_album')); handleError(error, $t('errors.unable_to_save_album'));
} }

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { shortcut } from '$lib/actions/shortcut'; import { shortcut } from '$lib/actions/shortcut';
import { eventManager } from '$lib/managers/event-manager.svelte';
import { handleError } from '$lib/utils/handle-error'; import { handleError } from '$lib/utils/handle-error';
import { updateAlbumInfo } from '@immich/sdk'; import { updateAlbumInfo } from '@immich/sdk';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
@@ -21,12 +22,14 @@
} }
try { try {
({ albumName } = await updateAlbumInfo({ const response = await updateAlbumInfo({
id, id,
updateAlbumDto: { updateAlbumDto: {
albumName: newAlbumName, albumName: newAlbumName,
}, },
})); });
({ albumName } = response);
eventManager.emit('AlbumUpdate', response);
onUpdate(albumName); onUpdate(albumName);
} catch (error) { } catch (error) {
handleError(error, $t('errors.unable_to_save_album')); handleError(error, $t('errors.unable_to_save_album'));

View File

@@ -17,7 +17,6 @@
type AlbumViewSettings, type AlbumViewSettings,
} from '$lib/stores/preferences.store'; } from '$lib/stores/preferences.store';
import { user } from '$lib/stores/user.store'; import { user } from '$lib/stores/user.store';
import { userInteraction } from '$lib/stores/user.svelte';
import { getSelectedAlbumGroupOption, sortAlbums, stringToSortOrder, type AlbumGroup } from '$lib/utils/album-utils'; import { getSelectedAlbumGroupOption, sortAlbums, stringToSortOrder, type AlbumGroup } from '$lib/utils/album-utils';
import type { ContextMenuPosition } from '$lib/utils/context-menu'; import type { ContextMenuPosition } from '$lib/utils/context-menu';
import { normalizeSearchString } from '$lib/utils/string-utils'; import { normalizeSearchString } from '$lib/utils/string-utils';
@@ -233,16 +232,11 @@
return albums; return albums;
}; };
const onUpdate = (album: AlbumResponseDto) => { const onAlbumUpdate = (album: AlbumResponseDto) => {
ownedAlbums = findAndUpdate(ownedAlbums, album); ownedAlbums = findAndUpdate(ownedAlbums, album);
sharedAlbums = findAndUpdate(sharedAlbums, album); sharedAlbums = findAndUpdate(sharedAlbums, album);
}; };
const onAlbumUpdate = (album: AlbumResponseDto) => {
onUpdate(album);
userInteraction.recentAlbums = findAndUpdate(userInteraction.recentAlbums || [], album);
};
const onAlbumDelete = (album: AlbumResponseDto) => { const onAlbumDelete = (album: AlbumResponseDto) => {
ownedAlbums = ownedAlbums.filter(({ id }) => id !== album.id); ownedAlbums = ownedAlbums.filter(({ id }) => id !== album.id);
sharedAlbums = sharedAlbums.filter(({ id }) => id !== album.id); sharedAlbums = sharedAlbums.filter(({ id }) => id !== album.id);
@@ -250,7 +244,7 @@
const onSharedLinkCreate = (sharedLink: SharedLinkResponseDto) => { const onSharedLinkCreate = (sharedLink: SharedLinkResponseDto) => {
if (sharedLink.album) { if (sharedLink.album) {
onUpdate(sharedLink.album); onAlbumUpdate(sharedLink.album);
} }
}; };
</script> </script>

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte'; import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { eventManager } from '$lib/managers/event-manager.svelte';
import { handleError } from '$lib/utils/handle-error'; import { handleError } from '$lib/utils/handle-error';
import { updateAlbumInfo, type AlbumResponseDto, type AssetResponseDto } from '@immich/sdk'; import { updateAlbumInfo, type AlbumResponseDto, type AssetResponseDto } from '@immich/sdk';
import { toastManager } from '@immich/ui'; import { toastManager } from '@immich/ui';
@@ -15,12 +16,13 @@
const handleUpdateThumbnail = async () => { const handleUpdateThumbnail = async () => {
try { try {
await updateAlbumInfo({ const response = await updateAlbumInfo({
id: album.id, id: album.id,
updateAlbumDto: { updateAlbumDto: {
albumThumbnailAssetId: asset.id, albumThumbnailAssetId: asset.id,
}, },
}); });
eventManager.emit('AlbumUpdate', response);
toastManager.success($t('album_cover_updated')); toastManager.success($t('album_cover_updated'));
} catch (error) { } catch (error) {
handleError(error, $t('errors.unable_to_update_album_cover')); handleError(error, $t('errors.unable_to_update_album_cover'));

View File

@@ -3,17 +3,12 @@
import { userInteraction } from '$lib/stores/user.svelte'; import { userInteraction } from '$lib/stores/user.svelte';
import { getAssetMediaUrl } from '$lib/utils'; import { getAssetMediaUrl } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error'; import { handleError } from '$lib/utils/handle-error';
import { getAllAlbums, type AlbumResponseDto } from '@immich/sdk'; import { getAllAlbums } from '@immich/sdk';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
let albums: AlbumResponseDto[] = $state([]); let albums = $state(userInteraction.recentAlbums);
onMount(async () => { const refreshAlbums = async () => {
if (userInteraction.recentAlbums) {
albums = userInteraction.recentAlbums;
return;
}
try { try {
const allAlbums = await getAllAlbums({}); const allAlbums = await getAllAlbums({});
albums = allAlbums.sort((a, b) => (a.updatedAt > b.updatedAt ? -1 : 1)).slice(0, 3); albums = allAlbums.sort((a, b) => (a.updatedAt > b.updatedAt ? -1 : 1)).slice(0, 3);
@@ -21,6 +16,12 @@
} catch (error) { } catch (error) {
handleError(error, $t('failed_to_load_assets')); handleError(error, $t('failed_to_load_assets'));
} }
};
$effect(() => {
if (!userInteraction.recentAlbums) {
void refreshAlbums();
}
}); });
</script> </script>

View File

@@ -39,6 +39,7 @@ export type Events = {
AssetsTag: [string[]]; AssetsTag: [string[]];
AlbumAddAssets: [{ assetIds: string[]; albumIds: string[] }]; AlbumAddAssets: [{ assetIds: string[]; albumIds: string[] }];
AlbumCreate: [AlbumResponseDto];
AlbumUpdate: [AlbumResponseDto]; AlbumUpdate: [AlbumResponseDto];
AlbumDelete: [AlbumResponseDto]; AlbumDelete: [AlbumResponseDto];
AlbumShare: []; AlbumShare: [];

View File

@@ -5,6 +5,7 @@
AlbumModalRowType, AlbumModalRowType,
isSelectableRowType, isSelectableRowType,
} from '$lib/components/shared-components/album-selection/album-selection-utils'; } from '$lib/components/shared-components/album-selection/album-selection-utils';
import { eventManager } from '$lib/managers/event-manager.svelte';
import { albumViewSettings } from '$lib/stores/preferences.store'; import { albumViewSettings } from '$lib/stores/preferences.store';
import { createAlbum, getAllAlbums, type AlbumResponseDto } from '@immich/sdk'; import { createAlbum, getAllAlbums, type AlbumResponseDto } from '@immich/sdk';
import { Button, Icon, Modal, ModalBody, ModalFooter, Text } from '@immich/ui'; import { Button, Icon, Modal, ModalBody, ModalFooter, Text } from '@immich/ui';
@@ -43,6 +44,7 @@
const onNewAlbum = async (name: string) => { const onNewAlbum = async (name: string) => {
const album = await createAlbum({ createAlbumDto: { albumName: name } }); const album = await createAlbum({ createAlbumDto: { albumName: name } });
eventManager.emit('AlbumCreate', album);
onClose([album]); onClose([album]);
}; };

View File

@@ -22,10 +22,17 @@ const defaultUserInteraction: UserInteractions = {
export const userInteraction = $state<UserInteractions>(defaultUserInteraction); export const userInteraction = $state<UserInteractions>(defaultUserInteraction);
const resetRecentAlbums = () => {
userInteraction.recentAlbums = undefined;
};
const reset = () => { const reset = () => {
Object.assign(userInteraction, defaultUserInteraction); Object.assign(userInteraction, defaultUserInteraction);
}; };
eventManager.on({ eventManager.on({
AlbumCreate: () => resetRecentAlbums(),
AlbumUpdate: () => resetRecentAlbums(),
AlbumDelete: () => resetRecentAlbums(),
AuthLogout: () => reset(), AuthLogout: () => reset(),
}); });

View File

@@ -1,4 +1,5 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { eventManager } from '$lib/managers/event-manager.svelte';
import { Route } from '$lib/route'; import { Route } from '$lib/route';
import { import {
AlbumFilter, AlbumFilter,
@@ -29,6 +30,7 @@ export const createAlbum = async (name?: string, assetIds?: string[]) => {
assetIds, assetIds,
}, },
}); });
eventManager.emit('AlbumCreate', newAlbum);
return newAlbum; return newAlbum;
} catch (error) { } catch (error) {
const $t = get(t); const $t = get(t);

View File

@@ -30,6 +30,7 @@
import { AlbumPageViewMode } from '$lib/constants'; import { AlbumPageViewMode } from '$lib/constants';
import { activityManager } from '$lib/managers/activity-manager.svelte'; import { activityManager } from '$lib/managers/activity-manager.svelte';
import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte';
import { eventManager } from '$lib/managers/event-manager.svelte';
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
@@ -192,12 +193,13 @@
const updateThumbnail = async (assetId: string) => { const updateThumbnail = async (assetId: string) => {
try { try {
await updateAlbumInfo({ const response = await updateAlbumInfo({
id: album.id, id: album.id,
updateAlbumDto: { updateAlbumDto: {
albumThumbnailAssetId: assetId, albumThumbnailAssetId: assetId,
}, },
}); });
eventManager.emit('AlbumUpdate', response);
toastManager.success($t('album_cover_updated')); toastManager.success($t('album_cover_updated'));
} catch (error) { } catch (error) {
handleError(error, $t('errors.unable_to_update_album_cover')); handleError(error, $t('errors.unable_to_update_album_cover'));