Skip to content

Commit 3af09ad

Browse files
committed
fix: new schemaformfield has value of the same type
1 parent 5156438 commit 3af09ad

File tree

3 files changed

+109
-81
lines changed

3 files changed

+109
-81
lines changed

web/src/lib/components/workflows/SchemaFormFields.svelte

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
2-
import { formatLabel, getComponentFromSchema, type ComponentConfig } from '$lib/utils/workflow';
3-
import { Field, Input, MultiSelect, Select, Switch, Text, type SelectItem } from '@immich/ui';
2+
import { getComponentFromSchema, type ComponentConfig } from '$lib/utils/workflow';
3+
import { Field, Input, MultiSelect, Select, Switch, Text } from '@immich/ui';
44
import WorkflowPickerField from './WorkflowPickerField.svelte';
55
66
type Props = {
@@ -63,10 +63,6 @@
6363
return updates;
6464
});
6565
66-
let selectValue = $state<SelectItem>();
67-
let switchValue = $state<boolean>(false);
68-
let multiSelectValue = $state<SelectItem[]>([]);
69-
7066
// Initialize config namespace if needed
7167
$effect(() => {
7268
if (configKey && !config[configKey]) {
@@ -81,26 +77,6 @@
8177
}
8278
});
8379
84-
// Sync UI state for components with default values
85-
$effect(() => {
86-
for (const { component } of uninitializedKeys) {
87-
if (component.defaultValue === undefined) {
88-
continue;
89-
}
90-
91-
if (component.type === 'select') {
92-
selectValue = {
93-
label: formatLabel(String(component.defaultValue)),
94-
value: String(component.defaultValue),
95-
};
96-
}
97-
98-
if (component.type === 'switch') {
99-
switchValue = Boolean(component.defaultValue);
100-
}
101-
}
102-
});
103-
10480
const isPickerField = (subType: string | undefined) => subType === 'album-picker' || subType === 'people-picker';
10581
</script>
10682

@@ -123,14 +99,16 @@
12399
{@const options = component.options?.map((opt) => {
124100
return { label: opt.label, value: String(opt.value) };
125101
}) || [{ label: 'N/A', value: '' }]}
102+
{@const currentValue = actualConfig[key]}
103+
{@const selectedItem = options.find((opt) => opt.value === String(currentValue)) ?? options[0]}
126104

127105
<Field
128106
{label}
129107
required={component.required}
130108
description={component.description}
131109
requiredIndicator={component.required}
132110
>
133-
<Select data={options} onChange={(opt) => updateConfig(key, opt.value)} bind:value={selectValue} />
111+
<Select data={options} onChange={(opt) => updateConfig(key, opt.value)} value={selectedItem} />
134112
</Field>
135113
{/if}
136114

@@ -147,6 +125,8 @@
147125
{@const options = component.options?.map((opt) => {
148126
return { label: opt.label, value: String(opt.value) };
149127
}) || [{ label: 'N/A', value: '' }]}
128+
{@const currentValues = (actualConfig[key] as string[]) ?? []}
129+
{@const selectedItems = options.filter((opt) => currentValues.includes(opt.value))}
150130

151131
<Field
152132
{label}
@@ -161,20 +141,21 @@
161141
key,
162142
opt.map((o) => o.value),
163143
)}
164-
bind:values={multiSelectValue}
144+
values={selectedItems}
165145
/>
166146
</Field>
167147
{/if}
168148

169149
<!-- Switch component -->
170150
{:else if component.type === 'switch'}
151+
{@const checked = Boolean(actualConfig[key])}
171152
<Field
172153
{label}
173154
description={component.description}
174155
requiredIndicator={component.required}
175156
required={component.required}
176157
>
177-
<Switch bind:checked={switchValue} onCheckedChange={(check) => updateConfig(key, check)} />
158+
<Switch {checked} onCheckedChange={(check) => updateConfig(key, check)} />
178159
</Field>
179160

180161
<!-- Text input -->

web/src/lib/services/workflow.service.ts

Lines changed: 83 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,69 @@ export const getActionsByContext = (
5858
};
5959

6060
/**
61-
* Initialize filter configurations from existing workflow
61+
* Remap configs when items are reordered (drag-drop)
62+
* Moves config from old index to new index position
6263
*/
63-
export const initializeFilterConfigs = (
64-
workflow: WorkflowResponseDto,
65-
availableFilters: PluginFilterResponseDto[],
64+
export const remapConfigsOnReorder = (
65+
configs: Record<string, unknown>,
66+
prefix: 'filter' | 'action',
67+
fromIndex: number,
68+
toIndex: number,
69+
totalCount: number,
70+
): Record<string, unknown> => {
71+
const newConfigs: Record<string, unknown> = {};
72+
73+
// Create an array of configs in order
74+
const configArray: unknown[] = [];
75+
for (let i = 0; i < totalCount; i++) {
76+
configArray.push(configs[`${prefix}_${i}`] ?? {});
77+
}
78+
79+
// Move the item from fromIndex to toIndex
80+
const [movedItem] = configArray.splice(fromIndex, 1);
81+
configArray.splice(toIndex, 0, movedItem);
82+
83+
// Rebuild the configs object with new indices
84+
for (let i = 0; i < configArray.length; i++) {
85+
newConfigs[`${prefix}_${i}`] = configArray[i];
86+
}
87+
88+
return newConfigs;
89+
};
90+
91+
/**
92+
* Remap configs when an item is removed
93+
* Shifts all configs after the removed index down by one
94+
*/
95+
export const remapConfigsOnRemove = (
96+
configs: Record<string, unknown>,
97+
prefix: 'filter' | 'action',
98+
removedIndex: number,
99+
totalCount: number,
66100
): Record<string, unknown> => {
101+
const newConfigs: Record<string, unknown> = {};
102+
103+
let newIndex = 0;
104+
for (let i = 0; i < totalCount; i++) {
105+
if (i !== removedIndex) {
106+
newConfigs[`${prefix}_${newIndex}`] = configs[`${prefix}_${i}`] ?? {};
107+
newIndex++;
108+
}
109+
}
110+
111+
return newConfigs;
112+
};
113+
114+
/**
115+
* Initialize filter configurations from existing workflow
116+
* Uses index-based keys to support multiple filters of the same type
117+
*/
118+
export const initializeFilterConfigs = (workflow: WorkflowResponseDto): Record<string, unknown> => {
67119
const configs: Record<string, unknown> = {};
68120

69121
if (workflow.filters) {
70-
for (const workflowFilter of workflow.filters) {
71-
const filterDef = availableFilters.find((f) => f.id === workflowFilter.pluginFilterId);
72-
if (filterDef) {
73-
configs[filterDef.methodName] = workflowFilter.filterConfig ?? {};
74-
}
122+
for (const [index, workflowFilter] of workflow.filters.entries()) {
123+
configs[`filter_${index}`] = workflowFilter.filterConfig ?? {};
75124
}
76125
}
77126

@@ -80,19 +129,14 @@ export const initializeFilterConfigs = (
80129

81130
/**
82131
* Initialize action configurations from existing workflow
132+
* Uses index-based keys to support multiple actions of the same type
83133
*/
84-
export const initializeActionConfigs = (
85-
workflow: WorkflowResponseDto,
86-
availableActions: PluginActionResponseDto[],
87-
): Record<string, unknown> => {
134+
export const initializeActionConfigs = (workflow: WorkflowResponseDto): Record<string, unknown> => {
88135
const configs: Record<string, unknown> = {};
89136

90137
if (workflow.actions) {
91-
for (const workflowAction of workflow.actions) {
92-
const actionDef = availableActions.find((a) => a.id === workflowAction.pluginActionId);
93-
if (actionDef) {
94-
configs[actionDef.methodName] = workflowAction.actionConfig ?? {};
95-
}
138+
for (const [index, workflowAction] of workflow.actions.entries()) {
139+
configs[`action_${index}`] = workflowAction.actionConfig ?? {};
96140
}
97141
}
98142

@@ -101,6 +145,7 @@ export const initializeActionConfigs = (
101145

102146
/**
103147
* Build workflow payload from current state
148+
* Uses index-based keys to support multiple filters/actions of the same type
104149
*/
105150
export const buildWorkflowPayload = (
106151
name: string,
@@ -112,12 +157,12 @@ export const buildWorkflowPayload = (
112157
filterConfigs: Record<string, unknown>,
113158
actionConfigs: Record<string, unknown>,
114159
): WorkflowPayload => {
115-
const filters = orderedFilters.map((filter) => ({
116-
[filter.methodName]: filterConfigs[filter.methodName] ?? {},
160+
const filters = orderedFilters.map((filter, index) => ({
161+
[filter.methodName]: filterConfigs[`filter_${index}`] ?? {},
117162
}));
118163

119-
const actions = orderedActions.map((action) => ({
120-
[action.methodName]: actionConfigs[action.methodName] ?? {},
164+
const actions = orderedActions.map((action, index) => ({
165+
[action.methodName]: actionConfigs[`action_${index}`] ?? {},
121166
}));
122167

123168
return {
@@ -158,30 +203,30 @@ export const parseWorkflowJson = (
158203
// Find trigger
159204
const trigger = availableTriggers.find((t) => t.type === parsed.triggerType);
160205

161-
// Parse filters
206+
// Parse filters (using index-based keys to support multiple of same type)
162207
const filters: PluginFilterResponseDto[] = [];
163208
const filterConfigs: Record<string, unknown> = {};
164209
if (Array.isArray(parsed.filters)) {
165-
for (const filterObj of parsed.filters) {
210+
for (const [index, filterObj] of parsed.filters.entries()) {
166211
const methodName = Object.keys(filterObj)[0];
167212
const filter = availableFilters.find((f) => f.methodName === methodName);
168213
if (filter) {
169214
filters.push(filter);
170-
filterConfigs[methodName] = (filterObj as Record<string, unknown>)[methodName];
215+
filterConfigs[`filter_${index}`] = (filterObj as Record<string, unknown>)[methodName];
171216
}
172217
}
173218
}
174219

175-
// Parse actions
220+
// Parse actions (using index-based keys to support multiple of same type)
176221
const actions: PluginActionResponseDto[] = [];
177222
const actionConfigs: Record<string, unknown> = {};
178223
if (Array.isArray(parsed.actions)) {
179-
for (const actionObj of parsed.actions) {
224+
for (const [index, actionObj] of parsed.actions.entries()) {
180225
const methodName = Object.keys(actionObj)[0];
181226
const action = availableActions.find((a) => a.methodName === methodName);
182227
if (action) {
183228
actions.push(action);
184-
actionConfigs[methodName] = (actionObj as Record<string, unknown>)[methodName];
229+
actionConfigs[`action_${index}`] = (actionObj as Record<string, unknown>)[methodName];
185230
}
186231
}
187232
}
@@ -220,8 +265,6 @@ export const hasWorkflowChanged = (
220265
orderedActions: PluginActionResponseDto[],
221266
filterConfigs: Record<string, unknown>,
222267
actionConfigs: Record<string, unknown>,
223-
availableFilters: PluginFilterResponseDto[],
224-
availableActions: PluginActionResponseDto[],
225268
): boolean => {
226269
// Check enabled state
227270
if (enabled !== previousWorkflow.enabled) {
@@ -252,25 +295,19 @@ export const hasWorkflowChanged = (
252295
return true;
253296
}
254297

255-
// Check filter configs
298+
// Check filter configs (using index-based keys)
256299
const previousFilterConfigs: Record<string, unknown> = {};
257-
for (const wf of previousWorkflow.filters ?? []) {
258-
const filterDef = availableFilters.find((f) => f.id === wf.pluginFilterId);
259-
if (filterDef) {
260-
previousFilterConfigs[filterDef.methodName] = wf.filterConfig ?? {};
261-
}
300+
for (const [index, wf] of (previousWorkflow.filters ?? []).entries()) {
301+
previousFilterConfigs[`filter_${index}`] = wf.filterConfig ?? {};
262302
}
263303
if (JSON.stringify(previousFilterConfigs) !== JSON.stringify(filterConfigs)) {
264304
return true;
265305
}
266306

267-
// Check action configs
307+
// Check action configs (using index-based keys)
268308
const previousActionConfigs: Record<string, unknown> = {};
269-
for (const wa of previousWorkflow.actions ?? []) {
270-
const actionDef = availableActions.find((a) => a.id === wa.pluginActionId);
271-
if (actionDef) {
272-
previousActionConfigs[actionDef.methodName] = wa.actionConfig ?? {};
273-
}
309+
for (const [index, wa] of (previousWorkflow.actions ?? []).entries()) {
310+
previousActionConfigs[`action_${index}`] = wa.actionConfig ?? {};
274311
}
275312
if (JSON.stringify(previousActionConfigs) !== JSON.stringify(actionConfigs)) {
276313
return true;
@@ -293,14 +330,14 @@ export const handleUpdateWorkflow = async (
293330
filterConfigs: Record<string, unknown>,
294331
actionConfigs: Record<string, unknown>,
295332
): Promise<WorkflowResponseDto> => {
296-
const filters = orderedFilters.map((filter) => ({
333+
const filters = orderedFilters.map((filter, index) => ({
297334
pluginFilterId: filter.id,
298-
filterConfig: filterConfigs[filter.methodName] ?? {},
335+
filterConfig: filterConfigs[`filter_${index}`] ?? {},
299336
})) as WorkflowFilterItemDto[];
300337

301-
const actions = orderedActions.map((action) => ({
338+
const actions = orderedActions.map((action, index) => ({
302339
pluginActionId: action.id,
303-
actionConfig: actionConfigs[action.methodName] ?? {},
340+
actionConfig: actionConfigs[`action_${index}`] ?? {},
304341
})) as WorkflowActionItemDto[];
305342

306343
const updateDto: WorkflowUpdateDto = {

0 commit comments

Comments
 (0)