feat(web): undo delete (#18729)

* feat(web): Undo asset delete

* - lints and checks
- Update English translation

* Update delete-assets.svelte

Make onUndoDelete optional in Props interface

* - Ensure undo button not available on permanent delete, or trash disabled.
- Enforce lint requirement for no-negated-condition

* Fix formatting

* fix: lint

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
xCJPECKOVERx
2025-06-04 11:46:07 -04:00
committed by GitHub
parent 8733d1e554
commit 19ff39c2b9
12 changed files with 74 additions and 17 deletions
@@ -87,6 +87,7 @@
import { t } from 'svelte-i18n';
import { fly } from 'svelte/transition';
import type { PageData } from './$types';
import { type TimelineAsset } from '$lib/stores/assets-store.svelte';
interface Props {
data: PageData;
@@ -317,6 +318,11 @@
await refreshAlbum();
};
const handleUndoRemoveAssets = async (assets: TimelineAsset[]) => {
assetStore.addAssets(assets);
await refreshAlbum();
};
const handleUpdateThumbnail = async (assetId: string) => {
if (viewMode !== AlbumPageViewMode.SELECT_THUMBNAIL) {
return;
@@ -623,7 +629,7 @@
<RemoveFromAlbum menuItem bind:album onRemove={handleRemoveAssets} />
{/if}
{#if assetInteraction.isAllUserOwned}
<DeleteAssets menuItem onAssetDelete={handleRemoveAssets} />
<DeleteAssets menuItem onAssetDelete={handleRemoveAssets} onUndoDelete={handleUndoRemoveAssets} />
{/if}
</ButtonContextMenu>
</AssetSelectControlBar>
@@ -13,6 +13,7 @@
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import { AssetAction } from '$lib/constants';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { AssetVisibility } from '@immich/sdk';
@@ -20,7 +21,6 @@
import { onDestroy } from 'svelte';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
interface Props {
data: PageData;
@@ -92,7 +92,11 @@
<TagAction menuItem />
{/if}
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
<DeleteAssets menuItem onAssetDelete={(assetIds) => assetStore.removeAssets(assetIds)} />
<DeleteAssets
menuItem
onAssetDelete={(assetIds) => assetStore.removeAssets(assetIds)}
onUndoDelete={(assets) => assetStore.addAssets(assets)}
/>
</ButtonContextMenu>
</AssetSelectControlBar>
{/if}
@@ -122,6 +122,7 @@
{viewport}
showAssetName={true}
pageHeaderOffset={54}
onReload={triggerAssetUpdate}
/>
</div>
{/if}
@@ -170,7 +171,7 @@
{#if $preferences.tags.enabled && assetInteraction.isAllUserOwned}
<TagAction menuItem />
{/if}
<DeleteAssets menuItem onAssetDelete={triggerAssetUpdate} />
<DeleteAssets menuItem onAssetDelete={triggerAssetUpdate} onUndoDelete={triggerAssetUpdate} />
<hr />
<AssetJobActions />
</ButtonContextMenu>
@@ -351,6 +351,11 @@
await updateAssetCount();
};
const handleUndoDeleteAssets = async (assets: TimelineAsset[]) => {
assetStore.addAssets(assets);
await updateAssetCount();
};
let person = $derived(data.person);
let thumbnailData = $derived(getPeopleThumbnailUrl(person));
@@ -532,7 +537,11 @@
<TagAction menuItem />
{/if}
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
<DeleteAssets menuItem onAssetDelete={(assetIds) => handleDeleteAssets(assetIds)} />
<DeleteAssets
menuItem
onAssetDelete={(assetIds) => handleDeleteAssets(assetIds)}
onUndoDelete={(assets) => handleUndoDeleteAssets(assets)}
/>
</ButtonContextMenu>
</AssetSelectControlBar>
{:else}
@@ -150,7 +150,11 @@
{#if $preferences.tags.enabled}
<TagAction menuItem />
{/if}
<DeleteAssets menuItem onAssetDelete={(assetIds) => assetStore.removeAssets(assetIds)} />
<DeleteAssets
menuItem
onAssetDelete={(assetIds) => assetStore.removeAssets(assetIds)}
onUndoDelete={(assets) => assetStore.addAssets(assets)}
/>
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
<hr />
<AssetJobActions />
@@ -301,7 +301,7 @@
{#if $preferences.tags.enabled && assetInteraction.isAllUserOwned}
<TagAction menuItem />
{/if}
<DeleteAssets menuItem {onAssetDelete} />
<DeleteAssets menuItem {onAssetDelete} onUndoDelete={onSearchQueryUpdate} />
<hr />
<AssetJobActions />
</ButtonContextMenu>
@@ -382,6 +382,7 @@
showArchiveIcon={true}
{viewport}
pageHeaderOffset={54}
onReload={onSearchQueryUpdate}
/>
{:else if !isLoading}
<div class="flex min-h-[calc(66vh-11rem)] w-full place-content-center items-center dark:text-white">
@@ -444,7 +445,7 @@
{#if $preferences.tags.enabled && assetInteraction.isAllUserOwned}
<TagAction menuItem />
{/if}
<DeleteAssets menuItem {onAssetDelete} />
<DeleteAssets menuItem {onAssetDelete} onUndoDelete={onSearchQueryUpdate} />
<hr />
<AssetJobActions />
</ButtonContextMenu>