mirror of
https://github.com/immich-app/immich.git
synced 2026-06-24 07:28:30 -07:00
111 lines
3.4 KiB
Svelte
111 lines
3.4 KiB
Svelte
<script lang="ts">
|
|
import SchemaAlbumPicker from '$lib/components/SchemaAlbumPicker.svelte';
|
|
import Self from '$lib/components/SchemaConfiguration.svelte';
|
|
import type { JSONSchemaProperty, SchemaConfig } from '$lib/types';
|
|
import {
|
|
CodeBlock,
|
|
Field,
|
|
HelperText,
|
|
Input,
|
|
Label,
|
|
MultiSelect,
|
|
NumberInput,
|
|
Select,
|
|
Switch,
|
|
Text,
|
|
} from '@immich/ui';
|
|
import { t } from 'svelte-i18n';
|
|
|
|
type Props = {
|
|
schema: JSONSchemaProperty;
|
|
root?: boolean;
|
|
key?: string;
|
|
config: SchemaConfig;
|
|
};
|
|
|
|
let { schema, key = '', root = false, config = $bindable() }: Props = $props();
|
|
|
|
const label = $derived(schema.title ?? key);
|
|
const description = $derived(schema.description);
|
|
|
|
const getValue = <T,>(defaultValue?: T) => (root === true ? config : (config?.[key] ?? defaultValue)) as T;
|
|
const setValue = <T,>(value: T) => {
|
|
if (root === true) {
|
|
config = value;
|
|
} else {
|
|
if (config === undefined) {
|
|
config = {};
|
|
}
|
|
|
|
config[key] = value;
|
|
}
|
|
};
|
|
|
|
const getUiHintValue = () => {
|
|
if (schema.array) {
|
|
return getValue<string[]>([]);
|
|
}
|
|
|
|
const values = getValue<string>();
|
|
return values ? [values] : [];
|
|
};
|
|
|
|
const setUiHintValue = (values: string[]) => setValue(schema.array ? values : values[0]);
|
|
|
|
const getBoolean = (defaultValue = false) => getValue<boolean>(defaultValue);
|
|
const getString = () => getValue<string>();
|
|
const getEnum = () => getValue<string[]>([]);
|
|
const getNumber = () => getValue<number>();
|
|
</script>
|
|
|
|
<!-- Empty schema object -->
|
|
{#if Object.keys(schema).length === 0}
|
|
<!-- noop -->
|
|
<!-- nested configuration (also top level objects) -->
|
|
{:else if schema.type === 'object'}
|
|
{#if !root}
|
|
<div class="flex flex-col gap-2">
|
|
<Label size="small" class="font-medium" {label}></Label>
|
|
{#if description}
|
|
<Text color="muted" size="small">{description}</Text>
|
|
{/if}
|
|
</div>
|
|
{/if}
|
|
<div class="flex flex-col gap-4 {root ? '' : 'border-l-4 border-gray-200 ps-2'}">
|
|
{#each Object.entries(schema.properties ?? {}) as [childKey, childSchema] (childKey)}
|
|
<Self schema={childSchema} key={childKey} bind:config={getValue, setValue} />
|
|
{/each}
|
|
</div>
|
|
{:else if schema.uiHint === 'AlbumId'}
|
|
<SchemaAlbumPicker {label} {description} array={schema.array} bind:albumIds={getUiHintValue, setUiHintValue} />
|
|
{:else if schema.enum && schema.array}
|
|
<Field {label} {description}>
|
|
<MultiSelect options={schema.enum} bind:values={getEnum, setValue} />
|
|
</Field>
|
|
{:else if schema.enum}
|
|
<Field {label} {description}>
|
|
<Select options={schema.enum} bind:value={getString, setValue} />
|
|
</Field>
|
|
{:else if schema.array}
|
|
{@const values = getValue<string[]>([])}
|
|
<Field {label} {description}>
|
|
<Input value={values.join(',')} disabled />
|
|
<HelperText>{$t('unsupported_field_type')}</HelperText>
|
|
</Field>
|
|
{:else if schema.type === 'boolean'}
|
|
<Field {label} {description}>
|
|
<Switch bind:checked={() => getBoolean(schema.default ?? false), setValue} />
|
|
</Field>
|
|
{:else if schema.type === 'number'}
|
|
<Field {label} {description}>
|
|
<NumberInput bind:value={getNumber, setValue} />
|
|
</Field>
|
|
{:else if schema.type === 'string'}
|
|
<Field {label} {description}>
|
|
<Input bind:value={() => getValue<string>(), setValue} />
|
|
</Field>
|
|
{:else}
|
|
<Text>Unknown schema</Text>
|
|
<CodeBlock code={JSON.stringify(schema, null, 2)} />
|
|
{/if}
|