mirror of
https://github.com/immich-app/immich.git
synced 2026-03-19 00:28:35 -07:00
Compare commits
3 Commits
main
...
feat/deepl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4865938f55 | ||
|
|
3b20bf4a6a | ||
|
|
096927a835 |
@@ -10,7 +10,7 @@
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { oauth } from '$lib/utils';
|
||||
import { type ApiKeyResponseDto, type SessionResponseDto } from '@immich/sdk';
|
||||
import { getApiKeys, type ApiKeyResponseDto, type SessionResponseDto } from '@immich/sdk';
|
||||
import {
|
||||
mdiAccountGroupOutline,
|
||||
mdiAccountOutline,
|
||||
@@ -26,6 +26,7 @@
|
||||
mdiServerOutline,
|
||||
mdiTwoFactorAuthentication,
|
||||
} from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import SettingAccordionState from '../shared-components/settings/setting-accordion-state.svelte';
|
||||
import SettingAccordion from '../shared-components/settings/setting-accordion.svelte';
|
||||
@@ -38,11 +39,16 @@
|
||||
import UserProfileSettings from './user-profile-settings.svelte';
|
||||
|
||||
interface Props {
|
||||
keys?: ApiKeyResponseDto[];
|
||||
sessions?: SessionResponseDto[];
|
||||
}
|
||||
|
||||
let { keys = $bindable([]), sessions = $bindable([]) }: Props = $props();
|
||||
let { sessions = $bindable([]) }: Props = $props();
|
||||
|
||||
let keys: ApiKeyResponseDto[] = $state([]);
|
||||
|
||||
onMount(async () => {
|
||||
keys = await getApiKeys();
|
||||
});
|
||||
|
||||
let oauthOpen =
|
||||
oauth.isCallback(globalThis.location) ||
|
||||
|
||||
@@ -62,6 +62,7 @@ export enum SessionStorageKey {
|
||||
|
||||
// TODO split into user settings vs system settings
|
||||
export enum OpenQueryParam {
|
||||
API_KEYS = 'api-keys',
|
||||
OAUTH = 'oauth',
|
||||
JOB = 'job',
|
||||
STORAGE_TEMPLATE = 'storage-template',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const Route = {
|
||||
|
||||
// settings
|
||||
userSettings: (params?: { isOpen?: OpenQueryParam }) => '/user-settings' + asQueryString(params),
|
||||
newApiKey: (params?: { permissions?: string }) => '/user-settings/new-api-key' + asQueryString(params),
|
||||
|
||||
// system
|
||||
systemSettings: (params?: { isOpen?: OpenQueryParam }) => '/admin/system-settings' + asQueryString(params),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import ApiKeyCreateModal from '$lib/modals/ApiKeyCreateModal.svelte';
|
||||
import ApiKeyUpdateModal from '$lib/modals/ApiKeyUpdateModal.svelte';
|
||||
import { Route } from '$lib/route';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import {
|
||||
@@ -19,7 +20,7 @@ export const getApiKeysActions = ($t: MessageFormatter) => {
|
||||
const Create: ActionItem = {
|
||||
title: $t('new_api_key'),
|
||||
icon: mdiPlus,
|
||||
onAction: () => modalManager.show(ApiKeyCreateModal, {}),
|
||||
onAction: () => goto(Route.newApiKey()),
|
||||
};
|
||||
|
||||
return { Create };
|
||||
|
||||
23
web/src/routes/(user)/user-settings/+layout.svelte
Normal file
23
web/src/routes/(user)/user-settings/+layout.svelte
Normal file
@@ -0,0 +1,23 @@
|
||||
<script lang="ts">
|
||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||
import { getKeyboardActions } from '$lib/services/keyboard.service';
|
||||
import { Container } from '@immich/ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
type Props = {
|
||||
children?: Snippet;
|
||||
data: PageData;
|
||||
};
|
||||
|
||||
let { children, data }: Props = $props();
|
||||
|
||||
const { KeyboardShortcuts } = $derived(getKeyboardActions($t));
|
||||
</script>
|
||||
|
||||
<UserPageLayout title={data.meta.title} actions={[KeyboardShortcuts]}>
|
||||
<Container size="medium" center>
|
||||
{@render children?.()}
|
||||
</Container>
|
||||
</UserPageLayout>
|
||||
15
web/src/routes/(user)/user-settings/+layout.ts
Normal file
15
web/src/routes/(user)/user-settings/+layout.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { authenticate } from '$lib/utils/auth';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load = (async ({ url }) => {
|
||||
await authenticate(url);
|
||||
|
||||
const $t = await getFormatter();
|
||||
|
||||
return {
|
||||
meta: {
|
||||
title: $t('settings'),
|
||||
},
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
@@ -1,9 +1,5 @@
|
||||
<script lang="ts">
|
||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||
import UserSettingsList from '$lib/components/user-settings-page/user-settings-list.svelte';
|
||||
import { getKeyboardActions } from '$lib/services/keyboard.service';
|
||||
import { Container } from '@immich/ui';
|
||||
import { t } from 'svelte-i18n';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
type Props = {
|
||||
@@ -11,12 +7,6 @@
|
||||
};
|
||||
|
||||
let { data }: Props = $props();
|
||||
|
||||
const { KeyboardShortcuts } = $derived(getKeyboardActions($t));
|
||||
</script>
|
||||
|
||||
<UserPageLayout title={data.meta.title} actions={[KeyboardShortcuts]}>
|
||||
<Container size="medium" center>
|
||||
<UserSettingsList keys={data.keys} sessions={data.sessions} />
|
||||
</Container>
|
||||
</UserPageLayout>
|
||||
<UserSettingsList sessions={data.sessions} />
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
import { authenticate } from '$lib/utils/auth';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import { getApiKeys, getSessions } from '@immich/sdk';
|
||||
import { getSessions } from '@immich/sdk';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load = (async ({ url }) => {
|
||||
await authenticate(url);
|
||||
|
||||
const keys = await getApiKeys();
|
||||
const sessions = await getSessions();
|
||||
const $t = await getFormatter();
|
||||
|
||||
return {
|
||||
keys,
|
||||
sessions,
|
||||
meta: {
|
||||
title: $t('settings'),
|
||||
},
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
|
||||
55
web/src/routes/(user)/user-settings/new-api-key/+page.svelte
Normal file
55
web/src/routes/(user)/user-settings/new-api-key/+page.svelte
Normal file
@@ -0,0 +1,55 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
import ApiKeyPermissionsPicker from '$lib/components/ApiKeyPermissionsPicker.svelte';
|
||||
import { OpenQueryParam } from '$lib/constants';
|
||||
import ApiKeySecretModal from '$lib/modals/ApiKeySecretModal.svelte';
|
||||
import { Route } from '$lib/route';
|
||||
import { handleCreateApiKey } from '$lib/services/api-key.service';
|
||||
import { Permission } from '@immich/sdk';
|
||||
import { Field, FormModal, Input } from '@immich/ui';
|
||||
import { mdiKeyVariant } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
const validPermissions = new Set(Object.values(Permission));
|
||||
const queryPermissions = (page.url.searchParams.get('permissions') || '')
|
||||
.split(' ')
|
||||
.filter((x) => x !== '')
|
||||
.map((value) => {
|
||||
if (value === Permission.All || !validPermissions.has(value as Permission)) {
|
||||
console.warn(`Invalid permission value: ${value}`);
|
||||
}
|
||||
return value as Permission;
|
||||
});
|
||||
|
||||
let name = $state('API Key');
|
||||
let selectedPermissions = $state<Permission[]>(queryPermissions);
|
||||
const isAllPermissions = $derived(selectedPermissions.length === Object.keys(Permission).length - 1);
|
||||
|
||||
const onClose = async () => {
|
||||
await goto(Route.userSettings({ isOpen: OpenQueryParam.API_KEYS }));
|
||||
};
|
||||
|
||||
let secret: string | undefined = $state();
|
||||
|
||||
const onSubmit = async () => {
|
||||
const permissions = isAllPermissions ? [Permission.All] : selectedPermissions;
|
||||
const response = await handleCreateApiKey({ name, permissions });
|
||||
if (response) {
|
||||
secret = response.secret;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if !secret}
|
||||
<FormModal title={$t('new_api_key')} icon={mdiKeyVariant} {onClose} {onSubmit} submitText={$t('create')} size="giant">
|
||||
<div class="mb-4 flex flex-col gap-2">
|
||||
<Field label={$t('name')}>
|
||||
<Input bind:value={name} />
|
||||
</Field>
|
||||
</div>
|
||||
<ApiKeyPermissionsPicker bind:selectedPermissions />
|
||||
</FormModal>
|
||||
{:else}
|
||||
<ApiKeySecretModal {secret} {onClose} />
|
||||
{/if}
|
||||
14
web/src/routes/(user)/user-settings/new-api-key/+page.ts
Normal file
14
web/src/routes/(user)/user-settings/new-api-key/+page.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { authenticate } from '$lib/utils/auth';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load = (async ({ url }) => {
|
||||
await authenticate(url);
|
||||
const $t = await getFormatter();
|
||||
|
||||
return {
|
||||
meta: {
|
||||
title: $t('settings'),
|
||||
},
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
Reference in New Issue
Block a user