mirror of
https://github.com/immich-app/immich.git
synced 2025-12-08 22:01:00 -08:00
Compare commits
1 Commits
main
...
feat/singl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
caa6902a2c |
@@ -13,7 +13,7 @@ describe('DeleteAction component', () => {
|
||||
});
|
||||
|
||||
it('displays a button to move the asset to the trash bin', () => {
|
||||
const { getByTitle, queryByTitle } = render(DeleteAction, { asset, onAction: vi.fn() });
|
||||
const { getByTitle, queryByTitle } = render(DeleteAction, { asset, onAction: vi.fn(), preAction: vi.fn() });
|
||||
expect(getByTitle('delete')).toBeInTheDocument();
|
||||
expect(queryByTitle('deletePermanently')).toBeNull();
|
||||
});
|
||||
@@ -25,7 +25,7 @@ describe('DeleteAction component', () => {
|
||||
});
|
||||
|
||||
it('displays a button to permanently delete the asset', () => {
|
||||
const { getByTitle, queryByTitle } = render(DeleteAction, { asset, onAction: vi.fn() });
|
||||
const { getByTitle, queryByTitle } = render(DeleteAction, { asset, onAction: vi.fn(), preAction: vi.fn() });
|
||||
expect(getByTitle('permanently_delete')).toBeInTheDocument();
|
||||
expect(queryByTitle('delete')).toBeNull();
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import Portal from '$lib/elements/Portal.svelte';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.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';
|
||||
@@ -17,9 +18,10 @@
|
||||
asset: AssetResponseDto;
|
||||
onAction: OnAction;
|
||||
preAction: PreAction;
|
||||
onUndoDelete?: OnUndoDelete;
|
||||
}
|
||||
|
||||
let { asset, onAction, preAction }: Props = $props();
|
||||
let { asset, onAction, preAction, onUndoDelete = undefined }: Props = $props();
|
||||
|
||||
let showConfirmModal = $state(false);
|
||||
|
||||
@@ -38,14 +40,14 @@
|
||||
};
|
||||
|
||||
const trashAsset = async () => {
|
||||
try {
|
||||
preAction({ type: AssetAction.TRASH, asset: toTimelineAsset(asset) });
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: [asset.id] } });
|
||||
onAction({ type: AssetAction.TRASH, asset: toTimelineAsset(asset) });
|
||||
toastManager.success($t('moved_to_trash'));
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_trash_asset'));
|
||||
}
|
||||
const timelineAsset = toTimelineAsset(asset);
|
||||
preAction({ type: AssetAction.TRASH, asset: timelineAsset });
|
||||
await deleteAssetsUtil(
|
||||
false,
|
||||
() => onAction({ type: AssetAction.TRASH, asset: timelineAsset }),
|
||||
[timelineAsset],
|
||||
onUndoDelete,
|
||||
);
|
||||
};
|
||||
|
||||
const deleteAsset = async () => {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { photoZoomState } from '$lib/stores/zoom-image.store';
|
||||
import { getAssetJobName, getSharedLink } from '$lib/utils';
|
||||
import type { OnUndoDelete } from '$lib/utils/actions';
|
||||
import { canCopyImageToClipboard } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import {
|
||||
@@ -73,6 +74,7 @@
|
||||
onCopyImage?: () => Promise<void>;
|
||||
preAction: PreAction;
|
||||
onAction: OnAction;
|
||||
onUndoDelete?: OnUndoDelete;
|
||||
onRunJob: (name: AssetJobName) => void;
|
||||
onPlaySlideshow: () => void;
|
||||
onShowDetail: () => void;
|
||||
@@ -95,6 +97,7 @@
|
||||
onCopyImage,
|
||||
preAction,
|
||||
onAction,
|
||||
onUndoDelete = undefined,
|
||||
onRunJob,
|
||||
onPlaySlideshow,
|
||||
onShowDetail,
|
||||
@@ -182,7 +185,7 @@
|
||||
{/if}
|
||||
|
||||
{#if isOwner}
|
||||
<DeleteAction {asset} {onAction} {preAction} />
|
||||
<DeleteAction {asset} {onAction} {preAction} {onUndoDelete} />
|
||||
|
||||
<ButtonContextMenu direction="left" align="top-right" color="secondary" title={$t('more')} icon={mdiDotsVertical}>
|
||||
{#if showSlideshow && !isLocked}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { websocketEvents } from '$lib/stores/websocket';
|
||||
import { getAssetJobMessage, getSharedLink, handlePromiseError } from '$lib/utils';
|
||||
import type { OnUndoDelete } from '$lib/utils/actions';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { SlideshowHistory } from '$lib/utils/slideshow-history';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
@@ -62,6 +63,7 @@
|
||||
person?: PersonResponseDto | null;
|
||||
preAction?: PreAction | undefined;
|
||||
onAction?: OnAction | undefined;
|
||||
onUndoDelete?: OnUndoDelete | undefined;
|
||||
showCloseButton?: boolean;
|
||||
onClose: (asset: AssetResponseDto) => void;
|
||||
onNext: () => Promise<HasAsset>;
|
||||
@@ -80,6 +82,7 @@
|
||||
person = null,
|
||||
preAction = undefined,
|
||||
onAction = undefined,
|
||||
onUndoDelete = undefined,
|
||||
showCloseButton,
|
||||
onClose,
|
||||
onNext,
|
||||
@@ -430,6 +433,7 @@
|
||||
onCopyImage={copyImage}
|
||||
preAction={handlePreAction}
|
||||
onAction={handleAction}
|
||||
{onUndoDelete}
|
||||
onRunJob={handleRunJob}
|
||||
onPlaySlideshow={() => ($slideshowState = SlideshowState.PlaySlideshow)}
|
||||
onShowDetail={toggleDetailPanel}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { updateStackedAssetInTimeline, updateUnstackedAssetInTimeline } from '$lib/utils/actions';
|
||||
import { navigate } from '$lib/utils/navigation';
|
||||
@@ -163,6 +164,15 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleUndoDelete = async (assets: TimelineAsset[]) => {
|
||||
timelineManager.upsertAssets(assets);
|
||||
if (assets.length > 0) {
|
||||
const restoredAsset = assets[0];
|
||||
const asset = await getAssetInfo({ ...authManager.params, id: restoredAsset.id });
|
||||
assetViewingStore.setAsset(asset);
|
||||
await navigate({ targetRoute: 'current', assetId: restoredAsset.id });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
{#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }}
|
||||
@@ -175,6 +185,7 @@
|
||||
{person}
|
||||
preAction={handlePreAction}
|
||||
onAction={handleAction}
|
||||
onUndoDelete={handleUndoDelete}
|
||||
onPrevious={handlePrevious}
|
||||
onNext={handleNext}
|
||||
onRandom={handleRandom}
|
||||
|
||||
Reference in New Issue
Block a user