mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
refactor: adjust favorite, delete, and archive actions for timeline
- Pass TimelineManager instance to timeline action components instead of callbacks - Move asset update logic (delete, archive, favorite) into action components
This commit is contained in:
parent
e5fce47c0c
commit
98ab224791
12 changed files with 74 additions and 104 deletions
|
|
@ -161,7 +161,24 @@ export class NotificationService extends BaseService {
|
|||
|
||||
const [asset] = await this.assetRepository.getByIdsWithAllRelationsButStacks([assetId]);
|
||||
if (asset) {
|
||||
this.eventRepository.clientSend('on_asset_update', userId, mapAsset(asset));
|
||||
// need to specify authDto to this mapAsset request, because it tries to prevent
|
||||
// leaking information PR#7580 which expects a userId in the auth options object
|
||||
this.eventRepository.clientSend(
|
||||
'on_asset_update',
|
||||
userId,
|
||||
mapAsset(asset, {
|
||||
auth: {
|
||||
user: {
|
||||
id: userId,
|
||||
isAdmin: false,
|
||||
name: '',
|
||||
email: '',
|
||||
quotaUsageInBytes: 0,
|
||||
quotaSizeInBytes: null,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import type { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { OnArchive } from '$lib/utils/actions';
|
||||
import { archiveAssets } from '$lib/utils/asset-utils';
|
||||
import { AssetVisibility } from '@immich/sdk';
|
||||
|
|
@ -12,9 +13,10 @@
|
|||
onArchive?: OnArchive;
|
||||
menuItem?: boolean;
|
||||
unarchive?: boolean;
|
||||
manager?: TimelineManager;
|
||||
}
|
||||
|
||||
let { onArchive, menuItem = false, unarchive = false }: Props = $props();
|
||||
let { onArchive, menuItem = false, unarchive = false, manager }: Props = $props();
|
||||
|
||||
let text = $derived(unarchive ? $t('unarchive') : $t('to_archive'));
|
||||
let icon = $derived(unarchive ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline);
|
||||
|
|
@ -24,12 +26,13 @@
|
|||
const { clearSelect, getOwnedAssets } = getAssetControlContext();
|
||||
|
||||
const handleArchive = async () => {
|
||||
const isArchived = unarchive ? AssetVisibility.Timeline : AssetVisibility.Archive;
|
||||
const assets = [...getOwnedAssets()].filter((asset) => asset.visibility !== isArchived);
|
||||
const visibility = unarchive ? AssetVisibility.Timeline : AssetVisibility.Archive;
|
||||
const assets = [...getOwnedAssets()].filter((asset) => asset.visibility !== visibility);
|
||||
loading = true;
|
||||
const ids = await archiveAssets(assets, isArchived as AssetVisibility);
|
||||
const ids = await archiveAssets(assets, visibility as AssetVisibility);
|
||||
if (ids) {
|
||||
onArchive?.(ids, isArchived ? AssetVisibility.Archive : AssetVisibility.Timeline);
|
||||
manager?.updateAssetOperation(ids, (asset) => ((asset.visibility = visibility), void 0));
|
||||
onArchive?.(ids, visibility ? AssetVisibility.Archive : AssetVisibility.Timeline);
|
||||
clearSelect();
|
||||
}
|
||||
loading = false;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<script lang="ts">
|
||||
import DeleteAssetDialog from '$lib/components/photos-page/delete-asset-dialog.svelte';
|
||||
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import { featureFlags } from '$lib/stores/server-config.store';
|
||||
import { type OnDelete, type OnUndoDelete, deleteAssets } from '$lib/utils/actions';
|
||||
import { IconButton } from '@immich/ui';
|
||||
|
|
@ -9,13 +11,14 @@
|
|||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||
|
||||
interface Props {
|
||||
onAssetDelete: OnDelete;
|
||||
onUndoDelete?: OnUndoDelete | undefined;
|
||||
onAssetDelete?: OnDelete;
|
||||
onUndoDelete?: OnUndoDelete;
|
||||
menuItem?: boolean;
|
||||
force?: boolean;
|
||||
manager?: TimelineManager;
|
||||
}
|
||||
|
||||
let { onAssetDelete, onUndoDelete = undefined, menuItem = false, force = !$featureFlags.trash }: Props = $props();
|
||||
let { onAssetDelete, onUndoDelete, menuItem = false, force = !$featureFlags.trash, manager }: Props = $props();
|
||||
|
||||
const { clearSelect, getOwnedAssets } = getAssetControlContext();
|
||||
|
||||
|
|
@ -36,7 +39,12 @@
|
|||
const handleDelete = async () => {
|
||||
loading = true;
|
||||
const assets = [...getOwnedAssets()];
|
||||
await deleteAssets(force, onAssetDelete, assets, onUndoDelete);
|
||||
const undo = (assets: TimelineAsset[]) => {
|
||||
manager?.addAssets(assets);
|
||||
onUndoDelete?.(assets);
|
||||
};
|
||||
await deleteAssets(force, onAssetDelete, assets, undo);
|
||||
manager?.removeAssets(assets.map((asset) => asset.id));
|
||||
clearSelect();
|
||||
isShowConfirmation = false;
|
||||
loading = false;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
notificationController,
|
||||
} from '$lib/components/shared-components/notification/notification';
|
||||
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import type { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { OnFavorite } from '$lib/utils/actions';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { updateAssets } from '@immich/sdk';
|
||||
|
|
@ -16,9 +17,10 @@
|
|||
onFavorite?: OnFavorite;
|
||||
menuItem?: boolean;
|
||||
removeFavorite: boolean;
|
||||
manager?: TimelineManager;
|
||||
}
|
||||
|
||||
let { onFavorite, menuItem = false, removeFavorite }: Props = $props();
|
||||
let { onFavorite, menuItem = false, removeFavorite, manager }: Props = $props();
|
||||
|
||||
let text = $derived(removeFavorite ? $t('remove_from_favorites') : $t('to_favorite'));
|
||||
let icon = $derived(removeFavorite ? mdiHeartMinusOutline : mdiHeartOutline);
|
||||
|
|
@ -39,11 +41,7 @@
|
|||
if (ids.length > 0) {
|
||||
await updateAssets({ assetBulkUpdateDto: { ids, isFavorite } });
|
||||
}
|
||||
|
||||
for (const asset of assets) {
|
||||
asset.isFavorite = isFavorite;
|
||||
}
|
||||
|
||||
manager?.updateAssetOperation(ids, (asset) => ((asset.isFavorite = isFavorite), void 0));
|
||||
onFavorite?.(ids, isFavorite);
|
||||
|
||||
notificationController.show({
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ export class DayGroup {
|
|||
|
||||
const asset = this.viewerAssets[index].asset!;
|
||||
const oldTime = { ...asset.localDateTime };
|
||||
let { remove } = operation(asset);
|
||||
let { remove } = operation(asset) ?? { remove: false };
|
||||
const newTime = asset.localDateTime;
|
||||
if (oldTime.year !== newTime.year || oldTime.month !== newTime.month || oldTime.day !== newTime.day) {
|
||||
const { year, month, day } = newTime;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export type TimelineAsset = {
|
|||
longitude?: number | null;
|
||||
};
|
||||
|
||||
export type AssetOperation = (asset: TimelineAsset) => { remove: boolean };
|
||||
export type AssetOperation = (asset: TimelineAsset) => { remove: boolean } | void;
|
||||
|
||||
export type MoveAsset = { asset: TimelineAsset; date: TimelineDate };
|
||||
|
||||
|
|
|
|||
|
|
@ -21,15 +21,15 @@ export type OnSetVisibility = (ids: string[]) => void;
|
|||
|
||||
export const deleteAssets = async (
|
||||
force: boolean,
|
||||
onAssetDelete: OnDelete,
|
||||
onAssetDelete: OnDelete | undefined,
|
||||
assets: TimelineAsset[],
|
||||
onUndoDelete: OnUndoDelete | undefined = undefined,
|
||||
onUndoDelete: OnUndoDelete | undefined,
|
||||
) => {
|
||||
const $t = get(t);
|
||||
try {
|
||||
const ids = assets.map((a) => a.id);
|
||||
await deleteBulk({ assetBulkDeleteDto: { ids, force } });
|
||||
onAssetDelete(ids);
|
||||
onAssetDelete?.(ids);
|
||||
|
||||
notificationController.show({
|
||||
message: force
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
import { AlbumPageViewMode, AppRoute } from '$lib/constants';
|
||||
import { activityManager } from '$lib/managers/activity-manager.svelte';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import AlbumOptionsModal from '$lib/modals/AlbumOptionsModal.svelte';
|
||||
import AlbumShareModal from '$lib/modals/AlbumShareModal.svelte';
|
||||
import AlbumUsersModal from '$lib/modals/AlbumUsersModal.svelte';
|
||||
|
|
@ -262,18 +261,15 @@
|
|||
}
|
||||
};
|
||||
|
||||
const handleSetVisibility = (assetIds: string[]) => {
|
||||
timelineManager.removeAssets(assetIds);
|
||||
const handleSetVisibility = () => {
|
||||
assetInteraction.clearMultiselect();
|
||||
};
|
||||
|
||||
const handleRemoveAssets = async (assetIds: string[]) => {
|
||||
timelineManager.removeAssets(assetIds);
|
||||
const handleRemoveAssets = async () => {
|
||||
await refreshAlbum();
|
||||
};
|
||||
|
||||
const handleUndoRemoveAssets = async (assets: TimelineAsset[]) => {
|
||||
timelineManager.addAssets(assets);
|
||||
const handleUndoRemoveAssets = async () => {
|
||||
await refreshAlbum();
|
||||
};
|
||||
|
||||
|
|
@ -572,14 +568,7 @@
|
|||
<AddToAlbum shared />
|
||||
</ButtonContextMenu>
|
||||
{#if assetInteraction.isAllUserOwned}
|
||||
<FavoriteAction
|
||||
removeFavorite={assetInteraction.isAllFavorite}
|
||||
onFavorite={(ids, isFavorite) =>
|
||||
timelineManager.updateAssetOperation(ids, (asset) => {
|
||||
asset.isFavorite = isFavorite;
|
||||
return { remove: false };
|
||||
})}
|
||||
></FavoriteAction>
|
||||
<FavoriteAction removeFavorite={assetInteraction.isAllFavorite} manager={timelineManager}></FavoriteAction>
|
||||
{/if}
|
||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')} offset={{ x: 175, y: 25 }}>
|
||||
<DownloadAction menuItem filename="{album.albumName}.zip" />
|
||||
|
|
@ -594,7 +583,7 @@
|
|||
onClick={() => updateThumbnailUsingCurrentSelection()}
|
||||
/>
|
||||
{/if}
|
||||
<ArchiveAction menuItem unarchive={assetInteraction.isAllArchived} />
|
||||
<ArchiveAction menuItem unarchive={assetInteraction.isAllArchived} manager={timelineManager} />
|
||||
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
||||
{/if}
|
||||
|
||||
|
|
@ -606,7 +595,12 @@
|
|||
<RemoveFromAlbum menuItem bind:album onRemove={handleRemoveAssets} />
|
||||
{/if}
|
||||
{#if assetInteraction.isAllUserOwned}
|
||||
<DeleteAssets menuItem onAssetDelete={handleRemoveAssets} onUndoDelete={handleUndoRemoveAssets} />
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={handleRemoveAssets}
|
||||
onUndoDelete={handleUndoRemoveAssets}
|
||||
manager={timelineManager}
|
||||
/>
|
||||
{/if}
|
||||
</ButtonContextMenu>
|
||||
</AssetSelectControlBar>
|
||||
|
|
|
|||
|
|
@ -65,32 +65,18 @@
|
|||
assets={assetInteraction.selectedAssets}
|
||||
clearSelect={() => assetInteraction.clearMultiselect()}
|
||||
>
|
||||
<ArchiveAction
|
||||
unarchive
|
||||
onArchive={(ids, visibility) =>
|
||||
timelineManager.updateAssetOperation(ids, (asset) => {
|
||||
asset.visibility = visibility;
|
||||
return { remove: false };
|
||||
})}
|
||||
/>
|
||||
<ArchiveAction unarchive manager={timelineManager} />
|
||||
<CreateSharedLink />
|
||||
<SelectAllAssets {timelineManager} {assetInteraction} />
|
||||
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
||||
<AddToAlbum />
|
||||
<AddToAlbum shared />
|
||||
</ButtonContextMenu>
|
||||
<FavoriteAction
|
||||
removeFavorite={assetInteraction.isAllFavorite}
|
||||
onFavorite={(ids, isFavorite) =>
|
||||
timelineManager.updateAssetOperation(ids, (asset) => {
|
||||
asset.isFavorite = isFavorite;
|
||||
return { remove: false };
|
||||
})}
|
||||
/>
|
||||
<FavoriteAction removeFavorite={assetInteraction.isAllFavorite} manager={timelineManager} />
|
||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
||||
<DownloadAction menuItem />
|
||||
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
||||
<DeleteAssets menuItem onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
||||
<DeleteAssets menuItem manager={timelineManager} />
|
||||
</ButtonContextMenu>
|
||||
</AssetSelectControlBar>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@
|
|||
assets={assetInteraction.selectedAssets}
|
||||
clearSelect={() => assetInteraction.clearMultiselect()}
|
||||
>
|
||||
<FavoriteAction removeFavorite onFavorite={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
||||
<FavoriteAction removeFavorite manager={timelineManager} />
|
||||
<CreateSharedLink />
|
||||
<SelectAllAssets {timelineManager} {assetInteraction} />
|
||||
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
||||
|
|
@ -83,20 +83,12 @@
|
|||
<ChangeDate menuItem />
|
||||
<ChangeDescription menuItem />
|
||||
<ChangeLocation menuItem />
|
||||
<ArchiveAction
|
||||
menuItem
|
||||
unarchive={assetInteraction.isAllArchived}
|
||||
onArchive={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||
/>
|
||||
<ArchiveAction menuItem unarchive={assetInteraction.isAllArchived} manager={timelineManager} />
|
||||
{#if $preferences.tags.enabled}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||
onUndoDelete={(assets) => timelineManager.addAssets(assets)}
|
||||
/>
|
||||
<DeleteAssets menuItem manager={timelineManager} />
|
||||
</ButtonContextMenu>
|
||||
</AssetSelectControlBar>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -349,15 +349,8 @@
|
|||
}
|
||||
};
|
||||
|
||||
const handleDeleteAssets = async (assetIds: string[]) => {
|
||||
timelineManager.removeAssets(assetIds);
|
||||
await updateAssetCount();
|
||||
};
|
||||
|
||||
const handleUndoDeleteAssets = async (assets: TimelineAsset[]) => {
|
||||
timelineManager.addAssets(assets);
|
||||
await updateAssetCount();
|
||||
};
|
||||
const handleDeleteAssets = async () => await updateAssetCount();
|
||||
const handleUndoDeleteAssets = async () => await updateAssetCount();
|
||||
|
||||
let person = $derived(data.person);
|
||||
|
||||
|
|
@ -511,14 +504,7 @@
|
|||
<AddToAlbum />
|
||||
<AddToAlbum shared />
|
||||
</ButtonContextMenu>
|
||||
<FavoriteAction
|
||||
removeFavorite={assetInteraction.isAllFavorite}
|
||||
onFavorite={(ids, isFavorite) =>
|
||||
timelineManager.updateAssetOperation(ids, (asset) => {
|
||||
asset.isFavorite = isFavorite;
|
||||
return { remove: false };
|
||||
})}
|
||||
/>
|
||||
<FavoriteAction removeFavorite={assetInteraction.isAllFavorite} manager={timelineManager} />
|
||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
||||
<DownloadAction menuItem filename="{person.name || 'immich'}.zip" />
|
||||
<MenuOption
|
||||
|
|
@ -529,19 +515,16 @@
|
|||
<ChangeDate menuItem />
|
||||
<ChangeDescription menuItem />
|
||||
<ChangeLocation menuItem />
|
||||
<ArchiveAction
|
||||
menuItem
|
||||
unarchive={assetInteraction.isAllArchived}
|
||||
onArchive={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||
/>
|
||||
<ArchiveAction menuItem unarchive={assetInteraction.isAllArchived} manager={timelineManager} />
|
||||
{#if $preferences.tags.enabled && assetInteraction.isAllUserOwned}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={(assetIds) => handleDeleteAssets(assetIds)}
|
||||
onUndoDelete={(assets) => handleUndoDeleteAssets(assets)}
|
||||
manager={timelineManager}
|
||||
onAssetDelete={handleDeleteAssets}
|
||||
onUndoDelete={handleUndoDeleteAssets}
|
||||
/>
|
||||
</ButtonContextMenu>
|
||||
</AssetSelectControlBar>
|
||||
|
|
|
|||
|
|
@ -118,14 +118,7 @@
|
|||
<AddToAlbum />
|
||||
<AddToAlbum shared />
|
||||
</ButtonContextMenu>
|
||||
<FavoriteAction
|
||||
removeFavorite={assetInteraction.isAllFavorite}
|
||||
onFavorite={(ids, isFavorite) =>
|
||||
timelineManager.updateAssetOperation(ids, (asset) => {
|
||||
asset.isFavorite = isFavorite;
|
||||
return { remove: false };
|
||||
})}
|
||||
></FavoriteAction>
|
||||
<FavoriteAction removeFavorite={assetInteraction.isAllFavorite} manager={timelineManager}></FavoriteAction>
|
||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
||||
<DownloadAction menuItem />
|
||||
{#if assetInteraction.selectedAssets.length > 1 || isAssetStackSelected}
|
||||
|
|
@ -146,15 +139,11 @@
|
|||
<ChangeDate menuItem />
|
||||
<ChangeDescription menuItem />
|
||||
<ChangeLocation menuItem />
|
||||
<ArchiveAction menuItem onArchive={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
||||
<ArchiveAction menuItem manager={timelineManager} />
|
||||
{#if $preferences.tags.enabled}
|
||||
<TagAction menuItem />
|
||||
{/if}
|
||||
<DeleteAssets
|
||||
menuItem
|
||||
onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||
onUndoDelete={(assets) => timelineManager.addAssets(assets)}
|
||||
/>
|
||||
<DeleteAssets menuItem manager={timelineManager} />
|
||||
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
||||
<hr />
|
||||
<AssetJobActions />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue