mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
refactor: delete confirm modal (#25135)
This commit is contained in:
@@ -7,6 +7,13 @@ import DeleteAction from './delete-action.svelte';
|
||||
let asset: AssetResponseDto;
|
||||
|
||||
describe('DeleteAction component', () => {
|
||||
beforeEach(() => {
|
||||
vi.mock(import('$lib/managers/feature-flags-manager.svelte'), () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return { featureFlagsManager: { init: vi.fn(), loadFeatureFlags: vi.fn(), value: { trash: true } } as any };
|
||||
});
|
||||
});
|
||||
|
||||
describe('given an asset which is not trashed yet', () => {
|
||||
beforeEach(() => {
|
||||
asset = assetFactory.build({ isTrashed: false });
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { shortcuts } from '$lib/actions/shortcut';
|
||||
import DeleteAssetDialog from '$lib/components/photos-page/delete-asset-dialog.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import Portal from '$lib/elements/Portal.svelte';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import AssetDeleteConfirmModal from '$lib/modals/AssetDeleteConfirmModal.svelte';
|
||||
import { showDeleteModal } from '$lib/stores/preferences.store';
|
||||
import { deleteAssets as deleteAssetsUtil, type OnUndoDelete } from '$lib/utils/actions';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { deleteAssets, type AssetResponseDto } from '@immich/sdk';
|
||||
import { IconButton, toastManager } from '@immich/ui';
|
||||
import { IconButton, modalManager, toastManager } from '@immich/ui';
|
||||
import { mdiDeleteForeverOutline, mdiDeleteOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
import type { OnAction, PreAction } from './action';
|
||||
@@ -23,24 +22,32 @@
|
||||
|
||||
let { asset, onAction, preAction, onUndoDelete = undefined }: Props = $props();
|
||||
|
||||
let showConfirmModal = $state(false);
|
||||
const forceDefault = $derived(asset.isTrashed || !featureFlagsManager.value.trash);
|
||||
|
||||
const trashOrDelete = async (force = false) => {
|
||||
if (force || !featureFlagsManager.value.trash) {
|
||||
const trashOrDelete = async (forceRequest?: boolean) => {
|
||||
const timelineAsset = toTimelineAsset(asset);
|
||||
const force = forceDefault || forceRequest;
|
||||
|
||||
if (force) {
|
||||
if ($showDeleteModal) {
|
||||
showConfirmModal = true;
|
||||
return;
|
||||
const confirmed = await modalManager.show(AssetDeleteConfirmModal, { size: 1 });
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
await deleteAsset();
|
||||
|
||||
try {
|
||||
preAction({ type: AssetAction.DELETE, asset: timelineAsset });
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: [asset.id], force: true } });
|
||||
onAction({ type: AssetAction.DELETE, asset: timelineAsset });
|
||||
toastManager.success($t('permanently_deleted_asset'));
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_delete_asset'));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await trashAsset();
|
||||
return;
|
||||
};
|
||||
|
||||
const trashAsset = async () => {
|
||||
const timelineAsset = toTimelineAsset(asset);
|
||||
preAction({ type: AssetAction.TRASH, asset: timelineAsset });
|
||||
await deleteAssetsUtil(
|
||||
false,
|
||||
@@ -49,24 +56,11 @@
|
||||
onUndoDelete,
|
||||
);
|
||||
};
|
||||
|
||||
const deleteAsset = async () => {
|
||||
try {
|
||||
preAction({ type: AssetAction.DELETE, asset: toTimelineAsset(asset) });
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: [asset.id], force: true } });
|
||||
onAction({ type: AssetAction.DELETE, asset: toTimelineAsset(asset) });
|
||||
toastManager.success($t('permanently_deleted_asset'));
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_delete_asset'));
|
||||
} finally {
|
||||
showConfirmModal = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:document
|
||||
use:shortcuts={[
|
||||
{ shortcut: { key: 'Delete' }, onShortcut: () => trashOrDelete(asset.isTrashed) },
|
||||
{ shortcut: { key: 'Delete' }, onShortcut: () => trashOrDelete() },
|
||||
{ shortcut: { key: 'Delete', shift: true }, onShortcut: () => trashOrDelete(true) },
|
||||
]}
|
||||
/>
|
||||
@@ -75,13 +69,7 @@
|
||||
color="secondary"
|
||||
shape="round"
|
||||
variant="ghost"
|
||||
icon={asset.isTrashed ? mdiDeleteForeverOutline : mdiDeleteOutline}
|
||||
aria-label={asset.isTrashed ? $t('permanently_delete') : $t('delete')}
|
||||
onclick={() => trashOrDelete(asset.isTrashed)}
|
||||
icon={forceDefault ? mdiDeleteForeverOutline : mdiDeleteOutline}
|
||||
aria-label={forceDefault ? $t('permanently_delete') : $t('delete')}
|
||||
onclick={() => trashOrDelete()}
|
||||
/>
|
||||
|
||||
{#if showConfirmModal}
|
||||
<Portal target="body">
|
||||
<DeleteAssetDialog size={1} onCancel={() => (showConfirmModal = false)} onConfirm={deleteAsset} />
|
||||
</Portal>
|
||||
{/if}
|
||||
|
||||
@@ -32,8 +32,14 @@ describe('AssetViewerNavBar component', () => {
|
||||
vi.fn(() => ({ observe: vi.fn(), unobserve: vi.fn(), disconnect: vi.fn() })),
|
||||
);
|
||||
vi.mock(import('$lib/managers/feature-flags-manager.svelte'), () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return { featureFlagsManager: { init: vi.fn(), loadFeatureFlags: vi.fn(), value: { smartSearch: true } } as any };
|
||||
return {
|
||||
featureFlagsManager: {
|
||||
init: vi.fn(),
|
||||
loadFeatureFlags: vi.fn(),
|
||||
value: { trash: true, smartSearch: true },
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user