mirror of
https://github.com/immich-app/immich.git
synced 2026-02-28 09:38:43 +03:00
refactor: add to album (#26366)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import type { AssetAction } from '$lib/constants';
|
import type { AssetAction } from '$lib/constants';
|
||||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||||
import type { AlbumResponseDto, AssetResponseDto, PersonResponseDto, StackResponseDto } from '@immich/sdk';
|
import type { AssetResponseDto, PersonResponseDto, StackResponseDto } from '@immich/sdk';
|
||||||
|
|
||||||
type ActionMap = {
|
type ActionMap = {
|
||||||
[AssetAction.ARCHIVE]: { asset: TimelineAsset };
|
[AssetAction.ARCHIVE]: { asset: TimelineAsset };
|
||||||
@@ -8,7 +8,6 @@ type ActionMap = {
|
|||||||
[AssetAction.TRASH]: { asset: TimelineAsset };
|
[AssetAction.TRASH]: { asset: TimelineAsset };
|
||||||
[AssetAction.DELETE]: { asset: TimelineAsset };
|
[AssetAction.DELETE]: { asset: TimelineAsset };
|
||||||
[AssetAction.RESTORE]: { asset: TimelineAsset };
|
[AssetAction.RESTORE]: { asset: TimelineAsset };
|
||||||
[AssetAction.ADD_TO_ALBUM]: { asset: TimelineAsset; album: AlbumResponseDto };
|
|
||||||
[AssetAction.STACK]: { stack: StackResponseDto };
|
[AssetAction.STACK]: { stack: StackResponseDto };
|
||||||
[AssetAction.UNSTACK]: { assets: TimelineAsset[] };
|
[AssetAction.UNSTACK]: { assets: TimelineAsset[] };
|
||||||
[AssetAction.SET_STACK_PRIMARY_ASSET]: { stack: StackResponseDto };
|
[AssetAction.SET_STACK_PRIMARY_ASSET]: { stack: StackResponseDto };
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { shortcut } from '$lib/actions/shortcut';
|
|
||||||
import type { OnAction } from '$lib/components/asset-viewer/actions/action';
|
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
|
||||||
import { AssetAction } from '$lib/constants';
|
|
||||||
import AlbumPickerModal from '$lib/modals/AlbumPickerModal.svelte';
|
|
||||||
import { addAssetsToAlbum, addAssetsToAlbums } from '$lib/utils/asset-utils';
|
|
||||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
|
||||||
import type { AssetResponseDto } from '@immich/sdk';
|
|
||||||
import { modalManager } from '@immich/ui';
|
|
||||||
import { mdiImageAlbum } from '@mdi/js';
|
|
||||||
import { t } from 'svelte-i18n';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
asset: AssetResponseDto;
|
|
||||||
onAction: OnAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { asset, onAction }: Props = $props();
|
|
||||||
|
|
||||||
const onClick = async () => {
|
|
||||||
const albums = await modalManager.show(AlbumPickerModal, {});
|
|
||||||
|
|
||||||
if (!albums || albums.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (albums.length === 1) {
|
|
||||||
const album = albums[0];
|
|
||||||
await addAssetsToAlbum(album.id, [asset.id]);
|
|
||||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toTimelineAsset(asset), album });
|
|
||||||
} else {
|
|
||||||
await addAssetsToAlbums(
|
|
||||||
albums.map((a) => a.id),
|
|
||||||
[asset.id],
|
|
||||||
);
|
|
||||||
onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toTimelineAsset(asset), album: albums[0] });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:document use:shortcut={{ shortcut: { key: 'l' }, onShortcut: onClick }} />
|
|
||||||
|
|
||||||
<MenuOption icon={mdiImageAlbum} text={$t('add_to_album')} {onClick} />
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
import ActionButton from '$lib/components/ActionButton.svelte';
|
import ActionButton from '$lib/components/ActionButton.svelte';
|
||||||
import ActionMenuItem from '$lib/components/ActionMenuItem.svelte';
|
import ActionMenuItem from '$lib/components/ActionMenuItem.svelte';
|
||||||
import type { OnAction, PreAction } from '$lib/components/asset-viewer/actions/action';
|
import type { OnAction, PreAction } from '$lib/components/asset-viewer/actions/action';
|
||||||
import AddToAlbumAction from '$lib/components/asset-viewer/actions/add-to-album-action.svelte';
|
|
||||||
import AddToStackAction from '$lib/components/asset-viewer/actions/add-to-stack-action.svelte';
|
import AddToStackAction from '$lib/components/asset-viewer/actions/add-to-stack-action.svelte';
|
||||||
import ArchiveAction from '$lib/components/asset-viewer/actions/archive-action.svelte';
|
import ArchiveAction from '$lib/components/asset-viewer/actions/archive-action.svelte';
|
||||||
import DeleteAction from '$lib/components/asset-viewer/actions/delete-action.svelte';
|
import DeleteAction from '$lib/components/asset-viewer/actions/delete-action.svelte';
|
||||||
@@ -102,6 +101,7 @@
|
|||||||
Unfavorite,
|
Unfavorite,
|
||||||
PlayMotionPhoto,
|
PlayMotionPhoto,
|
||||||
StopMotionPhoto,
|
StopMotionPhoto,
|
||||||
|
AddToAlbum,
|
||||||
ZoomIn,
|
ZoomIn,
|
||||||
ZoomOut,
|
ZoomOut,
|
||||||
Copy,
|
Copy,
|
||||||
@@ -129,6 +129,7 @@
|
|||||||
Unfavorite,
|
Unfavorite,
|
||||||
PlayMotionPhoto,
|
PlayMotionPhoto,
|
||||||
StopMotionPhoto,
|
StopMotionPhoto,
|
||||||
|
AddToAlbum,
|
||||||
ZoomIn,
|
ZoomIn,
|
||||||
ZoomOut,
|
ZoomOut,
|
||||||
Copy,
|
Copy,
|
||||||
@@ -181,14 +182,12 @@
|
|||||||
<ActionMenuItem action={Download} />
|
<ActionMenuItem action={Download} />
|
||||||
<ActionMenuItem action={DownloadOriginal} />
|
<ActionMenuItem action={DownloadOriginal} />
|
||||||
|
|
||||||
{#if !isLocked}
|
{#if !isLocked && asset.isTrashed}
|
||||||
{#if asset.isTrashed}
|
<RestoreAction {asset} {onAction} />
|
||||||
<RestoreAction {asset} {onAction} />
|
|
||||||
{:else}
|
|
||||||
<AddToAlbumAction {asset} {onAction} />
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<ActionMenuItem action={AddToAlbum} />
|
||||||
|
|
||||||
{#if isOwner}
|
{#if isOwner}
|
||||||
<AddToStackAction {asset} {stack} {onAction} />
|
<AddToStackAction {asset} {stack} {onAction} />
|
||||||
{#if stack}
|
{#if stack}
|
||||||
|
|||||||
@@ -167,9 +167,7 @@
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!sharedLink) {
|
await onAlbumAddAssets();
|
||||||
await handleGetAllAlbums();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
@@ -182,7 +180,7 @@
|
|||||||
syncAssetViewerOpenClass(false);
|
syncAssetViewerOpenClass(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleGetAllAlbums = async () => {
|
const onAlbumAddAssets = async () => {
|
||||||
if (authManager.isSharedLink) {
|
if (authManager.isSharedLink) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -303,10 +301,6 @@
|
|||||||
};
|
};
|
||||||
const handleAction = async (action: Action) => {
|
const handleAction = async (action: Action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case AssetAction.ADD_TO_ALBUM: {
|
|
||||||
await handleGetAllAlbums();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetAction.DELETE:
|
case AssetAction.DELETE:
|
||||||
case AssetAction.TRASH: {
|
case AssetAction.TRASH: {
|
||||||
eventManager.emit('AssetsDelete', [asset.id]);
|
eventManager.emit('AssetsDelete', [asset.id]);
|
||||||
@@ -369,7 +363,7 @@
|
|||||||
|
|
||||||
const refresh = async () => {
|
const refresh = async () => {
|
||||||
await refreshStack();
|
await refreshStack();
|
||||||
await handleGetAllAlbums();
|
await onAlbumAddAssets();
|
||||||
ocrManager.clear();
|
ocrManager.clear();
|
||||||
if (!sharedLink) {
|
if (!sharedLink) {
|
||||||
if (previewStackedAsset) {
|
if (previewStackedAsset) {
|
||||||
@@ -441,7 +435,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CommandPaletteDefaultProvider name={$t('assets')} actions={[Tag]} />
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={[Tag]} />
|
||||||
<OnEvents {onAssetReplace} {onAssetUpdate} />
|
<OnEvents {onAssetReplace} {onAssetUpdate} {onAlbumAddAssets} />
|
||||||
|
|
||||||
<svelte:document bind:fullscreenElement />
|
<svelte:document bind:fullscreenElement />
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
|
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
||||||
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
||||||
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
||||||
@@ -25,6 +24,7 @@
|
|||||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types';
|
import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types';
|
||||||
import { Route } from '$lib/route';
|
import { Route } from '$lib/route';
|
||||||
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||||
import { memoryStore, type MemoryAsset } from '$lib/stores/memory.store.svelte';
|
import { memoryStore, type MemoryAsset } from '$lib/stores/memory.store.svelte';
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||||
import { fromISODateTimeUTC, toTimelineAsset } from '$lib/utils/timeline-util';
|
import { fromISODateTimeUTC, toTimelineAsset } from '$lib/utils/timeline-util';
|
||||||
import { AssetMediaSize, AssetTypeEnum, getAssetInfo } from '@immich/sdk';
|
import { AssetMediaSize, AssetTypeEnum, getAssetInfo } from '@immich/sdk';
|
||||||
import { IconButton, toastManager } from '@immich/ui';
|
import { ActionButton, IconButton, toastManager } from '@immich/ui';
|
||||||
import {
|
import {
|
||||||
mdiCardsOutline,
|
mdiCardsOutline,
|
||||||
mdiChevronDown,
|
mdiChevronDown,
|
||||||
@@ -328,6 +328,7 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => cancelMultiselect(assetInteraction)}
|
clearSelect={() => cancelMultiselect(assetInteraction)}
|
||||||
>
|
>
|
||||||
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<IconButton
|
<IconButton
|
||||||
shape="round"
|
shape="round"
|
||||||
@@ -338,7 +339,7 @@
|
|||||||
onclick={handleSelectAll}
|
onclick={handleSelectAll}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<AddToAlbum />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
|
|
||||||
<FavoriteAction removeFavorite={assetInteraction.isAllFavorite} />
|
<FavoriteAction removeFavorite={assetInteraction.isAllFavorite} />
|
||||||
|
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
|
||||||
import AlbumPickerModal from '$lib/modals/AlbumPickerModal.svelte';
|
|
||||||
import type { OnAddToAlbum } from '$lib/utils/actions';
|
|
||||||
import { addAssetsToAlbum, addAssetsToAlbums } from '$lib/utils/asset-utils';
|
|
||||||
import { getAssetControlContext } from '$lib/utils/context';
|
|
||||||
import { IconButton, modalManager } from '@immich/ui';
|
|
||||||
import { mdiImageAlbum, mdiPlus } from '@mdi/js';
|
|
||||||
import { t } from 'svelte-i18n';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
onAddToAlbum?: OnAddToAlbum;
|
|
||||||
menuItem?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { onAddToAlbum = () => {}, menuItem = false }: Props = $props();
|
|
||||||
|
|
||||||
const { getAssets } = getAssetControlContext();
|
|
||||||
|
|
||||||
const onClick = async () => {
|
|
||||||
const albums = await modalManager.show(AlbumPickerModal, {});
|
|
||||||
if (!albums || albums.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const assetIds = [...getAssets()].map(({ id }) => id);
|
|
||||||
if (albums.length === 1) {
|
|
||||||
const album = albums[0];
|
|
||||||
await addAssetsToAlbum(album.id, assetIds);
|
|
||||||
onAddToAlbum(assetIds, album.id);
|
|
||||||
} else {
|
|
||||||
await addAssetsToAlbums(
|
|
||||||
albums.map(({ id }) => id),
|
|
||||||
assetIds,
|
|
||||||
);
|
|
||||||
onAddToAlbum(assetIds, albums[0].id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if menuItem}
|
|
||||||
<MenuOption {onClick} text={$t('add_to_album')} icon={mdiImageAlbum} shortcut={{ key: 'l' }} />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if !menuItem}
|
|
||||||
<IconButton
|
|
||||||
shape="round"
|
|
||||||
color="secondary"
|
|
||||||
variant="ghost"
|
|
||||||
icon={mdiPlus}
|
|
||||||
aria-label={$t('add_to_album')}
|
|
||||||
onclick={onClick}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
@@ -6,7 +6,6 @@ export enum AssetAction {
|
|||||||
TRASH = 'trash',
|
TRASH = 'trash',
|
||||||
DELETE = 'delete',
|
DELETE = 'delete',
|
||||||
RESTORE = 'restore',
|
RESTORE = 'restore',
|
||||||
ADD_TO_ALBUM = 'add-to-album',
|
|
||||||
STACK = 'stack',
|
STACK = 'stack',
|
||||||
UNSTACK = 'unstack',
|
UNSTACK = 'unstack',
|
||||||
SET_STACK_PRIMARY_ASSET = 'set-stack-primary-asset',
|
SET_STACK_PRIMARY_ASSET = 'set-stack-primary-asset',
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export type Events = {
|
|||||||
AssetEditsApplied: [string];
|
AssetEditsApplied: [string];
|
||||||
AssetsTag: [string[]];
|
AssetsTag: [string[]];
|
||||||
|
|
||||||
AlbumAddAssets: [];
|
AlbumAddAssets: [{ assetIds: string[]; albumIds: string[] }];
|
||||||
AlbumUpdate: [AlbumResponseDto];
|
AlbumUpdate: [AlbumResponseDto];
|
||||||
AlbumDelete: [AlbumResponseDto];
|
AlbumDelete: [AlbumResponseDto];
|
||||||
AlbumShare: [];
|
AlbumShare: [];
|
||||||
|
|||||||
27
web/src/lib/modals/AssetAddToAlbumModal.svelte
Normal file
27
web/src/lib/modals/AssetAddToAlbumModal.svelte
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import AlbumPickerModal from '$lib/modals/AlbumPickerModal.svelte';
|
||||||
|
import { addAssetsToAlbums } from '$lib/services/album.service';
|
||||||
|
import { type AlbumResponseDto } from '@immich/sdk';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
assetIds: string[];
|
||||||
|
onClose: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { assetIds, onClose }: Props = $props();
|
||||||
|
|
||||||
|
const handleClose = async (albums?: AlbumResponseDto[]) => {
|
||||||
|
const albumIds = (albums ?? []).map(({ id }) => id);
|
||||||
|
if (albumIds.length === 0) {
|
||||||
|
onClose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const success = await addAssetsToAlbums(albumIds, assetIds, { notify: true });
|
||||||
|
if (success) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AlbumPickerModal onClose={handleClose} />
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import ToastAction from '$lib/components/ToastAction.svelte';
|
import ToastAction from '$lib/components/ToastAction.svelte';
|
||||||
import { AlbumPageViewMode } from '$lib/constants';
|
import { AlbumPageViewMode } from '$lib/constants';
|
||||||
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||||
import AlbumAddUsersModal from '$lib/modals/AlbumAddUsersModal.svelte';
|
import AlbumAddUsersModal from '$lib/modals/AlbumAddUsersModal.svelte';
|
||||||
@@ -11,17 +12,22 @@ import { user } from '$lib/stores/user.store';
|
|||||||
import { createAlbumAndRedirect } from '$lib/utils/album-utils';
|
import { createAlbumAndRedirect } from '$lib/utils/album-utils';
|
||||||
import { downloadArchive } from '$lib/utils/asset-utils';
|
import { downloadArchive } from '$lib/utils/asset-utils';
|
||||||
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||||
|
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { getFormatter } from '$lib/utils/i18n';
|
import { getFormatter } from '$lib/utils/i18n';
|
||||||
import {
|
import {
|
||||||
addAssetsToAlbum,
|
addAssetsToAlbum as addToAlbum,
|
||||||
|
addAssetsToAlbums as addToAlbums,
|
||||||
addUsersToAlbum,
|
addUsersToAlbum,
|
||||||
AlbumUserRole,
|
AlbumUserRole,
|
||||||
|
BulkIdErrorReason,
|
||||||
deleteAlbum,
|
deleteAlbum,
|
||||||
removeUserFromAlbum,
|
removeUserFromAlbum,
|
||||||
updateAlbumInfo,
|
updateAlbumInfo,
|
||||||
updateAlbumUser,
|
updateAlbumUser,
|
||||||
type AlbumResponseDto,
|
type AlbumResponseDto,
|
||||||
|
type AlbumsAddAssetsResponseDto,
|
||||||
|
type BulkIdResponseDto,
|
||||||
type UpdateAlbumDto,
|
type UpdateAlbumDto,
|
||||||
type UserResponseDto,
|
type UserResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
@@ -86,7 +92,12 @@ export const getAlbumAssetsActions = ($t: MessageFormatter, album: AlbumResponse
|
|||||||
color: 'primary',
|
color: 'primary',
|
||||||
icon: mdiPlusBoxOutline,
|
icon: mdiPlusBoxOutline,
|
||||||
$if: () => assets.length > 0,
|
$if: () => assets.length > 0,
|
||||||
onAction: () => addAssets(album, assets),
|
onAction: () =>
|
||||||
|
addAssetsToAlbums(
|
||||||
|
[album.id],
|
||||||
|
assets.map(({ id }) => id),
|
||||||
|
{ notify: true },
|
||||||
|
).then(() => undefined),
|
||||||
};
|
};
|
||||||
|
|
||||||
const Upload: ActionItem = {
|
const Upload: ActionItem = {
|
||||||
@@ -100,18 +111,73 @@ export const getAlbumAssetsActions = ($t: MessageFormatter, album: AlbumResponse
|
|||||||
return { AddAssets, Upload };
|
return { AddAssets, Upload };
|
||||||
};
|
};
|
||||||
|
|
||||||
const addAssets = async (album: AlbumResponseDto, assets: TimelineAsset[]) => {
|
export const addAssetsToAlbums = async (albumIds: string[], assetIds: string[], { notify }: { notify: boolean }) => {
|
||||||
const $t = await getFormatter();
|
const $t = await getFormatter();
|
||||||
const assetIds = assets.map(({ id }) => id);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const results = await addAssetsToAlbum({ id: album.id, bulkIdsDto: { ids: assetIds } });
|
if (albumIds.length === 1) {
|
||||||
|
const albumId = albumIds[0];
|
||||||
|
const results = await addToAlbum({ ...authManager.params, id: albumId, bulkIdsDto: { ids: assetIds } });
|
||||||
|
if (notify) {
|
||||||
|
notifyAddToAlbum($t, albumId, assetIds, results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const count = results.filter(({ success }) => success).length;
|
if (albumIds.length > 1) {
|
||||||
toastManager.success($t('assets_added_count', { values: { count } }));
|
const results = await addToAlbums({ ...authManager.params, albumsAddAssetsDto: { albumIds, assetIds } });
|
||||||
eventManager.emit('AlbumAddAssets');
|
if (notify) {
|
||||||
|
notifyAddToAlbums($t, albumIds, assetIds, results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eventManager.emit('AlbumAddAssets', { assetIds, albumIds });
|
||||||
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, $t('errors.error_adding_assets_to_album'));
|
handleError(error, $t('errors.error_adding_assets_to_album'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const notifyAddToAlbum = ($t: MessageFormatter, albumId: string, assetIds: string[], results: BulkIdResponseDto[]) => {
|
||||||
|
const successCount = results.filter(({ success }) => success).length;
|
||||||
|
const duplicateCount = results.filter(({ error }) => error === 'duplicate').length;
|
||||||
|
let description = $t('assets_cannot_be_added_to_album_count', { values: { count: assetIds.length } });
|
||||||
|
if (successCount > 0) {
|
||||||
|
description = $t('assets_added_to_album_count', { values: { count: successCount } });
|
||||||
|
} else if (duplicateCount > 0) {
|
||||||
|
description = $t('assets_were_part_of_album_count', { values: { count: duplicateCount } });
|
||||||
|
}
|
||||||
|
|
||||||
|
toastManager.custom(
|
||||||
|
{
|
||||||
|
component: ToastAction,
|
||||||
|
props: {
|
||||||
|
title: $t('info'),
|
||||||
|
color: 'primary',
|
||||||
|
description,
|
||||||
|
button: { text: $t('view_album'), color: 'primary', onClick: () => goto(Route.viewAlbum({ id: albumId })) },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ timeout: 5000 },
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const notifyAddToAlbums = (
|
||||||
|
$t: MessageFormatter,
|
||||||
|
albumIds: string[],
|
||||||
|
assetIds: string[],
|
||||||
|
results: AlbumsAddAssetsResponseDto,
|
||||||
|
) => {
|
||||||
|
if (results.error === BulkIdErrorReason.Duplicate) {
|
||||||
|
toastManager.info($t('assets_were_part_of_albums_count', { values: { count: assetIds.length } }));
|
||||||
|
} else if (results.error) {
|
||||||
|
toastManager.warning($t('assets_cannot_be_added_to_albums', { values: { count: assetIds.length } }));
|
||||||
|
} else {
|
||||||
|
toastManager.success(
|
||||||
|
$t('assets_added_to_albums_count', {
|
||||||
|
values: { albumTotal: albumIds.length, assetTotal: assetIds.length },
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ProjectionType } from '$lib/constants';
|
|||||||
import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte';
|
import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte';
|
||||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||||
|
import AssetAddToAlbumModal from '$lib/modals/AssetAddToAlbumModal.svelte';
|
||||||
import AssetTagModal from '$lib/modals/AssetTagModal.svelte';
|
import AssetTagModal from '$lib/modals/AssetTagModal.svelte';
|
||||||
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
||||||
import { user as authUser, preferences } from '$lib/stores/user.store';
|
import { user as authUser, preferences } from '$lib/stores/user.store';
|
||||||
@@ -42,6 +43,7 @@ import {
|
|||||||
mdiMagnifyPlusOutline,
|
mdiMagnifyPlusOutline,
|
||||||
mdiMotionPauseOutline,
|
mdiMotionPauseOutline,
|
||||||
mdiMotionPlayOutline,
|
mdiMotionPlayOutline,
|
||||||
|
mdiPlus,
|
||||||
mdiShareVariantOutline,
|
mdiShareVariantOutline,
|
||||||
mdiTagPlusOutline,
|
mdiTagPlusOutline,
|
||||||
mdiTune,
|
mdiTune,
|
||||||
@@ -59,6 +61,13 @@ export const getAssetBulkActions = ($t: MessageFormatter, ctx: AssetControlConte
|
|||||||
ctx.clearSelect();
|
ctx.clearSelect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const AddToAlbum: ActionItem = {
|
||||||
|
title: $t('add_to_album'),
|
||||||
|
icon: mdiPlus,
|
||||||
|
shortcuts: [{ key: 'l' }],
|
||||||
|
onAction: () => modalManager.show(AssetAddToAlbumModal, { assetIds }),
|
||||||
|
};
|
||||||
|
|
||||||
const RefreshFacesJob: ActionItem = {
|
const RefreshFacesJob: ActionItem = {
|
||||||
title: $t('refresh_faces'),
|
title: $t('refresh_faces'),
|
||||||
icon: mdiHeadSyncOutline,
|
icon: mdiHeadSyncOutline,
|
||||||
@@ -84,7 +93,7 @@ export const getAssetBulkActions = ($t: MessageFormatter, ctx: AssetControlConte
|
|||||||
$if: () => isAllVideos,
|
$if: () => isAllVideos,
|
||||||
};
|
};
|
||||||
|
|
||||||
return { RefreshFacesJob, RefreshMetadataJob, RegenerateThumbnailJob, TranscodeVideoJob };
|
return { AddToAlbum, RefreshFacesJob, RefreshMetadataJob, RegenerateThumbnailJob, TranscodeVideoJob };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) => {
|
export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) => {
|
||||||
@@ -161,6 +170,14 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
|
|||||||
shortcuts: [{ key: 'f' }],
|
shortcuts: [{ key: 'f' }],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const AddToAlbum: ActionItem = {
|
||||||
|
title: $t('add_to_album'),
|
||||||
|
icon: mdiPlus,
|
||||||
|
shortcuts: [{ key: 'l' }],
|
||||||
|
$if: () => asset.visibility !== AssetVisibility.Locked && !asset.isTrashed,
|
||||||
|
onAction: () => modalManager.show(AssetAddToAlbumModal, { assetIds: [asset.id] }),
|
||||||
|
};
|
||||||
|
|
||||||
const Offline: ActionItem = {
|
const Offline: ActionItem = {
|
||||||
title: $t('asset_offline'),
|
title: $t('asset_offline'),
|
||||||
icon: mdiAlertOutline,
|
icon: mdiAlertOutline,
|
||||||
@@ -260,6 +277,7 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
|
|||||||
Unfavorite,
|
Unfavorite,
|
||||||
PlayMotionPhoto,
|
PlayMotionPhoto,
|
||||||
StopMotionPhoto,
|
StopMotionPhoto,
|
||||||
|
AddToAlbum,
|
||||||
ZoomIn,
|
ZoomIn,
|
||||||
ZoomOut,
|
ZoomOut,
|
||||||
Copy,
|
Copy,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
|
import type { AssetControlContext } from '$lib/types';
|
||||||
import { AssetVisibility, type UserAdminResponseDto } from '@immich/sdk';
|
import { AssetVisibility, type UserAdminResponseDto } from '@immich/sdk';
|
||||||
import { SvelteMap, SvelteSet } from 'svelte/reactivity';
|
import { SvelteMap, SvelteSet } from 'svelte/reactivity';
|
||||||
import { fromStore } from 'svelte/store';
|
import { fromStore } from 'svelte/store';
|
||||||
@@ -22,6 +23,14 @@ export class AssetInteraction {
|
|||||||
private user = fromStore<UserAdminResponseDto | undefined>(user);
|
private user = fromStore<UserAdminResponseDto | undefined>(user);
|
||||||
private userId = $derived(this.user.current?.id);
|
private userId = $derived(this.user.current?.id);
|
||||||
|
|
||||||
|
asControlContext(): AssetControlContext {
|
||||||
|
return {
|
||||||
|
getOwnedAssets: () => this.selectedAssets.filter((asset) => asset.ownerId === this.userId),
|
||||||
|
getAssets: () => this.selectedAssets,
|
||||||
|
clearSelect: () => this.clearMultiselect(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
isAllTrashed = $derived(this.selectedAssets.every((asset) => asset.isTrashed));
|
isAllTrashed = $derived(this.selectedAssets.every((asset) => asset.isTrashed));
|
||||||
isAllArchived = $derived(this.selectedAssets.every((asset) => asset.visibility === AssetVisibility.Archive));
|
isAllArchived = $derived(this.selectedAssets.every((asset) => asset.visibility === AssetVisibility.Archive));
|
||||||
isAllFavorite = $derived(this.selectedAssets.every((asset) => asset.isFavorite));
|
isAllFavorite = $derived(this.selectedAssets.every((asset) => asset.isFavorite));
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { goto } from '$app/navigation';
|
|
||||||
import ToastAction from '$lib/components/ToastAction.svelte';
|
import ToastAction from '$lib/components/ToastAction.svelte';
|
||||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
import { downloadManager } from '$lib/managers/download-manager.svelte';
|
import { downloadManager } from '$lib/managers/download-manager.svelte';
|
||||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||||
import { Route } from '$lib/route';
|
|
||||||
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { preferences } from '$lib/stores/user.store';
|
import { preferences } from '$lib/stores/user.store';
|
||||||
import { downloadRequest, withError } from '$lib/utils';
|
import { downloadRequest, withError } from '$lib/utils';
|
||||||
@@ -13,10 +11,7 @@ import { getFormatter } from '$lib/utils/i18n';
|
|||||||
import { navigate } from '$lib/utils/navigation';
|
import { navigate } from '$lib/utils/navigation';
|
||||||
import { asQueryString } from '$lib/utils/shared-links';
|
import { asQueryString } from '$lib/utils/shared-links';
|
||||||
import {
|
import {
|
||||||
addAssetsToAlbum as addAssets,
|
|
||||||
addAssetsToAlbums as addToAlbums,
|
|
||||||
AssetVisibility,
|
AssetVisibility,
|
||||||
BulkIdErrorReason,
|
|
||||||
bulkTagAssets,
|
bulkTagAssets,
|
||||||
createStack,
|
createStack,
|
||||||
deleteAssets,
|
deleteAssets,
|
||||||
@@ -41,77 +36,6 @@ import { t } from 'svelte-i18n';
|
|||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
import { handleError } from './handle-error';
|
import { handleError } from './handle-error';
|
||||||
|
|
||||||
export const addAssetsToAlbum = async (albumId: string, assetIds: string[], showNotification = true) => {
|
|
||||||
const result = await addAssets({
|
|
||||||
...authManager.params,
|
|
||||||
id: albumId,
|
|
||||||
bulkIdsDto: {
|
|
||||||
ids: assetIds,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const count = result.filter(({ success }) => success).length;
|
|
||||||
const duplicateErrorCount = result.filter(({ error }) => error === 'duplicate').length;
|
|
||||||
const $t = get(t);
|
|
||||||
|
|
||||||
if (showNotification) {
|
|
||||||
let description = $t('assets_cannot_be_added_to_album_count', { values: { count: assetIds.length } });
|
|
||||||
if (count > 0) {
|
|
||||||
description = $t('assets_added_to_album_count', { values: { count } });
|
|
||||||
} else if (duplicateErrorCount > 0) {
|
|
||||||
description = $t('assets_were_part_of_album_count', { values: { count: duplicateErrorCount } });
|
|
||||||
}
|
|
||||||
toastManager.custom(
|
|
||||||
{
|
|
||||||
component: ToastAction,
|
|
||||||
props: {
|
|
||||||
title: $t('info'),
|
|
||||||
color: 'primary',
|
|
||||||
description,
|
|
||||||
button: {
|
|
||||||
text: $t('view_album'),
|
|
||||||
color: 'primary',
|
|
||||||
onClick() {
|
|
||||||
return goto(Route.viewAlbum({ id: albumId }));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ timeout: 5000 },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addAssetsToAlbums = async (albumIds: string[], assetIds: string[], showNotification = true) => {
|
|
||||||
const result = await addToAlbums({
|
|
||||||
...authManager.params,
|
|
||||||
albumsAddAssetsDto: {
|
|
||||||
albumIds,
|
|
||||||
assetIds,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!showNotification) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showNotification) {
|
|
||||||
const $t = get(t);
|
|
||||||
|
|
||||||
if (result.error === BulkIdErrorReason.Duplicate) {
|
|
||||||
toastManager.info($t('assets_were_part_of_albums_count', { values: { count: assetIds.length } }));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (result.error) {
|
|
||||||
toastManager.warning($t('assets_cannot_be_added_to_albums', { values: { count: assetIds.length } }));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
toastManager.success(
|
|
||||||
$t('assets_added_to_albums_count', { values: { albumTotal: albumIds.length, assetTotal: assetIds.length } }),
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const tagAssets = async ({
|
export const tagAssets = async ({
|
||||||
assetIds,
|
assetIds,
|
||||||
tagIds,
|
tagIds,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
import { uploadManager } from '$lib/managers/upload-manager.svelte';
|
import { uploadManager } from '$lib/managers/upload-manager.svelte';
|
||||||
|
import { addAssetsToAlbums } from '$lib/services/album.service';
|
||||||
import { uploadAssetsStore } from '$lib/stores/upload';
|
import { uploadAssetsStore } from '$lib/stores/upload';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
import { UploadState } from '$lib/types';
|
import { UploadState } from '$lib/types';
|
||||||
import { uploadRequest } from '$lib/utils';
|
import { uploadRequest } from '$lib/utils';
|
||||||
import { addAssetsToAlbum } from '$lib/utils/asset-utils';
|
|
||||||
import { ExecutorQueue } from '$lib/utils/executor-queue';
|
import { ExecutorQueue } from '$lib/utils/executor-queue';
|
||||||
import { asQueryString } from '$lib/utils/shared-links';
|
import { asQueryString } from '$lib/utils/shared-links';
|
||||||
import {
|
import {
|
||||||
@@ -213,7 +213,7 @@ async function fileUploader({
|
|||||||
|
|
||||||
if (albumId) {
|
if (albumId) {
|
||||||
uploadAssetsStore.updateItem(deviceAssetId, { message: $t('asset_adding_to_album') });
|
uploadAssetsStore.updateItem(deviceAssetId, { message: $t('asset_adding_to_album') });
|
||||||
await addAssetsToAlbum(albumId, [responseData.id], false);
|
await addAssetsToAlbums([albumId], [responseData.id], { notify: false });
|
||||||
uploadAssetsStore.updateItem(deviceAssetId, { message: $t('asset_added_to_album') });
|
uploadAssetsStore.updateItem(deviceAssetId, { message: $t('asset_added_to_album') });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
||||||
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
||||||
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
||||||
@@ -45,6 +44,7 @@
|
|||||||
handleDownloadAlbum,
|
handleDownloadAlbum,
|
||||||
} from '$lib/services/album.service';
|
} from '$lib/services/album.service';
|
||||||
import { getGlobalActions } from '$lib/services/app.service';
|
import { getGlobalActions } from '$lib/services/app.service';
|
||||||
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||||
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
||||||
@@ -438,9 +438,11 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => assetInteraction.clearMultiselect()}
|
clearSelect={() => assetInteraction.clearMultiselect()}
|
||||||
>
|
>
|
||||||
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {timelineManager} {assetInteraction} />
|
<SelectAllAssets {timelineManager} {assetInteraction} />
|
||||||
<AddToAlbum />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
{#if assetInteraction.isAllUserOwned}
|
{#if assetInteraction.isAllUserOwned}
|
||||||
<FavoriteAction
|
<FavoriteAction
|
||||||
removeFavorite={assetInteraction.isAllFavorite}
|
removeFavorite={assetInteraction.isAllFavorite}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
||||||
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
||||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||||
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
|
||||||
@@ -15,8 +14,10 @@
|
|||||||
|
|
||||||
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
|
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
|
||||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||||
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { AssetVisibility } from '@immich/sdk';
|
import { AssetVisibility } from '@immich/sdk';
|
||||||
|
import { ActionButton, CommandPaletteDefaultProvider } from '@immich/ui';
|
||||||
import { mdiDotsVertical } from '@mdi/js';
|
import { mdiDotsVertical } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
@@ -64,13 +65,15 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => assetInteraction.clearMultiselect()}
|
clearSelect={() => assetInteraction.clearMultiselect()}
|
||||||
>
|
>
|
||||||
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<ArchiveAction
|
<ArchiveAction
|
||||||
unarchive
|
unarchive
|
||||||
onArchive={(ids, visibility) => timelineManager.update(ids, (asset) => (asset.visibility = visibility))}
|
onArchive={(ids, visibility) => timelineManager.update(ids, (asset) => (asset.visibility = visibility))}
|
||||||
/>
|
/>
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {timelineManager} {assetInteraction} />
|
<SelectAllAssets {timelineManager} {assetInteraction} />
|
||||||
<AddToAlbum />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
<FavoriteAction
|
<FavoriteAction
|
||||||
removeFavorite={assetInteraction.isAllFavorite}
|
removeFavorite={assetInteraction.isAllFavorite}
|
||||||
onFavorite={(ids, isFavorite) => timelineManager.update(ids, (asset) => (asset.isFavorite = isFavorite))}
|
onFavorite={(ids, isFavorite) => timelineManager.update(ids, (asset) => (asset.isFavorite = isFavorite))}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
||||||
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
||||||
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
||||||
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
||||||
@@ -17,8 +16,10 @@
|
|||||||
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||||
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
||||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||||
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { preferences } from '$lib/stores/user.store';
|
import { preferences } from '$lib/stores/user.store';
|
||||||
|
import { ActionButton, CommandPaletteDefaultProvider } from '@immich/ui';
|
||||||
import { mdiDotsVertical } from '@mdi/js';
|
import { mdiDotsVertical } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
@@ -68,10 +69,12 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => assetInteraction.clearMultiselect()}
|
clearSelect={() => assetInteraction.clearMultiselect()}
|
||||||
>
|
>
|
||||||
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<FavoriteAction removeFavorite onFavorite={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
<FavoriteAction removeFavorite onFavorite={(assetIds) => timelineManager.removeAssets(assetIds)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {timelineManager} {assetInteraction} />
|
<SelectAllAssets {timelineManager} {assetInteraction} />
|
||||||
<AddToAlbum />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
||||||
<DownloadAction menuItem />
|
<DownloadAction menuItem />
|
||||||
<ChangeDate menuItem />
|
<ChangeDate menuItem />
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
import TreeItemThumbnails from '$lib/components/shared-components/tree/tree-item-thumbnails.svelte';
|
import TreeItemThumbnails from '$lib/components/shared-components/tree/tree-item-thumbnails.svelte';
|
||||||
import TreeItems from '$lib/components/shared-components/tree/tree-items.svelte';
|
import TreeItems from '$lib/components/shared-components/tree/tree-items.svelte';
|
||||||
import Sidebar from '$lib/components/sidebar/sidebar.svelte';
|
import Sidebar from '$lib/components/sidebar/sidebar.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
||||||
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
||||||
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
||||||
@@ -27,10 +26,9 @@
|
|||||||
import { foldersStore } from '$lib/stores/folders.svelte';
|
import { foldersStore } from '$lib/stores/folders.svelte';
|
||||||
import { preferences } from '$lib/stores/user.store';
|
import { preferences } from '$lib/stores/user.store';
|
||||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||||
import { getAssetControlContext } from '$lib/utils/context';
|
|
||||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||||
import { joinPaths } from '$lib/utils/tree-utils';
|
import { joinPaths } from '$lib/utils/tree-utils';
|
||||||
import { IconButton, Text } from '@immich/ui';
|
import { ActionButton, CommandPaletteDefaultProvider, IconButton, Text } from '@immich/ui';
|
||||||
import { mdiDotsVertical, mdiFolder, mdiFolderHome, mdiFolderOutline, mdiSelectAll } from '@mdi/js';
|
import { mdiDotsVertical, mdiFolder, mdiFolderHome, mdiFolderOutline, mdiSelectAll } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
@@ -119,8 +117,8 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => cancelMultiselect(assetInteraction)}
|
clearSelect={() => cancelMultiselect(assetInteraction)}
|
||||||
>
|
>
|
||||||
{@const Actions = getAssetBulkActions($t, getAssetControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<IconButton
|
<IconButton
|
||||||
shape="round"
|
shape="round"
|
||||||
@@ -130,7 +128,7 @@
|
|||||||
icon={mdiSelectAll}
|
icon={mdiSelectAll}
|
||||||
onclick={handleSelectAllAssets}
|
onclick={handleSelectAllAssets}
|
||||||
/>
|
/>
|
||||||
<AddToAlbum onAddToAlbum={() => cancelMultiselect(assetInteraction)} />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
<FavoriteAction
|
<FavoriteAction
|
||||||
removeFavorite={assetInteraction.isAllFavorite}
|
removeFavorite={assetInteraction.isAllFavorite}
|
||||||
onFavorite={function handleFavoriteUpdate(ids, isFavorite) {
|
onFavorite={function handleFavoriteUpdate(ids, isFavorite) {
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
|
||||||
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
|
||||||
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||||
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
||||||
import { Route } from '$lib/route';
|
import { Route } from '$lib/route';
|
||||||
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { AssetVisibility } from '@immich/sdk';
|
import { AssetVisibility } from '@immich/sdk';
|
||||||
|
import { ActionButton, CommandPaletteDefaultProvider } from '@immich/ui';
|
||||||
import { mdiArrowLeft } from '@mdi/js';
|
import { mdiArrowLeft } from '@mdi/js';
|
||||||
import type { PageData } from './$types';
|
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: PageData;
|
data: PageData;
|
||||||
@@ -44,8 +45,10 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => assetInteraction.clearMultiselect()}
|
clearSelect={() => assetInteraction.clearMultiselect()}
|
||||||
>
|
>
|
||||||
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<AddToAlbum />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
<DownloadAction />
|
<DownloadAction />
|
||||||
</AssetSelectControlBar>
|
</AssetSelectControlBar>
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
||||||
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
||||||
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
||||||
@@ -31,6 +30,7 @@
|
|||||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||||
import PersonMergeSuggestionModal from '$lib/modals/PersonMergeSuggestionModal.svelte';
|
import PersonMergeSuggestionModal from '$lib/modals/PersonMergeSuggestionModal.svelte';
|
||||||
import { Route } from '$lib/route';
|
import { Route } from '$lib/route';
|
||||||
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { getPersonActions } from '$lib/services/person.service';
|
import { getPersonActions } from '$lib/services/person.service';
|
||||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
@@ -40,7 +40,15 @@
|
|||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { isExternalUrl } from '$lib/utils/navigation';
|
import { isExternalUrl } from '$lib/utils/navigation';
|
||||||
import { AssetVisibility, searchPerson, updatePerson, type PersonResponseDto } from '@immich/sdk';
|
import { AssetVisibility, searchPerson, updatePerson, type PersonResponseDto } from '@immich/sdk';
|
||||||
import { ContextMenuButton, LoadingSpinner, modalManager, toastManager, type ActionItem } from '@immich/ui';
|
import {
|
||||||
|
ActionButton,
|
||||||
|
CommandPaletteDefaultProvider,
|
||||||
|
ContextMenuButton,
|
||||||
|
LoadingSpinner,
|
||||||
|
modalManager,
|
||||||
|
toastManager,
|
||||||
|
type ActionItem,
|
||||||
|
} from '@immich/ui';
|
||||||
import { mdiAccountBoxOutline, mdiAccountMultipleCheckOutline, mdiArrowLeft, mdiDotsVertical } from '@mdi/js';
|
import { mdiAccountBoxOutline, mdiAccountMultipleCheckOutline, mdiArrowLeft, mdiDotsVertical } from '@mdi/js';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
@@ -455,9 +463,11 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => assetInteraction.clearMultiselect()}
|
clearSelect={() => assetInteraction.clearMultiselect()}
|
||||||
>
|
>
|
||||||
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {timelineManager} {assetInteraction} />
|
<SelectAllAssets {timelineManager} {assetInteraction} />
|
||||||
<AddToAlbum />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
<FavoriteAction
|
<FavoriteAction
|
||||||
removeFavorite={assetInteraction.isAllFavorite}
|
removeFavorite={assetInteraction.isAllFavorite}
|
||||||
onFavorite={(ids, isFavorite) => timelineManager.update(ids, (asset) => (asset.isFavorite = isFavorite))}
|
onFavorite={(ids, isFavorite) => timelineManager.update(ids, (asset) => (asset.isFavorite = isFavorite))}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
||||||
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
||||||
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
||||||
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
||||||
@@ -36,12 +35,11 @@
|
|||||||
type OnLink,
|
type OnLink,
|
||||||
type OnUnlink,
|
type OnUnlink,
|
||||||
} from '$lib/utils/actions';
|
} from '$lib/utils/actions';
|
||||||
import { getAssetControlContext } from '$lib/utils/context';
|
|
||||||
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||||
import { getAltText } from '$lib/utils/thumbnail-util';
|
import { getAltText } from '$lib/utils/thumbnail-util';
|
||||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||||
import { AssetVisibility } from '@immich/sdk';
|
import { AssetVisibility } from '@immich/sdk';
|
||||||
import { ImageCarousel } from '@immich/ui';
|
import { ActionButton, CommandPaletteDefaultProvider, ImageCarousel } from '@immich/ui';
|
||||||
import { mdiDotsVertical } from '@mdi/js';
|
import { mdiDotsVertical } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@@ -130,11 +128,12 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => assetInteraction.clearMultiselect()}
|
clearSelect={() => assetInteraction.clearMultiselect()}
|
||||||
>
|
>
|
||||||
{@const Actions = getAssetBulkActions($t, getAssetControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
|
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {timelineManager} {assetInteraction} />
|
<SelectAllAssets {timelineManager} {assetInteraction} />
|
||||||
<AddToAlbum />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
|
|
||||||
{#if isAllUserOwned}
|
{#if isAllUserOwned}
|
||||||
<FavoriteAction
|
<FavoriteAction
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
import { afterNavigate, goto } from '$app/navigation';
|
import { afterNavigate, goto } from '$app/navigation';
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import ActionMenuItem from '$lib/components/ActionMenuItem.svelte';
|
import ActionMenuItem from '$lib/components/ActionMenuItem.svelte';
|
||||||
|
import OnEvents from '$lib/components/OnEvents.svelte';
|
||||||
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
|
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
|
||||||
import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
|
import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
||||||
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
||||||
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
import { preferences, user } from '$lib/stores/user.store';
|
import { preferences, user } from '$lib/stores/user.store';
|
||||||
import { handlePromiseError } from '$lib/utils';
|
import { handlePromiseError } from '$lib/utils';
|
||||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||||
import { getAssetControlContext } from '$lib/utils/context';
|
|
||||||
import { parseUtcDate } from '$lib/utils/date-time';
|
import { parseUtcDate } from '$lib/utils/date-time';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { isAlbumsRoute, isPeopleRoute } from '$lib/utils/navigation';
|
import { isAlbumsRoute, isPeopleRoute } from '$lib/utils/navigation';
|
||||||
@@ -43,7 +42,7 @@
|
|||||||
searchSmart,
|
searchSmart,
|
||||||
type SmartSearchDto,
|
type SmartSearchDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { Icon, IconButton, LoadingSpinner } from '@immich/ui';
|
import { ActionButton, CommandPaletteDefaultProvider, Icon, IconButton, LoadingSpinner } from '@immich/ui';
|
||||||
import { mdiArrowLeft, mdiDotsVertical, mdiImageOffOutline, mdiSelectAll } from '@mdi/js';
|
import { mdiArrowLeft, mdiDotsVertical, mdiImageOffOutline, mdiSelectAll } from '@mdi/js';
|
||||||
import { tick, untrack } from 'svelte';
|
import { tick, untrack } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
@@ -232,7 +231,7 @@
|
|||||||
return tagNames.join(', ');
|
return tagNames.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
const onAddToAlbum = (assetIds: string[]) => {
|
const onAlbumAddAssets = ({ assetIds }: { assetIds: string[] }) => {
|
||||||
cancelMultiselect(assetInteraction);
|
cancelMultiselect(assetInteraction);
|
||||||
|
|
||||||
if (terms.isNotInAlbum.toString() == 'true') {
|
if (terms.isNotInAlbum.toString() == 'true') {
|
||||||
@@ -248,6 +247,8 @@
|
|||||||
|
|
||||||
<svelte:window bind:scrollY />
|
<svelte:window bind:scrollY />
|
||||||
|
|
||||||
|
<OnEvents {onAlbumAddAssets} />
|
||||||
|
|
||||||
{#if terms}
|
{#if terms}
|
||||||
<section
|
<section
|
||||||
id="search-chips"
|
id="search-chips"
|
||||||
@@ -328,7 +329,8 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => cancelMultiselect(assetInteraction)}
|
clearSelect={() => cancelMultiselect(assetInteraction)}
|
||||||
>
|
>
|
||||||
{@const Actions = getAssetBulkActions($t, getAssetControlContext())}
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
|
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -339,7 +341,7 @@
|
|||||||
icon={mdiSelectAll}
|
icon={mdiSelectAll}
|
||||||
onclick={handleSelectAll}
|
onclick={handleSelectAll}
|
||||||
/>
|
/>
|
||||||
<AddToAlbum {onAddToAlbum} />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
{#if isAllUserOwned}
|
{#if isAllUserOwned}
|
||||||
<FavoriteAction
|
<FavoriteAction
|
||||||
removeFavorite={assetInteraction.isAllFavorite}
|
removeFavorite={assetInteraction.isAllFavorite}
|
||||||
@@ -354,7 +356,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
||||||
<AddToAlbum menuItem {onAddToAlbum} />
|
<ActionMenuItem action={Actions.AddToAlbum} />
|
||||||
<DownloadAction menuItem />
|
<DownloadAction menuItem />
|
||||||
<ChangeDate menuItem />
|
<ChangeDate menuItem />
|
||||||
<ChangeDescription menuItem />
|
<ChangeDescription menuItem />
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
import Sidebar from '$lib/components/sidebar/sidebar.svelte';
|
import Sidebar from '$lib/components/sidebar/sidebar.svelte';
|
||||||
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||||
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
||||||
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
|
|
||||||
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
|
||||||
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
|
||||||
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
|
||||||
@@ -25,12 +24,13 @@
|
|||||||
import SkipLink from '$lib/elements/SkipLink.svelte';
|
import SkipLink from '$lib/elements/SkipLink.svelte';
|
||||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||||
import { Route } from '$lib/route';
|
import { Route } from '$lib/route';
|
||||||
|
import { getAssetBulkActions } from '$lib/services/asset.service';
|
||||||
import { getTagActions } from '$lib/services/tag.service';
|
import { getTagActions } from '$lib/services/tag.service';
|
||||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { preferences, user } from '$lib/stores/user.store';
|
import { preferences, user } from '$lib/stores/user.store';
|
||||||
import { joinPaths, TreeNode } from '$lib/utils/tree-utils';
|
import { joinPaths, TreeNode } from '$lib/utils/tree-utils';
|
||||||
import { getAllTags, type TagResponseDto } from '@immich/sdk';
|
import { getAllTags, type TagResponseDto } from '@immich/sdk';
|
||||||
import { Text } from '@immich/ui';
|
import { ActionButton, CommandPaletteDefaultProvider, Text } from '@immich/ui';
|
||||||
import { mdiDotsVertical, mdiTag, mdiTagMultiple } from '@mdi/js';
|
import { mdiDotsVertical, mdiTag, mdiTagMultiple } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
@@ -120,9 +120,11 @@
|
|||||||
assets={assetInteraction.selectedAssets}
|
assets={assetInteraction.selectedAssets}
|
||||||
clearSelect={() => assetInteraction.clearMultiselect()}
|
clearSelect={() => assetInteraction.clearMultiselect()}
|
||||||
>
|
>
|
||||||
|
{@const Actions = getAssetBulkActions($t, assetInteraction.asControlContext())}
|
||||||
|
<CommandPaletteDefaultProvider name={$t('assets')} actions={Object.values(Actions)} />
|
||||||
<CreateSharedLink />
|
<CreateSharedLink />
|
||||||
<SelectAllAssets {timelineManager} {assetInteraction} />
|
<SelectAllAssets {timelineManager} {assetInteraction} />
|
||||||
<AddToAlbum />
|
<ActionButton action={Actions.AddToAlbum} />
|
||||||
<FavoriteAction
|
<FavoriteAction
|
||||||
removeFavorite={assetInteraction.isAllFavorite}
|
removeFavorite={assetInteraction.isAllFavorite}
|
||||||
onFavorite={(ids, isFavorite) => timelineManager.update(ids, (asset) => (asset.isFavorite = isFavorite))}
|
onFavorite={(ids, isFavorite) => timelineManager.update(ids, (asset) => (asset.isFavorite = isFavorite))}
|
||||||
|
|||||||
Reference in New Issue
Block a user