mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
Merge c0ac7af1c4 into af33a78d18
This commit is contained in:
commit
b8e32e4568
15 changed files with 78 additions and 43 deletions
|
|
@ -41,10 +41,13 @@ export class AlbumModalRowConverter {
|
|||
albums: AlbumResponseDto[],
|
||||
selectedRowIndex: number,
|
||||
multiSelectedAlbumIds: string[],
|
||||
allowNew = true
|
||||
): AlbumModalRow[] {
|
||||
// only show recent albums if no search was entered
|
||||
const recentAlbumsToShow = search.length === 0 ? recentAlbums : [];
|
||||
const rows: AlbumModalRow[] = [{ type: AlbumModalRowType.NEW_ALBUM, selected: selectedRowIndex === 0 }];
|
||||
const rows: AlbumModalRow[] = allowNew
|
||||
? [{ type: AlbumModalRowType.NEW_ALBUM, selected: selectedRowIndex === 0 }]
|
||||
: [];
|
||||
|
||||
const normalizedSearch = normalizeSearchString(search);
|
||||
const filteredAlbums = sortAlbums(
|
||||
|
|
|
|||
|
|
@ -1,54 +1,29 @@
|
|||
<script lang="ts">
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/MenuOption.svelte';
|
||||
import { assetMultiSelectManager } from '$lib/managers/asset-multi-select-manager.svelte';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { getAlbumInfo, removeAssetFromAlbum, type AlbumResponseDto } from '@immich/sdk';
|
||||
import { IconButton, modalManager, toastManager } from '@immich/ui';
|
||||
import { type AlbumResponseDto } from '@immich/sdk';
|
||||
import AssetRemoveFromAlbumModal from '$lib/modals/AssetRemoveFromAlbumModal.svelte';
|
||||
import { IconButton, modalManager } from '@immich/ui';
|
||||
import { mdiDeleteOutline, mdiImageRemoveOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
interface Props {
|
||||
album: AlbumResponseDto;
|
||||
onRemove: ((assetIds: string[]) => void) | undefined;
|
||||
assetIds?: string[];
|
||||
album?: AlbumResponseDto;
|
||||
onRemove?: (assetIds: string[]) => void;
|
||||
menuItem?: boolean;
|
||||
}
|
||||
|
||||
let { album = $bindable(), onRemove, assetIds, menuItem = false }: Props = $props();
|
||||
let { album, onRemove, menuItem = false }: Props = $props();
|
||||
|
||||
const removeFromAlbum = async () => {
|
||||
const ids = assetIds ?? assetMultiSelectManager.assets.map(({ id }) => id) ?? [];
|
||||
|
||||
const isConfirmed = await modalManager.showDialog({
|
||||
prompt: $t('remove_assets_album_confirmation', { values: { count: ids.length } }),
|
||||
});
|
||||
|
||||
if (!isConfirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const results = await removeAssetFromAlbum({
|
||||
id: album.id,
|
||||
bulkIdsDto: { ids },
|
||||
});
|
||||
|
||||
album = await getAlbumInfo({ id: album.id });
|
||||
|
||||
onRemove?.(ids);
|
||||
|
||||
const count = results.filter(({ success }) => success).length;
|
||||
toastManager.primary($t('assets_removed_count', { values: { count } }));
|
||||
|
||||
assetMultiSelectManager.clear();
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.error_removing_assets_from_album'));
|
||||
}
|
||||
const onAction = async () => {
|
||||
const assetIds = assetMultiSelectManager.assets.map(({ id }) => id) ?? [];
|
||||
const albumIds = await modalManager.show(AssetRemoveFromAlbumModal, { assetIds });
|
||||
if (!album || albumIds.includes(album.id)) onRemove?.(assetIds);
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if menuItem}
|
||||
<MenuOption text={$t('remove_from_album')} icon={mdiImageRemoveOutline} onClick={removeFromAlbum} />
|
||||
<MenuOption text={$t('remove_from_album')} icon={mdiImageRemoveOutline} onClick={onAction} />
|
||||
{:else}
|
||||
<IconButton
|
||||
shape="round"
|
||||
|
|
@ -56,6 +31,6 @@
|
|||
variant="ghost"
|
||||
aria-label={$t('remove_from_album')}
|
||||
icon={mdiDeleteOutline}
|
||||
onclick={removeFromAlbum}
|
||||
onclick={onAction}
|
||||
/>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -22,11 +22,12 @@
|
|||
let selectedRowIndex: number = $state(-1);
|
||||
|
||||
type Props = {
|
||||
remove?: boolean;
|
||||
onClose: (albums?: AlbumResponseDto[]) => void;
|
||||
selectedItemsCount?: number;
|
||||
};
|
||||
|
||||
let { onClose, selectedItemsCount }: Props = $props();
|
||||
let { remove, onClose, selectedItemsCount }: Props = $props();
|
||||
|
||||
onMount(async () => {
|
||||
albums = await getAllAlbums({});
|
||||
|
|
@ -39,7 +40,7 @@
|
|||
|
||||
const rowConverter = new AlbumModalRowConverter($albumViewSettings.sortBy, $albumViewSettings.sortOrder);
|
||||
const albumModalRows = $derived(
|
||||
rowConverter.toModalRows(search, recentAlbums, albums, selectedRowIndex, multiSelectedAlbumIds),
|
||||
rowConverter.toModalRows(search, recentAlbums, albums, selectedRowIndex, multiSelectedAlbumIds, !remove),
|
||||
);
|
||||
const selectableRowCount = $derived(albumModalRows.filter((row) => isSelectableRowType(row.type)).length);
|
||||
|
||||
|
|
@ -150,9 +151,11 @@
|
|||
};
|
||||
|
||||
const title = $derived(
|
||||
selectedItemsCount === undefined
|
||||
? $t('select_albums')
|
||||
: $t('add_to_album_item_count', { values: { count: selectedItemsCount } }),
|
||||
remove
|
||||
? 'remove_from_album'
|
||||
: selectedItemsCount === undefined
|
||||
? $t('select_albums')
|
||||
: $t('add_to_album_item_count', { values: { count: selectedItemsCount } }),
|
||||
);
|
||||
</script>
|
||||
|
||||
|
|
|
|||
33
web/src/lib/modals/AssetRemoveFromAlbumModal.svelte
Normal file
33
web/src/lib/modals/AssetRemoveFromAlbumModal.svelte
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<script lang="ts">
|
||||
import AlbumPickerModal from '$lib/modals/AlbumPickerModal.svelte';
|
||||
import { removeAssetFromAlbum, type AlbumResponseDto } from '@immich/sdk';
|
||||
import { toastManager } from '@immich/ui';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
type Props = {
|
||||
assetIds: string[];
|
||||
onClose: (albumIds: string[]) => void;
|
||||
};
|
||||
|
||||
const { assetIds, onClose }: Props = $props();
|
||||
|
||||
const handleClose = async (albums?: AlbumResponseDto[]) => {
|
||||
if (!albums?.length) return onClose([]);
|
||||
try {
|
||||
const albumIds = albums.map(({ id }) => id);
|
||||
let res;
|
||||
for (const id of albumIds) {
|
||||
res = await removeAssetFromAlbum({ id, bulkIdsDto: { ids: assetIds } });
|
||||
}
|
||||
const count = res.filter(({ success }) => success).length;
|
||||
toastManager.primary($t('assets_removed_count', { values: { count } }));
|
||||
onClose(albumIds);
|
||||
} catch (e) {
|
||||
handleError(e, $t('errors.error_removing_assets_from_album'));
|
||||
}
|
||||
};
|
||||
//TODO Only show albums that any selected item is in as option in AlbumPickerModal
|
||||
</script>
|
||||
|
||||
<AlbumPickerModal remove onClose={handleClose} />
|
||||
|
|
@ -158,6 +158,7 @@
|
|||
|
||||
const handleRemoveAssets = async (assetIds: string[]) => {
|
||||
timelineManager.removeAssets(assetIds);
|
||||
timelineMultiSelectManager.clear();
|
||||
await refreshAlbum();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
|
||||
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
|
||||
|
|
@ -86,6 +87,7 @@
|
|||
<TagAction menuItem />
|
||||
{/if}
|
||||
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
||||
<RemoveFromAlbum menuItem />
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
|
||||
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
|
||||
|
|
@ -155,6 +156,7 @@
|
|||
{#if authManager.preferences.tags.enabled && assetMultiSelectManager.isAllUserOwned}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<RemoveFromAlbum menuItem />
|
||||
<DeleteAssets menuItem onAssetDelete={triggerAssetUpdate} onUndoDelete={triggerAssetUpdate} />
|
||||
<hr />
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
||||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
|
||||
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
|
||||
|
|
@ -83,6 +84,7 @@
|
|||
<DownloadAction menuItem />
|
||||
<ChangeDate menuItem />
|
||||
<ChangeLocation menuItem />
|
||||
<RemoveFromAlbum menuItem />
|
||||
<DeleteAssets menuItem force onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
||||
</ButtonContextMenu>
|
||||
</AssetSelectControlBar>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
|
||||
import LinkLivePhotoAction from '$lib/components/timeline/actions/LinkLivePhotoAction.svelte';
|
||||
|
|
@ -161,6 +162,7 @@
|
|||
{#if authManager.preferences.tags.enabled}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<RemoveFromAlbum menuItem />
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
|
||||
import TagAction from '$lib/components/timeline/actions/TagAction.svelte';
|
||||
|
|
@ -357,6 +358,7 @@
|
|||
{#if authManager.preferences.tags.enabled && assetMultiSelectManager.isAllUserOwned}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<RemoveFromAlbum menuItem />
|
||||
<DeleteAssets menuItem onAssetDelete={handleDeleteOrArchiveAssets} />
|
||||
</ButtonContextMenu>
|
||||
</AssetSelectControlBar>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
|
||||
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
|
||||
|
|
@ -490,6 +491,7 @@
|
|||
<TagAction menuItem />
|
||||
{/if}
|
||||
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
||||
<RemoveFromAlbum menuItem />
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={(assetIds) => handleDeleteAssets(assetIds)}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
|
||||
import LinkLivePhotoAction from '$lib/components/timeline/actions/LinkLivePhotoAction.svelte';
|
||||
|
|
@ -153,6 +154,7 @@
|
|||
{#if authManager.preferences.tags.enabled}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<RemoveFromAlbum menuItem />
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
|
||||
import LinkLivePhotoAction from '$lib/components/timeline/actions/LinkLivePhotoAction.svelte';
|
||||
|
|
@ -147,6 +148,7 @@
|
|||
{#if authManager.preferences.tags.enabled}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<RemoveFromAlbum menuItem />
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
|
||||
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
|
||||
|
|
@ -377,6 +378,7 @@
|
|||
{#if authManager.preferences.tags.enabled}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<RemoveFromAlbum menuItem onRemove={onSearchQueryUpdate} />
|
||||
<DeleteAssets menuItem {onAssetDelete} onUndoDelete={onSearchQueryUpdate} />
|
||||
<hr />
|
||||
<ActionMenuItem action={Actions.RegenerateThumbnailJob} />
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
|
||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
|
||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
|
||||
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
|
||||
|
|
@ -135,6 +136,7 @@
|
|||
{#if authManager.preferences.tags.enabled}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<RemoveFromAlbum menuItem />
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue