refactor(web): a few more album actions (#31839)

This commit is contained in:
Mees Frensel
2026-09-28 13:56:15 -04:00
committed by GitHub
parent bf5b21b361
commit 93ad3645e8
2 changed files with 31 additions and 62 deletions
+18 -9
View File
@@ -27,6 +27,7 @@ import {
mdiTrashCanOutline,
mdiExitToApp,
mdiUpload,
mdiCogOutline,
} from '@mdi/js';
import { type MessageFormatter } from 'svelte-i18n';
import { goto } from '$app/navigation';
@@ -73,7 +74,7 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) =
};
const Delete: ActionItem = {
title: $t('delete'),
title: $t('delete_album'),
icon: mdiTrashCanOutline,
$if: () => isOwned,
onAction: () => handleDeleteAlbum(album),
@@ -82,16 +83,10 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) =
const Download: ActionItem = {
title: $t('download'),
icon: mdiDownload,
$if: () => album.assetCount > 0,
onAction: () => handleDownloadAlbum(album),
};
const Leave: ActionItem = {
title: $t('leave_album'),
icon: mdiExitToApp,
$if: () => !isOwned,
onAction: () => handleLeaveAlbum(album),
};
const Edit: ActionItem = {
title: $t('edit_album'),
icon: mdiRenameOutline,
@@ -99,6 +94,20 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) =
onAction: () => modalManager.show(AlbumEditModal, { album }),
};
const Leave: ActionItem = {
title: $t('leave_album'),
icon: mdiExitToApp,
$if: () => !isOwned,
onAction: () => handleLeaveAlbum(album),
};
const Options: ActionItem = {
title: $t('options'),
icon: mdiCogOutline,
$if: () => album.assetCount > 0,
onAction: () => modalManager.show(AlbumOptionsModal, { album, readOnly: !isOwned }),
};
const Share: ActionItem = {
title: $t('share'),
icon: mdiShareVariantOutline,
@@ -106,7 +115,7 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) =
onAction: () => modalManager.show(AlbumOptionsModal, { album }),
};
return { AddUsers, CreateSharedLink, Delete, Download, Edit, Leave, Share };
return { AddUsers, CreateSharedLink, Delete, Download, Edit, Leave, Options, Share };
};
export const getAlbumAssetActions = ($t: MessageFormatter, album: AlbumResponseDto, asset: AssetResponseDto) => {
@@ -34,14 +34,8 @@
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import AlbumOptionsModal from '$lib/modals/AlbumOptionsModal.svelte';
import { Route } from '$lib/route';
import {
getAlbumActions,
getAlbumAssetsActions,
handleDeleteAlbum,
handleDownloadAlbum,
} from '$lib/services/album.service';
import { getAlbumActions, getAlbumAssetsActions, handleDeleteAlbum } from '$lib/services/album.service';
import { getGlobalActions } from '$lib/services/app.service';
import { getAssetBulkActions } from '$lib/services/asset.service';
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
@@ -49,23 +43,13 @@
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 {
ActionButton,
CommandPaletteDefaultProvider,
Icon,
IconButton,
modalManager,
toastManager,
} from '@immich/ui';
import { ActionButton, CommandPaletteDefaultProvider, Icon, IconButton, toastManager } from '@immich/ui';
import {
mdiAccountEye,
mdiAccountEyeOutline,
mdiArrowLeft,
mdiCogOutline,
mdiDeleteOutline,
mdiDotsHorizontal,
mdiDotsVertical,
mdiDownload,
mdiImageOutline,
mdiImagePlusOutline,
mdiLink,
@@ -218,6 +202,7 @@
let album = $state(data.album);
let 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));
const albumUsers = $derived(showAlbumUsers && containsEditors ? album.albumUsers.map(({ user }) => user) : []);
@@ -261,7 +246,6 @@
album.albumUsers.find(({ user: { id } }) => id === authManager.user.id)?.role === AlbumUserRole.Editor || isOwned,
);
let albumHasViewers = $derived(album.albumUsers.some(({ role }) => role === AlbumUserRole.Viewer));
const isSelectionMode = $derived(
viewMode === AlbumPageViewMode.SELECT_ASSETS ? true : viewMode === AlbumPageViewMode.SELECT_THUMBNAIL,
);
@@ -278,10 +262,6 @@
viewMode === AlbumPageViewMode.SELECT_ASSETS ? timelineMultiSelectManager : assetMultiSelectManager,
);
const onSharedLinkCreate = async () => {
await refreshAlbum();
};
const onAlbumDelete = async ({ id }: AlbumResponseDto) => {
if (id !== album.id) {
return;
@@ -328,7 +308,7 @@
};
const { Cast } = $derived(getGlobalActions($t));
const { Share, Leave } = $derived(getAlbumActions($t, album));
const Actions = $derived(getAlbumActions($t, album));
const { AddAssets, Upload } = $derived(getAlbumAssetsActions($t, album, timelineMultiSelectManager.assets));
const Close = $derived({
@@ -341,7 +321,7 @@
</script>
<OnEvents
{onSharedLinkCreate}
onSharedLinkCreate={refreshAlbum}
onSharedLinkDelete={refreshAlbum}
{onAlbumDelete}
{onAlbumAddAssets}
@@ -351,7 +331,7 @@
onAlbumUserDelete={refreshAlbum}
{onAlbumUpdate}
/>
<CommandPaletteDefaultProvider name={$t('album')} actions={[AddAssets, Upload, Close]} />
<CommandPaletteDefaultProvider name={$t('album')} actions={[AddAssets, Upload, Close, ...Object.values(Actions)]} />
<div class="flex overflow-hidden" use:scrollMemoryClearer={{ routeStartsWith: Route.albums() }}>
<div class="relative w-full shrink">
@@ -392,7 +372,7 @@
<button
class="flex gap-x-1"
type="button"
onclick={() => modalManager.show(AlbumOptionsModal, { album, readOnly: !isOwned })}
onclick={(event) => Actions.Options.onAction({ event, action: Actions.Options })}
>
<!-- owner & users with write access (collaborators) -->
{#each album.albumUsers.filter(({ role }) => role === AlbumUserRole.Editor || role === AlbumUserRole.Owner) as { user } (user.id)}
@@ -421,9 +401,7 @@
{/if}
</button>
{#if isOwned}
<ActionButton action={Share} />
{/if}
<ActionButton action={Actions.Share} />
</div>
{/if}
<AlbumDescription
@@ -536,7 +514,7 @@
/>
{/if}
<ActionButton action={Share} />
<ActionButton action={Actions.Share} />
{#if featureFlagsManager.value.map}
<AlbumMap {album} />
@@ -551,15 +529,8 @@
onclick={handleStartSlideshow}
icon={mdiPresentationPlay}
/>
<IconButton
shape="round"
variant="ghost"
color="secondary"
aria-label={$t('download')}
onclick={() => handleDownloadAlbum(album)}
icon={mdiDownload}
/>
{/if}
<ActionButton action={Actions.Download} />
{#if isOwned || album.albumUsers.length > 1}
<ButtonContextMenu
@@ -575,28 +546,17 @@
onClick={() => timelineManager.toggleShowAssetOwners()}
/>
{/if}
<ActionMenuItem action={Actions.Options} />
{#if isOwned && album.assetCount > 0}
<MenuOption
icon={mdiImageOutline}
text={$t('select_album_cover')}
onClick={() => (viewMode = AlbumPageViewMode.SELECT_THUMBNAIL)}
/>
<MenuOption
icon={mdiCogOutline}
text={$t('options')}
onClick={() => modalManager.show(AlbumOptionsModal, { album })}
/>
{/if}
{#if isOwned}
<MenuOption
icon={mdiDeleteOutline}
text={$t('delete_album')}
onClick={() => handleDeleteAlbum(album)}
/>
{:else}
<ActionMenuItem action={Leave} />
{/if}
<ActionMenuItem action={Actions.Delete} />
<ActionMenuItem action={Actions.Leave} />
</ButtonContextMenu>
{/if}
{/snippet}