mirror of
https://github.com/immich-app/immich.git
synced 2026-02-28 01:29:04 +03:00
307 lines
9.6 KiB
TypeScript
307 lines
9.6 KiB
TypeScript
import { goto } from '$app/navigation';
|
|
import ToastAction from '$lib/components/ToastAction.svelte';
|
|
import { AlbumPageViewMode } from '$lib/constants';
|
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
|
import { eventManager } from '$lib/managers/event-manager.svelte';
|
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
|
import AlbumAddUsersModal from '$lib/modals/AlbumAddUsersModal.svelte';
|
|
import AlbumOptionsModal from '$lib/modals/AlbumOptionsModal.svelte';
|
|
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
|
import { Route } from '$lib/route';
|
|
import { user } from '$lib/stores/user.store';
|
|
import { createAlbumAndRedirect } from '$lib/utils/album-utils';
|
|
import { downloadArchive } from '$lib/utils/asset-utils';
|
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
|
|
|
import { handleError } from '$lib/utils/handle-error';
|
|
import { getFormatter } from '$lib/utils/i18n';
|
|
import {
|
|
addAssetsToAlbum as addToAlbum,
|
|
addAssetsToAlbums as addToAlbums,
|
|
addUsersToAlbum,
|
|
AlbumUserRole,
|
|
BulkIdErrorReason,
|
|
deleteAlbum,
|
|
removeUserFromAlbum,
|
|
updateAlbumInfo,
|
|
updateAlbumUser,
|
|
type AlbumResponseDto,
|
|
type AlbumsAddAssetsResponseDto,
|
|
type BulkIdResponseDto,
|
|
type UpdateAlbumDto,
|
|
type UserResponseDto,
|
|
} from '@immich/sdk';
|
|
import { modalManager, toastManager, type ActionItem } from '@immich/ui';
|
|
import { mdiArrowLeft, mdiLink, mdiPlus, mdiPlusBoxOutline, mdiShareVariantOutline, mdiUpload } from '@mdi/js';
|
|
import { type MessageFormatter } from 'svelte-i18n';
|
|
import { get } from 'svelte/store';
|
|
|
|
export const getAlbumsActions = ($t: MessageFormatter) => {
|
|
const Create: ActionItem = {
|
|
title: $t('create_album'),
|
|
icon: mdiPlusBoxOutline,
|
|
onAction: () => createAlbumAndRedirect(),
|
|
};
|
|
|
|
return { Create };
|
|
};
|
|
|
|
export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto, viewMode: AlbumPageViewMode) => {
|
|
const isOwned = get(user).id === album.ownerId;
|
|
|
|
const Share: ActionItem = {
|
|
title: $t('share'),
|
|
type: $t('command'),
|
|
icon: mdiShareVariantOutline,
|
|
$if: () => isOwned,
|
|
onAction: () => modalManager.show(AlbumOptionsModal, { album }),
|
|
};
|
|
|
|
const AddUsers: ActionItem = {
|
|
title: $t('invite_people'),
|
|
type: $t('command'),
|
|
icon: mdiPlus,
|
|
color: 'primary',
|
|
onAction: () => modalManager.show(AlbumAddUsersModal, { album }),
|
|
};
|
|
|
|
const CreateSharedLink: ActionItem = {
|
|
title: $t('create_link'),
|
|
type: $t('command'),
|
|
icon: mdiLink,
|
|
color: 'primary',
|
|
onAction: () => modalManager.show(SharedLinkCreateModal, { albumId: album.id }),
|
|
};
|
|
|
|
const Close: ActionItem = {
|
|
title: $t('go_back'),
|
|
type: $t('command'),
|
|
icon: mdiArrowLeft,
|
|
onAction: () => goto(Route.albums()),
|
|
$if: () => viewMode === AlbumPageViewMode.VIEW,
|
|
shortcuts: { key: 'Escape' },
|
|
};
|
|
|
|
return { Share, AddUsers, CreateSharedLink, Close };
|
|
};
|
|
|
|
export const getAlbumAssetsActions = ($t: MessageFormatter, album: AlbumResponseDto, assets: TimelineAsset[]) => {
|
|
const AddAssets: ActionItem = {
|
|
title: $t('add_assets'),
|
|
type: $t('command'),
|
|
color: 'primary',
|
|
icon: mdiPlusBoxOutline,
|
|
$if: () => assets.length > 0,
|
|
onAction: () =>
|
|
addAssetsToAlbums(
|
|
[album.id],
|
|
assets.map(({ id }) => id),
|
|
{ notify: true },
|
|
).then(() => undefined),
|
|
};
|
|
|
|
const Upload: ActionItem = {
|
|
title: $t('select_from_computer'),
|
|
description: $t('album_upload_assets'),
|
|
type: $t('command'),
|
|
icon: mdiUpload,
|
|
onAction: () => void openFileUploadDialog({ albumId: album.id }),
|
|
};
|
|
|
|
return { AddAssets, Upload };
|
|
};
|
|
|
|
export const addAssetsToAlbums = async (albumIds: string[], assetIds: string[], { notify }: { notify: boolean }) => {
|
|
const $t = await getFormatter();
|
|
|
|
try {
|
|
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);
|
|
}
|
|
}
|
|
|
|
if (albumIds.length > 1) {
|
|
const results = await addToAlbums({ ...authManager.params, albumsAddAssetsDto: { albumIds, assetIds } });
|
|
if (notify) {
|
|
notifyAddToAlbums($t, albumIds, assetIds, results);
|
|
}
|
|
}
|
|
|
|
eventManager.emit('AlbumAddAssets', { assetIds, albumIds });
|
|
return true;
|
|
} catch (error) {
|
|
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 },
|
|
}),
|
|
);
|
|
}
|
|
};
|
|
|
|
export const handleUpdateUserAlbumRole = async ({
|
|
albumId,
|
|
userId,
|
|
role,
|
|
}: {
|
|
albumId: string;
|
|
userId: string;
|
|
role: AlbumUserRole;
|
|
}) => {
|
|
const $t = await getFormatter();
|
|
|
|
try {
|
|
await updateAlbumUser({ id: albumId, userId, updateAlbumUserDto: { role } });
|
|
eventManager.emit('AlbumUserUpdate', { albumId, userId, role });
|
|
} catch (error) {
|
|
handleError(error, $t('errors.unable_to_change_album_user_role'));
|
|
}
|
|
};
|
|
|
|
export const handleAddUsersToAlbum = async (album: AlbumResponseDto, users: UserResponseDto[]) => {
|
|
const $t = await getFormatter();
|
|
|
|
try {
|
|
await addUsersToAlbum({ id: album.id, addUsersDto: { albumUsers: users.map(({ id }) => ({ userId: id })) } });
|
|
eventManager.emit('AlbumShare');
|
|
return true;
|
|
} catch (error) {
|
|
handleError(error, $t('errors.error_adding_users_to_album'));
|
|
}
|
|
};
|
|
|
|
export const handleRemoveUserFromAlbum = async (album: AlbumResponseDto, albumUser: UserResponseDto) => {
|
|
const $t = await getFormatter();
|
|
|
|
const confirmed = await modalManager.showDialog({
|
|
title: $t('album_remove_user'),
|
|
prompt: $t('album_remove_user_confirmation', { values: { user: albumUser.name } }),
|
|
confirmText: $t('remove_user'),
|
|
});
|
|
|
|
if (!confirmed) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await removeUserFromAlbum({ id: album.id, userId: albumUser.id });
|
|
eventManager.emit('AlbumUserDelete', { albumId: album.id, userId: albumUser.id });
|
|
} catch (error) {
|
|
handleError(error, $t('errors.unable_to_remove_album_users'));
|
|
}
|
|
};
|
|
|
|
export const handleUpdateAlbum = async ({ id }: { id: string }, dto: UpdateAlbumDto) => {
|
|
const $t = await getFormatter();
|
|
|
|
try {
|
|
const response = await updateAlbumInfo({ id, updateAlbumDto: dto });
|
|
eventManager.emit('AlbumUpdate', response);
|
|
toastManager.custom({
|
|
component: ToastAction,
|
|
props: {
|
|
color: 'primary',
|
|
title: $t('success'),
|
|
description: $t('album_info_updated'),
|
|
button: {
|
|
text: $t('view_album'),
|
|
color: 'primary',
|
|
onClick: () => goto(Route.viewAlbum({ id })),
|
|
},
|
|
},
|
|
});
|
|
|
|
return true;
|
|
} catch (error) {
|
|
handleError(error, $t('errors.unable_to_update_album_info'));
|
|
}
|
|
};
|
|
|
|
export const handleDeleteAlbum = async (album: AlbumResponseDto, options?: { prompt?: boolean; notify?: boolean }) => {
|
|
const $t = await getFormatter();
|
|
const { prompt = true, notify = true } = options ?? {};
|
|
|
|
if (prompt) {
|
|
const confirmation =
|
|
album.albumName.length > 0
|
|
? $t('album_delete_confirmation', { values: { album: album.albumName } })
|
|
: $t('unnamed_album_delete_confirmation');
|
|
const description = $t('album_delete_confirmation_description');
|
|
const success = await modalManager.showDialog({ prompt: `${confirmation} ${description}` });
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
try {
|
|
await deleteAlbum({ id: album.id });
|
|
eventManager.emit('AlbumDelete', album);
|
|
if (notify) {
|
|
toastManager.success();
|
|
}
|
|
return true;
|
|
} catch (error) {
|
|
handleError(error, $t('errors.unable_to_delete_album'));
|
|
return false;
|
|
}
|
|
};
|
|
|
|
export const handleDownloadAlbum = async (album: AlbumResponseDto) => {
|
|
await downloadArchive(`${album.albumName}.zip`, { albumId: album.id });
|
|
};
|
|
|
|
export const handleConfirmAlbumDelete = async (album: AlbumResponseDto) => {
|
|
const $t = await getFormatter();
|
|
const confirmation =
|
|
album.albumName.length > 0
|
|
? $t('album_delete_confirmation', { values: { album: album.albumName } })
|
|
: $t('unnamed_album_delete_confirmation');
|
|
|
|
const description = $t('album_delete_confirmation_description');
|
|
const prompt = `${confirmation} ${description}`;
|
|
|
|
return modalManager.showDialog({ prompt });
|
|
};
|