feat(web): lighter timeline buckets (#17719)
* feat(web): lighter timeline buckets * GalleryViewer * weird ssr * Remove generics from AssetInteraction * ensure keys on getAssetInfo, alt-text * empty - trigger ci * re-add alt-text * test fix * update tests * tests * missing import * fix: flappy e2e test * lint * revert settings * unneeded cast * fix after merge * missing import * lint * review * lint * avoid abbreviations * review comment - type safety in test * merge conflicts * lint * lint/abbreviations * fix: left-over migration --------- Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
@@ -1,20 +1,21 @@
|
||||
import type { AssetAction } from '$lib/constants';
|
||||
import type { AlbumResponseDto, AssetResponseDto } from '@immich/sdk';
|
||||
import type { TimelineAsset } from '$lib/stores/assets-store.svelte';
|
||||
import type { AlbumResponseDto } from '@immich/sdk';
|
||||
|
||||
type ActionMap = {
|
||||
[AssetAction.ARCHIVE]: { asset: AssetResponseDto };
|
||||
[AssetAction.UNARCHIVE]: { asset: AssetResponseDto };
|
||||
[AssetAction.FAVORITE]: { asset: AssetResponseDto };
|
||||
[AssetAction.UNFAVORITE]: { asset: AssetResponseDto };
|
||||
[AssetAction.TRASH]: { asset: AssetResponseDto };
|
||||
[AssetAction.DELETE]: { asset: AssetResponseDto };
|
||||
[AssetAction.RESTORE]: { asset: AssetResponseDto };
|
||||
[AssetAction.ADD]: { asset: AssetResponseDto };
|
||||
[AssetAction.ADD_TO_ALBUM]: { asset: AssetResponseDto; album: AlbumResponseDto };
|
||||
[AssetAction.UNSTACK]: { assets: AssetResponseDto[] };
|
||||
[AssetAction.KEEP_THIS_DELETE_OTHERS]: { asset: AssetResponseDto };
|
||||
[AssetAction.SET_VISIBILITY_LOCKED]: { asset: AssetResponseDto };
|
||||
[AssetAction.SET_VISIBILITY_TIMELINE]: { asset: AssetResponseDto };
|
||||
[AssetAction.ARCHIVE]: { asset: TimelineAsset };
|
||||
[AssetAction.UNARCHIVE]: { asset: TimelineAsset };
|
||||
[AssetAction.FAVORITE]: { asset: TimelineAsset };
|
||||
[AssetAction.UNFAVORITE]: { asset: TimelineAsset };
|
||||
[AssetAction.TRASH]: { asset: TimelineAsset };
|
||||
[AssetAction.DELETE]: { asset: TimelineAsset };
|
||||
[AssetAction.RESTORE]: { asset: TimelineAsset };
|
||||
[AssetAction.ADD]: { asset: TimelineAsset };
|
||||
[AssetAction.ADD_TO_ALBUM]: { asset: TimelineAsset; album: AlbumResponseDto };
|
||||
[AssetAction.UNSTACK]: { assets: TimelineAsset[] };
|
||||
[AssetAction.KEEP_THIS_DELETE_OTHERS]: { asset: TimelineAsset };
|
||||
[AssetAction.SET_VISIBILITY_LOCKED]: { asset: TimelineAsset };
|
||||
[AssetAction.SET_VISIBILITY_TIMELINE]: { asset: TimelineAsset };
|
||||
};
|
||||
|
||||
export type Action = {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import Portal from '$lib/components/shared-components/portal/portal.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { addAssetsToAlbum, addAssetsToNewAlbum } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import type { AlbumResponseDto, AssetResponseDto } from '@immich/sdk';
|
||||
import { mdiImageAlbum, mdiShareVariantOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -24,14 +25,14 @@
|
||||
showSelectionModal = false;
|
||||
const album = await addAssetsToNewAlbum(albumName, [asset.id]);
|
||||
if (album) {
|
||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset, album });
|
||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toTimelineAsset(asset), album });
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddToAlbum = async (album: AlbumResponseDto) => {
|
||||
showSelectionModal = false;
|
||||
await addAssetsToAlbum(album.id, [asset.id]);
|
||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset, album });
|
||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toTimelineAsset(asset), album });
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { toggleArchive } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import type { AssetResponseDto } from '@immich/sdk';
|
||||
import { mdiArchiveArrowDownOutline, mdiArchiveArrowUpOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -18,11 +19,11 @@
|
||||
|
||||
const onArchive = async () => {
|
||||
if (!asset.isArchived) {
|
||||
preAction({ type: AssetAction.ARCHIVE, asset });
|
||||
preAction({ type: AssetAction.ARCHIVE, asset: toTimelineAsset(asset) });
|
||||
}
|
||||
const updatedAsset = await toggleArchive(asset);
|
||||
if (updatedAsset) {
|
||||
onAction({ type: asset.isArchived ? AssetAction.ARCHIVE : AssetAction.UNARCHIVE, asset });
|
||||
onAction({ type: asset.isArchived ? AssetAction.ARCHIVE : AssetAction.UNARCHIVE, asset: toTimelineAsset(asset) });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import { showDeleteModal } from '$lib/stores/preferences.store';
|
||||
import { featureFlags } from '$lib/stores/server-config.store';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { deleteAssets, type AssetResponseDto } from '@immich/sdk';
|
||||
import { mdiDeleteForeverOutline, mdiDeleteOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -42,9 +43,9 @@
|
||||
|
||||
const trashAsset = async () => {
|
||||
try {
|
||||
preAction({ type: AssetAction.TRASH, asset });
|
||||
preAction({ type: AssetAction.TRASH, asset: toTimelineAsset(asset) });
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: [asset.id] } });
|
||||
onAction({ type: AssetAction.TRASH, asset });
|
||||
onAction({ type: AssetAction.TRASH, asset: toTimelineAsset(asset) });
|
||||
|
||||
notificationController.show({
|
||||
message: $t('moved_to_trash'),
|
||||
@@ -58,7 +59,7 @@
|
||||
const deleteAsset = async () => {
|
||||
try {
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: [asset.id], force: true } });
|
||||
onAction({ type: AssetAction.DELETE, asset });
|
||||
onAction({ type: AssetAction.DELETE, asset: toTimelineAsset(asset) });
|
||||
|
||||
notificationController.show({
|
||||
message: $t('permanently_deleted_asset'),
|
||||
|
||||
@@ -2,19 +2,21 @@
|
||||
import { shortcut } from '$lib/actions/shortcut';
|
||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/stores/assets-store.svelte';
|
||||
import { downloadFile } from '$lib/utils/asset-utils';
|
||||
import type { AssetResponseDto } from '@immich/sdk';
|
||||
import { getAssetInfo } from '@immich/sdk';
|
||||
import { mdiFolderDownloadOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
interface Props {
|
||||
asset: AssetResponseDto;
|
||||
asset: TimelineAsset;
|
||||
menuItem?: boolean;
|
||||
}
|
||||
|
||||
let { asset, menuItem = false }: Props = $props();
|
||||
|
||||
const onDownloadFile = () => downloadFile(asset);
|
||||
const onDownloadFile = async () => downloadFile(await getAssetInfo({ id: asset.id, key: authManager.key }));
|
||||
</script>
|
||||
|
||||
<svelte:window use:shortcut={{ shortcut: { key: 'd', shift: true }, onShortcut: onDownloadFile }} />
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
} from '$lib/components/shared-components/notification/notification';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { updateAsset, type AssetResponseDto } from '@immich/sdk';
|
||||
import { mdiHeart, mdiHeartOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -30,7 +31,10 @@
|
||||
|
||||
asset = { ...asset, isFavorite: data.isFavorite };
|
||||
|
||||
onAction({ type: asset.isFavorite ? AssetAction.FAVORITE : AssetAction.UNFAVORITE, asset });
|
||||
onAction({
|
||||
type: asset.isFavorite ? AssetAction.FAVORITE : AssetAction.UNFAVORITE,
|
||||
asset: toTimelineAsset(asset),
|
||||
});
|
||||
|
||||
notificationController.show({
|
||||
type: NotificationType.Info,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
||||
import { keepThisDeleteOthers } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import type { AssetResponseDto, StackResponseDto } from '@immich/sdk';
|
||||
import { mdiPinOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -29,7 +30,7 @@
|
||||
|
||||
const keptAsset = await keepThisDeleteOthers(asset, stack);
|
||||
if (keptAsset) {
|
||||
onAction({ type: AssetAction.UNSTACK, assets: [keptAsset] });
|
||||
onAction({ type: AssetAction.UNSTACK, assets: [toTimelineAsset(keptAsset)] });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
} from '$lib/components/shared-components/notification/notification';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import { restoreAssets, type AssetResponseDto } from '@immich/sdk';
|
||||
import { mdiHistory } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -23,7 +24,7 @@
|
||||
await restoreAssets({ bulkIdsDto: { ids: [asset.id] } });
|
||||
asset.isTrashed = false;
|
||||
|
||||
onAction({ type: AssetAction.RESTORE, asset });
|
||||
onAction({ type: AssetAction.RESTORE, asset: toTimelineAsset(asset) });
|
||||
|
||||
notificationController.show({
|
||||
type: NotificationType.Info,
|
||||
|
||||
@@ -3,14 +3,15 @@
|
||||
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/stores/assets-store.svelte';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { AssetVisibility, updateAssets, Visibility, type AssetResponseDto } from '@immich/sdk';
|
||||
import { AssetVisibility, updateAssets, Visibility } from '@immich/sdk';
|
||||
import { mdiEyeOffOutline, mdiFolderMoveOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
import type { OnAction, PreAction } from './action';
|
||||
|
||||
interface Props {
|
||||
asset: AssetResponseDto;
|
||||
asset: TimelineAsset;
|
||||
onAction: OnAction;
|
||||
preAction: PreAction;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||
import { AssetAction } from '$lib/constants';
|
||||
import { deleteStack } from '$lib/utils/asset-utils';
|
||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||
import type { StackResponseDto } from '@immich/sdk';
|
||||
import { mdiImageMinusOutline } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -17,7 +18,7 @@
|
||||
const handleUnstack = async () => {
|
||||
const unstackedAssets = await deleteStack([stack.id]);
|
||||
if (unstackedAssets) {
|
||||
onAction({ type: AssetAction.UNSTACK, assets: unstackedAssets });
|
||||
onAction({ type: AssetAction.UNSTACK, assets: unstackedAssets.map((asset) => toTimelineAsset(asset)) });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user