mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
@@ -1,16 +1,14 @@
|
||||
<script lang="ts">
|
||||
import type { ActionItem } from '$lib/types';
|
||||
import { IconButton, type IconButtonProps } from '@immich/ui';
|
||||
import { IconButton, type ActionItem } from '@immich/ui';
|
||||
|
||||
type Props = {
|
||||
action: ActionItem;
|
||||
};
|
||||
|
||||
const { action }: Props = $props();
|
||||
const { title, icon, color = 'secondary', props: other = {}, onSelect } = $derived(action);
|
||||
const onclick = (event: Event) => onSelect?.({ event, item: action });
|
||||
const { title, icon, color = 'secondary', onAction } = $derived(action);
|
||||
</script>
|
||||
|
||||
{#if action.$if?.() ?? true}
|
||||
<IconButton variant="ghost" {color} shape="round" {...other as IconButtonProps} {icon} aria-label={title} {onclick} />
|
||||
<IconButton variant="ghost" shape="round" {color} {icon} aria-label={title} onclick={() => onAction(action)} />
|
||||
{/if}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
<script lang="ts">
|
||||
import type { ActionItem } from '$lib/types';
|
||||
import { Button, type ButtonProps, Text } from '@immich/ui';
|
||||
import { type ActionItem, Button, Text } from '@immich/ui';
|
||||
|
||||
type Props = {
|
||||
action: ActionItem;
|
||||
title?: string;
|
||||
};
|
||||
|
||||
const { action }: Props = $props();
|
||||
const { title, icon, color = 'secondary', props: other = {}, onSelect } = $derived(action);
|
||||
const onclick = (event: Event) => onSelect?.({ event, item: action });
|
||||
const { action, title: titleAttr }: Props = $props();
|
||||
const { title, icon, color = 'secondary', onAction } = $derived(action);
|
||||
</script>
|
||||
|
||||
{#if action.$if?.() ?? true}
|
||||
<Button variant="ghost" size="small" {color} {...other as ButtonProps} leadingIcon={icon} {onclick}>
|
||||
<Button variant="ghost" size="small" {color} leadingIcon={icon} onclick={() => onAction(action)} title={titleAttr}>
|
||||
<Text class="hidden md:block">{title}</Text>
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
<script lang="ts">
|
||||
import type { ActionItem } from '$lib/types';
|
||||
import { IconButton, type IconButtonProps } from '@immich/ui';
|
||||
import { IconButton, type ActionItem } from '@immich/ui';
|
||||
|
||||
type Props = {
|
||||
action: ActionItem;
|
||||
};
|
||||
|
||||
const { action }: Props = $props();
|
||||
const { title, icon, props: other = {}, onSelect } = $derived(action);
|
||||
const onclick = (event: Event) => onSelect?.({ event, item: action });
|
||||
const { title, icon, onAction } = $derived(action);
|
||||
</script>
|
||||
|
||||
{#if action.$if?.() ?? true}
|
||||
<IconButton shape="round" color="primary" {...other as IconButtonProps} {icon} aria-label={title} {onclick} />
|
||||
<IconButton shape="round" color="primary" {icon} aria-label={title} onclick={() => onAction(action)} />
|
||||
{/if}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
.filter(Boolean)
|
||||
.join(' • ');
|
||||
|
||||
const SharedLinkActions = $derived(getSharedLinkActions($t, sharedLink));
|
||||
const { ViewQrCode, Copy } = $derived(getSharedLinkActions($t, sharedLink));
|
||||
</script>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
@@ -41,7 +41,7 @@
|
||||
<Text size="tiny" color="muted">{getShareProperties()}</Text>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<ActionButton action={SharedLinkActions.ViewQrCode} />
|
||||
<ActionButton action={SharedLinkActions.Copy} />
|
||||
<ActionButton action={ViewQrCode} />
|
||||
<ActionButton action={Copy} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
import NavigationBar from '$lib/components/shared-components/navigation-bar/navigation-bar.svelte';
|
||||
import AdminSidebar from '$lib/sidebars/AdminSidebar.svelte';
|
||||
import { sidebarStore } from '$lib/stores/sidebar.svelte';
|
||||
import { AppShell, AppShellHeader, AppShellSidebar, Scrollable } from '@immich/ui';
|
||||
import { AppShell, AppShellHeader, AppShellSidebar, Scrollable, type BreadcrumbItem } from '@immich/ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
breadcrumbs: BreadcrumbItem[];
|
||||
buttons?: Snippet;
|
||||
children?: Snippet;
|
||||
};
|
||||
|
||||
let { title, buttons, children }: Props = $props();
|
||||
let { breadcrumbs, buttons, children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<AppShell>
|
||||
@@ -24,7 +24,7 @@
|
||||
<AdminSidebar />
|
||||
</AppShellSidebar>
|
||||
|
||||
<TitleLayout {title} {buttons}>
|
||||
<TitleLayout {breadcrumbs} {buttons}>
|
||||
<Scrollable class="grow">
|
||||
<PageContent>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { Text } from '@immich/ui';
|
||||
import { Breadcrumbs, type BreadcrumbItem } from '@immich/ui';
|
||||
import { mdiSlashForward } from '@mdi/js';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
id?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
type Props = {
|
||||
breadcrumbs: BreadcrumbItem[];
|
||||
buttons?: Snippet;
|
||||
children?: Snippet;
|
||||
}
|
||||
};
|
||||
|
||||
let { id, title, description, buttons, children }: Props = $props();
|
||||
let { breadcrumbs, buttons, children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="flex h-16 w-full place-items-center justify-between border-b p-2">
|
||||
<div class="flex gap-1">
|
||||
<div class="font-medium outline-none" tabindex="-1" {id}>{title}</div>
|
||||
{#if description}
|
||||
<Text color="muted">{description}</Text>
|
||||
{/if}
|
||||
</div>
|
||||
<Breadcrumbs items={breadcrumbs} separator={mdiSlashForward} />
|
||||
{@render buttons?.()}
|
||||
</div>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { getSharedLinkActions } from '$lib/services/shared-link.service';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { SharedLinkType, type SharedLinkResponseDto } from '@immich/sdk';
|
||||
import { ContextMenuButton, MenuItemType } from '@immich/ui';
|
||||
import { DateTime, type ToRelativeUnit } from 'luxon';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
@@ -31,7 +32,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
const SharedLinkActions = $derived(getSharedLinkActions($t, sharedLink));
|
||||
const { Edit, Copy, Delete } = $derived(getSharedLinkActions($t, sharedLink));
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -95,13 +96,17 @@
|
||||
</svelte:element>
|
||||
<div class="flex flex-auto flex-col place-content-center place-items-end text-end ms-4">
|
||||
<div class="sm:flex hidden">
|
||||
<ActionButton action={SharedLinkActions.Edit} />
|
||||
<ActionButton action={SharedLinkActions.Copy} />
|
||||
<ActionButton action={SharedLinkActions.Delete} />
|
||||
<ActionButton action={Edit} />
|
||||
<ActionButton action={Copy} />
|
||||
<ActionButton action={Delete} />
|
||||
</div>
|
||||
|
||||
<div class="sm:hidden">
|
||||
<ActionButton action={SharedLinkActions.ContextMenu} />
|
||||
<ContextMenuButton
|
||||
aria-label={$t('shared_link_options')}
|
||||
position="top-right"
|
||||
items={[Edit, Copy, MenuItemType.Divider, Delete]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,6 @@ import LibraryFolderAddModal from '$lib/modals/LibraryFolderAddModal.svelte';
|
||||
import LibraryFolderEditModal from '$lib/modals/LibraryFolderEditModal.svelte';
|
||||
import LibraryRenameModal from '$lib/modals/LibraryRenameModal.svelte';
|
||||
import LibraryUserPickerModal from '$lib/modals/LibraryUserPickerModal.svelte';
|
||||
import type { ActionItem } from '$lib/types';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import {
|
||||
@@ -20,7 +19,7 @@ import {
|
||||
updateLibrary,
|
||||
type LibraryResponseDto,
|
||||
} from '@immich/sdk';
|
||||
import { modalManager, toastManager } from '@immich/ui';
|
||||
import { modalManager, toastManager, type ActionItem } from '@immich/ui';
|
||||
import { mdiPencilOutline, mdiPlusBoxOutline, mdiSync, mdiTrashCanOutline } from '@mdi/js';
|
||||
import type { MessageFormatter } from 'svelte-i18n';
|
||||
|
||||
@@ -28,13 +27,13 @@ export const getLibrariesActions = ($t: MessageFormatter) => {
|
||||
const ScanAll: ActionItem = {
|
||||
title: $t('scan_all_libraries'),
|
||||
icon: mdiSync,
|
||||
onSelect: () => void handleScanAllLibraries(),
|
||||
onAction: () => void handleScanAllLibraries(),
|
||||
};
|
||||
|
||||
const Create: ActionItem = {
|
||||
title: $t('create_library'),
|
||||
icon: mdiPlusBoxOutline,
|
||||
onSelect: () => void handleCreateLibrary(),
|
||||
onAction: () => void handleCreateLibrary(),
|
||||
};
|
||||
|
||||
return { ScanAll, Create };
|
||||
@@ -44,32 +43,32 @@ export const getLibraryActions = ($t: MessageFormatter, library: LibraryResponse
|
||||
const Rename: ActionItem = {
|
||||
icon: mdiPencilOutline,
|
||||
title: $t('rename'),
|
||||
onSelect: () => void modalManager.show(LibraryRenameModal, { library }),
|
||||
onAction: () => void modalManager.show(LibraryRenameModal, { library }),
|
||||
};
|
||||
|
||||
const Delete: ActionItem = {
|
||||
icon: mdiTrashCanOutline,
|
||||
title: $t('delete'),
|
||||
color: 'danger',
|
||||
onSelect: () => void handleDeleteLibrary(library),
|
||||
onAction: () => void handleDeleteLibrary(library),
|
||||
};
|
||||
|
||||
const AddFolder: ActionItem = {
|
||||
icon: mdiPlusBoxOutline,
|
||||
title: $t('add'),
|
||||
onSelect: () => void modalManager.show(LibraryFolderAddModal, { library }),
|
||||
onAction: () => void modalManager.show(LibraryFolderAddModal, { library }),
|
||||
};
|
||||
|
||||
const AddExclusionPattern: ActionItem = {
|
||||
icon: mdiPlusBoxOutline,
|
||||
title: $t('add'),
|
||||
onSelect: () => void modalManager.show(LibraryExclusionPatternAddModal, { library }),
|
||||
onAction: () => void modalManager.show(LibraryExclusionPatternAddModal, { library }),
|
||||
};
|
||||
|
||||
const Scan: ActionItem = {
|
||||
icon: mdiSync,
|
||||
title: $t('scan_library'),
|
||||
onSelect: () => void handleScanLibrary(library),
|
||||
onAction: () => void handleScanLibrary(library),
|
||||
};
|
||||
|
||||
return { Rename, Delete, AddFolder, AddExclusionPattern, Scan };
|
||||
@@ -79,13 +78,13 @@ export const getLibraryFolderActions = ($t: MessageFormatter, library: LibraryRe
|
||||
const Edit: ActionItem = {
|
||||
icon: mdiPencilOutline,
|
||||
title: $t('edit'),
|
||||
onSelect: () => void modalManager.show(LibraryFolderEditModal, { folder, library }),
|
||||
onAction: () => void modalManager.show(LibraryFolderEditModal, { folder, library }),
|
||||
};
|
||||
|
||||
const Delete: ActionItem = {
|
||||
icon: mdiTrashCanOutline,
|
||||
title: $t('delete'),
|
||||
onSelect: () => void handleDeleteLibraryFolder(library, folder),
|
||||
onAction: () => void handleDeleteLibraryFolder(library, folder),
|
||||
};
|
||||
|
||||
return { Edit, Delete };
|
||||
@@ -99,13 +98,13 @@ export const getLibraryExclusionPatternActions = (
|
||||
const Edit: ActionItem = {
|
||||
icon: mdiPencilOutline,
|
||||
title: $t('edit'),
|
||||
onSelect: () => void modalManager.show(LibraryExclusionPatternEditModal, { exclusionPattern, library }),
|
||||
onAction: () => void modalManager.show(LibraryExclusionPatternEditModal, { exclusionPattern, library }),
|
||||
};
|
||||
|
||||
const Delete: ActionItem = {
|
||||
icon: mdiTrashCanOutline,
|
||||
title: $t('delete'),
|
||||
onSelect: () => void handleDeleteExclusionPattern(library, exclusionPattern),
|
||||
onAction: () => void handleDeleteExclusionPattern(library, exclusionPattern),
|
||||
};
|
||||
|
||||
return { Edit, Delete };
|
||||
|
||||
@@ -16,48 +16,37 @@ import {
|
||||
type SharedLinkEditDto,
|
||||
type SharedLinkResponseDto,
|
||||
} from '@immich/sdk';
|
||||
import { MenuItemType, menuManager, modalManager, toastManager, type MenuItem } from '@immich/ui';
|
||||
import { mdiCircleEditOutline, mdiContentCopy, mdiDelete, mdiDotsVertical, mdiQrcode } from '@mdi/js';
|
||||
import { modalManager, toastManager, type ActionItem } from '@immich/ui';
|
||||
import { mdiCircleEditOutline, mdiContentCopy, mdiDelete, mdiQrcode } from '@mdi/js';
|
||||
import type { MessageFormatter } from 'svelte-i18n';
|
||||
|
||||
export const getSharedLinkActions = ($t: MessageFormatter, sharedLink: SharedLinkResponseDto) => {
|
||||
const Edit: MenuItem = {
|
||||
const Edit: ActionItem = {
|
||||
title: $t('edit_link'),
|
||||
icon: mdiCircleEditOutline,
|
||||
onSelect: () => void goto(`${AppRoute.SHARED_LINKS}/${sharedLink.id}`),
|
||||
onAction: () => void goto(`${AppRoute.SHARED_LINKS}/${sharedLink.id}`),
|
||||
};
|
||||
|
||||
const Delete: MenuItem = {
|
||||
const Delete: ActionItem = {
|
||||
title: $t('delete_link'),
|
||||
icon: mdiDelete,
|
||||
color: 'danger',
|
||||
onSelect: () => void handleDeleteSharedLink(sharedLink),
|
||||
onAction: () => void handleDeleteSharedLink(sharedLink),
|
||||
};
|
||||
|
||||
const Copy: MenuItem = {
|
||||
const Copy: ActionItem = {
|
||||
title: $t('copy_link'),
|
||||
icon: mdiContentCopy,
|
||||
onSelect: () => void copyToClipboard(asUrl(sharedLink)),
|
||||
onAction: () => void copyToClipboard(asUrl(sharedLink)),
|
||||
};
|
||||
|
||||
const ViewQrCode: MenuItem = {
|
||||
const ViewQrCode: ActionItem = {
|
||||
title: $t('view_qr_code'),
|
||||
icon: mdiQrcode,
|
||||
onSelect: () => void handleShowSharedLinkQrCode(sharedLink),
|
||||
onAction: () => void handleShowSharedLinkQrCode(sharedLink),
|
||||
};
|
||||
|
||||
const ContextMenu: MenuItem = {
|
||||
title: $t('shared_link_options'),
|
||||
icon: mdiDotsVertical,
|
||||
onSelect: ({ event }) =>
|
||||
void menuManager.show({
|
||||
target: event.currentTarget as HTMLElement,
|
||||
position: 'top-right',
|
||||
items: [Edit, Copy, MenuItemType.Divider, Delete],
|
||||
}),
|
||||
};
|
||||
|
||||
return { Edit, Delete, Copy, ViewQrCode, ContextMenu };
|
||||
return { Edit, Delete, Copy, ViewQrCode };
|
||||
};
|
||||
|
||||
const asUrl = (sharedLink: SharedLinkResponseDto) => {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { downloadManager } from '$lib/managers/download-manager.svelte';
|
||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import type { ActionItem } from '$lib/types';
|
||||
import { copyToClipboard } from '$lib/utils';
|
||||
import { downloadBlob } from '$lib/utils/asset-utils';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import { getConfig, updateConfig, type ServerFeaturesDto, type SystemConfigDto } from '@immich/sdk';
|
||||
import { toastManager } from '@immich/ui';
|
||||
import { toastManager, type ActionItem } from '@immich/ui';
|
||||
import { mdiContentCopy, mdiDownload, mdiUpload } from '@mdi/js';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import type { MessageFormatter } from 'svelte-i18n';
|
||||
@@ -19,20 +18,20 @@ export const getSystemConfigActions = (
|
||||
const CopyToClipboard: ActionItem = {
|
||||
title: $t('copy_to_clipboard'),
|
||||
icon: mdiContentCopy,
|
||||
onSelect: () => void handleCopyToClipboard(config),
|
||||
onAction: () => void handleCopyToClipboard(config),
|
||||
};
|
||||
|
||||
const Download: ActionItem = {
|
||||
title: $t('export_as_json'),
|
||||
icon: mdiDownload,
|
||||
onSelect: () => handleDownloadConfig(config),
|
||||
onAction: () => handleDownloadConfig(config),
|
||||
};
|
||||
|
||||
const Upload: ActionItem = {
|
||||
title: $t('import_from_json'),
|
||||
icon: mdiUpload,
|
||||
$if: () => !featureFlags.configFile,
|
||||
onSelect: () => handleUploadConfig(),
|
||||
onAction: () => handleUploadConfig(),
|
||||
};
|
||||
|
||||
return { CopyToClipboard, Download, Upload };
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
|
||||
import PasswordResetSuccessModal from '$lib/modals/PasswordResetSuccessModal.svelte';
|
||||
import UserCreateModal from '$lib/modals/UserCreateModal.svelte';
|
||||
import UserDeleteConfirmModal from '$lib/modals/UserDeleteConfirmModal.svelte';
|
||||
import UserEditModal from '$lib/modals/UserEditModal.svelte';
|
||||
import UserRestoreConfirmModal from '$lib/modals/UserRestoreConfirmModal.svelte';
|
||||
import { user as authUser } from '$lib/stores/user.store';
|
||||
import type { ActionItem } from '$lib/types';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import {
|
||||
@@ -21,45 +19,33 @@ import {
|
||||
type UserAdminResponseDto,
|
||||
type UserAdminUpdateDto,
|
||||
} from '@immich/sdk';
|
||||
import { MenuItemType, menuManager, modalManager, toastManager } from '@immich/ui';
|
||||
import { modalManager, toastManager, type ActionItem } from '@immich/ui';
|
||||
import {
|
||||
mdiDeleteRestore,
|
||||
mdiDotsVertical,
|
||||
mdiEyeOutline,
|
||||
mdiLockReset,
|
||||
mdiLockSmart,
|
||||
mdiPencilOutline,
|
||||
mdiPlusBoxOutline,
|
||||
mdiTrashCanOutline,
|
||||
} from '@mdi/js';
|
||||
import { DateTime } from 'luxon';
|
||||
import type { MessageFormatter } from 'svelte-i18n';
|
||||
import { get } from 'svelte/store';
|
||||
|
||||
const getDeleteDate = (deletedAt: string): Date =>
|
||||
DateTime.fromISO(deletedAt).plus({ days: serverConfigManager.value.userDeleteDelay }).toJSDate();
|
||||
|
||||
export const getUserAdminsActions = ($t: MessageFormatter) => {
|
||||
const Create: ActionItem = {
|
||||
title: $t('create_user'),
|
||||
icon: mdiPlusBoxOutline,
|
||||
onSelect: () => void modalManager.show(UserCreateModal, {}),
|
||||
onAction: () => void modalManager.show(UserCreateModal, {}),
|
||||
};
|
||||
|
||||
return { Create };
|
||||
};
|
||||
|
||||
export const getUserAdminActions = ($t: MessageFormatter, user: UserAdminResponseDto) => {
|
||||
const View: ActionItem = {
|
||||
icon: mdiEyeOutline,
|
||||
title: $t('view'),
|
||||
onSelect: () => void goto(`/admin/users/${user.id}`),
|
||||
};
|
||||
|
||||
const Update: ActionItem = {
|
||||
icon: mdiPencilOutline,
|
||||
title: $t('edit'),
|
||||
onSelect: () => void modalManager.show(UserEditModal, { user }),
|
||||
onAction: () => void modalManager.show(UserEditModal, { user }),
|
||||
};
|
||||
|
||||
const Delete: ActionItem = {
|
||||
@@ -67,7 +53,7 @@ export const getUserAdminActions = ($t: MessageFormatter, user: UserAdminRespons
|
||||
title: $t('delete'),
|
||||
color: 'danger',
|
||||
$if: () => get(authUser).id !== user.id && !user.deletedAt,
|
||||
onSelect: () => void modalManager.show(UserDeleteConfirmModal, { user }),
|
||||
onAction: () => void modalManager.show(UserDeleteConfirmModal, { user }),
|
||||
};
|
||||
|
||||
const Restore: ActionItem = {
|
||||
@@ -75,47 +61,23 @@ export const getUserAdminActions = ($t: MessageFormatter, user: UserAdminRespons
|
||||
title: $t('restore'),
|
||||
color: 'primary',
|
||||
$if: () => !!user.deletedAt && user.status === UserStatus.Deleted,
|
||||
onSelect: () => void modalManager.show(UserRestoreConfirmModal, { user }),
|
||||
props: {
|
||||
title: $t('admin.user_restore_scheduled_removal', {
|
||||
values: { date: getDeleteDate(user.deletedAt!) },
|
||||
}),
|
||||
},
|
||||
onAction: () => void modalManager.show(UserRestoreConfirmModal, { user }),
|
||||
};
|
||||
|
||||
const ResetPassword: ActionItem = {
|
||||
icon: mdiLockReset,
|
||||
title: $t('reset_password'),
|
||||
$if: () => get(authUser).id !== user.id,
|
||||
onSelect: () => void handleResetPasswordUserAdmin(user),
|
||||
onAction: () => void handleResetPasswordUserAdmin(user),
|
||||
};
|
||||
|
||||
const ResetPinCode: ActionItem = {
|
||||
icon: mdiLockSmart,
|
||||
title: $t('reset_pin_code'),
|
||||
onSelect: () => void handleResetPinCodeUserAdmin(user),
|
||||
onAction: () => void handleResetPinCodeUserAdmin(user),
|
||||
};
|
||||
|
||||
const ContextMenu: ActionItem = {
|
||||
icon: mdiDotsVertical,
|
||||
title: $t('actions'),
|
||||
onSelect: ({ event }) =>
|
||||
void menuManager.show({
|
||||
target: event.currentTarget as HTMLElement,
|
||||
position: 'top-right',
|
||||
items: [
|
||||
View,
|
||||
Update,
|
||||
ResetPassword,
|
||||
ResetPinCode,
|
||||
get(authUser).id === user.id ? undefined : MenuItemType.Divider,
|
||||
Restore,
|
||||
Delete,
|
||||
].filter(Boolean),
|
||||
}),
|
||||
};
|
||||
|
||||
return { View, Update, Delete, Restore, ResetPassword, ResetPinCode, ContextMenu };
|
||||
return { Update, Delete, Restore, ResetPassword, ResetPinCode };
|
||||
};
|
||||
|
||||
export const handleCreateUserAdmin = async (dto: UserAdminCreateDto) => {
|
||||
@@ -172,6 +134,10 @@ export const handleRestoreUserAdmin = async (user: UserAdminResponseDto) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const handleNavigateUserAdmin = async (user: UserAdminResponseDto) => {
|
||||
await goto(`/admin/users/${user.id}`);
|
||||
};
|
||||
|
||||
// TODO move password reset server-side
|
||||
const generatePassword = (length: number = 16) => {
|
||||
let generatedPassword = '';
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import type { ServerVersionResponseDto } from '@immich/sdk';
|
||||
import type { MenuItem } from '@immich/ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
|
||||
export type ActionItem = MenuItem & { props?: Omit<HTMLAttributes<HTMLElement>, 'color'> };
|
||||
|
||||
export interface ReleaseEvent {
|
||||
isAvailable: boolean;
|
||||
|
||||
Reference in New Issue
Block a user