mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
feat(web): Implement keep this delete others for asset stacks (#14217)
This commit is contained in:
parent
bcd17c2ebe
commit
1737013e66
7 changed files with 65 additions and 0 deletions
|
|
@ -12,6 +12,7 @@ type ActionMap = {
|
|||
[AssetAction.ADD]: { asset: AssetResponseDto };
|
||||
[AssetAction.ADD_TO_ALBUM]: { asset: AssetResponseDto; album: AlbumResponseDto };
|
||||
[AssetAction.UNSTACK]: { assets: AssetResponseDto[] };
|
||||
[AssetAction.KEEP_THIS_DELETE_OTHERS]: { asset: AssetResponseDto };
|
||||
};
|
||||
|
||||
export type Action = {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<script lang="ts">
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { keepThisDeleteOthers } from '$lib/utils/asset-utils';
|
||||
import type { AssetResponseDto, StackResponseDto } from '@immich/sdk';
|
||||
import { mdiPinOutline } from '@mdi/js';
|
||||
import type { OnAction } from './action';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||
|
||||
export let stack: StackResponseDto;
|
||||
export let asset: AssetResponseDto;
|
||||
export let onAction: OnAction;
|
||||
|
||||
const handleKeepThisDeleteOthers = async () => {
|
||||
const isConfirmed = await dialogController.show({
|
||||
title: $t('keep_this_delete_others'),
|
||||
prompt: $t('confirm_keep_this_delete_others'),
|
||||
confirmText: $t('delete_others'),
|
||||
});
|
||||
|
||||
if (!isConfirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const keptAsset = await keepThisDeleteOthers(asset, stack);
|
||||
if (keptAsset) {
|
||||
onAction({ type: AssetAction.UNSTACK, assets: [keptAsset] });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<MenuOption icon={mdiPinOutline} onClick={handleKeepThisDeleteOthers} text={$t('keep_this_delete_others')} />
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
import ShareAction from '$lib/components/asset-viewer/actions/share-action.svelte';
|
||||
import ShowDetailAction from '$lib/components/asset-viewer/actions/show-detail-action.svelte';
|
||||
import UnstackAction from '$lib/components/asset-viewer/actions/unstack-action.svelte';
|
||||
import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte';
|
||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
|
|
@ -166,6 +167,7 @@
|
|||
{#if isOwner}
|
||||
{#if stack}
|
||||
<UnstackAction {stack} {onAction} />
|
||||
<KeepThisDeleteOthersAction {stack} {asset} {onAction} />
|
||||
{/if}
|
||||
{#if album}
|
||||
<SetAlbumCoverAction {asset} {album} />
|
||||
|
|
|
|||
|
|
@ -379,6 +379,7 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case AssetAction.KEEP_THIS_DELETE_OTHERS:
|
||||
case AssetAction.UNSTACK: {
|
||||
closeViewer();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export enum AssetAction {
|
|||
ADD = 'add',
|
||||
ADD_TO_ALBUM = 'add-to-album',
|
||||
UNSTACK = 'unstack',
|
||||
KEEP_THIS_DELETE_OTHERS = 'keep-this-delete-others',
|
||||
}
|
||||
|
||||
export enum AppRoute {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { getFormatter } from '$lib/utils/i18n';
|
|||
import {
|
||||
addAssetsToAlbum as addAssets,
|
||||
createStack,
|
||||
deleteAssets,
|
||||
deleteStacks,
|
||||
getAssetInfo,
|
||||
getBaseUrl,
|
||||
|
|
@ -27,6 +28,7 @@ import {
|
|||
type AssetResponseDto,
|
||||
type AssetTypeEnum,
|
||||
type DownloadInfoDto,
|
||||
type StackResponseDto,
|
||||
type UserPreferencesResponseDto,
|
||||
type UserResponseDto,
|
||||
} from '@immich/sdk';
|
||||
|
|
@ -438,6 +440,26 @@ export const deleteStack = async (stackIds: string[]) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const keepThisDeleteOthers = async (keepAsset: AssetResponseDto, stack: StackResponseDto) => {
|
||||
const $t = get(t);
|
||||
|
||||
try {
|
||||
const assetsToDeleteIds = stack.assets.filter((asset) => asset.id !== keepAsset.id).map((asset) => asset.id);
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: assetsToDeleteIds } });
|
||||
await deleteStacks({ bulkIdsDto: { ids: [stack.id] } });
|
||||
|
||||
notificationController.show({
|
||||
type: NotificationType.Info,
|
||||
message: $t('kept_this_deleted_others', { values: { count: assetsToDeleteIds.length } }),
|
||||
});
|
||||
|
||||
keepAsset.stack = null;
|
||||
return keepAsset;
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.failed_to_keep_this_delete_others'));
|
||||
}
|
||||
};
|
||||
|
||||
export const selectAllAssets = async (assetStore: AssetStore, assetInteractionStore: AssetInteractionStore) => {
|
||||
if (get(isSelectingAllAssets)) {
|
||||
// Selection is already ongoing
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue