diff --git a/web/src/lib/components/SchemaConfiguration.svelte b/web/src/lib/components/SchemaConfiguration.svelte
index 2cc0b68089..37e799984f 100644
--- a/web/src/lib/components/SchemaConfiguration.svelte
+++ b/web/src/lib/components/SchemaConfiguration.svelte
@@ -2,7 +2,19 @@
import SchemaAlbumPicker from '$lib/components/SchemaAlbumPicker.svelte';
import Self from '$lib/components/SchemaConfiguration.svelte';
import type { JSONSchemaProperty, SchemaConfig } from '$lib/types';
- import { CodeBlock, Field, Input, Label, MultiSelect, NumberInput, Select, Switch, Text } from '@immich/ui';
+ import {
+ CodeBlock,
+ Field,
+ HelperText,
+ Input,
+ Label,
+ MultiSelect,
+ NumberInput,
+ Select,
+ Switch,
+ Text,
+ } from '@immich/ui';
+ import { t } from 'svelte-i18n';
type Props = {
schema: JSONSchemaProperty;
@@ -75,12 +87,11 @@
{:else if schema.array}
-
+
+ {$t('unsupported_field_type')}
+
{:else if schema.type === 'boolean'}
getBoolean(schema.default ?? false), setValue} />
diff --git a/web/src/lib/modals/WorkflowAddStepModal.svelte b/web/src/lib/modals/WorkflowAddStepModal.svelte
index d347a1feb3..c2a4d658a8 100644
--- a/web/src/lib/modals/WorkflowAddStepModal.svelte
+++ b/web/src/lib/modals/WorkflowAddStepModal.svelte
@@ -2,6 +2,7 @@
import SchemaConfiguration from '$lib/components/SchemaConfiguration.svelte';
import PluginMethodPicker from '$lib/modals/PluginMethodPicker.svelte';
import { type JSONSchemaProperty, type SchemaConfig } from '$lib/types';
+ import { getWorkflowDefaultConfig } from '$lib/utils/workflow';
import { WorkflowTrigger, type PluginMethodResponseDto, type WorkflowStepDto } from '@immich/sdk';
import { FormModal, IconButton, modalManager, Stack, Text, Textarea } from '@immich/ui';
import { mdiPencilOutline } from '@mdi/js';
@@ -31,7 +32,7 @@
}
method = selected;
- config = selected.schema ? {} : null;
+ config = selected.schema ? getWorkflowDefaultConfig(selected.schema as JSONSchemaProperty) : null;
};
void onPickMethod();
diff --git a/web/src/lib/modals/WorkflowEditStepModal.svelte b/web/src/lib/modals/WorkflowEditStepModal.svelte
index 5375edc7d3..a2adbba090 100644
--- a/web/src/lib/modals/WorkflowEditStepModal.svelte
+++ b/web/src/lib/modals/WorkflowEditStepModal.svelte
@@ -3,6 +3,7 @@
import { pluginManager } from '$lib/managers/plugin-manager.svelte';
import PluginMethodPicker from '$lib/modals/PluginMethodPicker.svelte';
import { type JSONSchemaProperty, type SchemaConfig } from '$lib/types';
+ import { getWorkflowDefaultConfig } from '$lib/utils/workflow';
import { WorkflowTrigger, type WorkflowStepDto } from '@immich/sdk';
import { Button, FormModal, modalManager, Stack, Text, Textarea } from '@immich/ui';
import { mdiPencilOutline } from '@mdi/js';
@@ -30,7 +31,7 @@
}
method = selected;
- config = selected.schema ? {} : null;
+ config = selected.schema ? getWorkflowDefaultConfig(selected.schema as JSONSchemaProperty) : null;
};
diff --git a/web/src/lib/utils/workflow.spec.ts b/web/src/lib/utils/workflow.spec.ts
new file mode 100644
index 0000000000..b6492ae32a
--- /dev/null
+++ b/web/src/lib/utils/workflow.spec.ts
@@ -0,0 +1,112 @@
+import { getWorkflowDefaultConfig } from '$lib/utils/workflow';
+
+describe(getWorkflowDefaultConfig.name, () => {
+ describe('required properties', () => {
+ it('should use a default value', () => {
+ expect(
+ getWorkflowDefaultConfig({
+ type: 'object',
+ properties: {
+ test: {
+ type: 'boolean',
+ default: true,
+ },
+ },
+ required: ['test'],
+ }),
+ ).toEqual({ test: true });
+ });
+
+ it('should default to an empty array', () => {
+ expect(
+ getWorkflowDefaultConfig({
+ type: 'object',
+ properties: {
+ test: {
+ type: 'string',
+ array: true,
+ },
+ },
+ required: ['test'],
+ }),
+ ).toEqual({ test: [] });
+ });
+
+ it('should default to false', () => {
+ expect(
+ getWorkflowDefaultConfig({
+ type: 'object',
+ properties: {
+ test: {
+ type: 'boolean',
+ },
+ },
+ required: ['test'],
+ }),
+ ).toEqual({ test: false });
+ });
+
+ it('should default to 0 (integer)', () => {
+ expect(
+ getWorkflowDefaultConfig({
+ type: 'object',
+ properties: {
+ test: {
+ type: 'integer',
+ },
+ },
+ required: ['test'],
+ }),
+ ).toEqual({ test: 0 });
+ });
+
+ it('should default to 0 (number)', () => {
+ expect(
+ getWorkflowDefaultConfig({
+ type: 'object',
+ properties: {
+ test: {
+ type: 'number',
+ },
+ },
+ required: ['test'],
+ }),
+ ).toEqual({ test: 0 });
+ });
+
+ it('should default to an empty string', () => {
+ expect(
+ getWorkflowDefaultConfig({
+ type: 'object',
+ properties: {
+ test: {
+ type: 'string',
+ },
+ },
+ required: ['test'],
+ }),
+ ).toEqual({ test: '' });
+ });
+
+ it('should default recursively', () => {
+ expect(
+ getWorkflowDefaultConfig({
+ type: 'object',
+ properties: {
+ parent: {
+ type: 'object',
+ properties: {
+ test: {
+ type: 'string',
+ array: true,
+ },
+ },
+ required: ['test'],
+ },
+ },
+ required: ['parent'],
+ }),
+ ).toEqual({ parent: { test: [] } });
+ });
+ });
+});
diff --git a/web/src/lib/utils/workflow.ts b/web/src/lib/utils/workflow.ts
index cb8d856cb9..61702f4264 100644
--- a/web/src/lib/utils/workflow.ts
+++ b/web/src/lib/utils/workflow.ts
@@ -1,5 +1,6 @@
import { WorkflowTrigger } from '@immich/sdk';
import type { MessageFormatter } from 'svelte-i18n';
+import type { JSONSchemaProperty } from '$lib/types';
export const getTriggerName = ($t: MessageFormatter, type: WorkflowTrigger) => {
switch (type) {
@@ -34,3 +35,56 @@ export const getTriggerDescription = ($t: MessageFormatter, type: WorkflowTrigge
}
}
};
+
+export const getWorkflowDefaultConfig = (schema: JSONSchemaProperty) => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const config: any = {};
+
+ const requiredProperties = schema.required ?? [];
+
+ for (const [key, property] of Object.entries(schema.properties ?? {})) {
+ // default values
+ if (property.default) {
+ config[key] = property.default;
+ break;
+ }
+
+ if (!requiredProperties.includes(key)) {
+ continue;
+ }
+
+ if (property.array) {
+ config[key] = [];
+ continue;
+ }
+
+ switch (property.type) {
+ case 'string': {
+ config[key] = '';
+ break;
+ }
+
+ case 'integer':
+ case 'number': {
+ config[key] = 0;
+ break;
+ }
+
+ case 'boolean': {
+ config[key] = false;
+ break;
+ }
+
+ case 'object': {
+ config[key] = property.properties ? getWorkflowDefaultConfig(property) : {};
+ break;
+ }
+
+ default: {
+ console.log(`Unknown configuration type: ${property.type}`);
+ }
+ }
+ }
+
+ return config;
+};