From 646b8249ca1eb3a386f5a5a758a705678c0409ca Mon Sep 17 00:00:00 2001 From: Alex Tran Date: Mon, 18 May 2026 16:37:53 -0500 Subject: [PATCH] wip: redesign card flow --- .../workflows/[workflowId]/+page.svelte | 218 ++++++++++-------- 1 file changed, 120 insertions(+), 98 deletions(-) diff --git a/web/src/routes/(user)/workflows/[workflowId]/+page.svelte b/web/src/routes/(user)/workflows/[workflowId]/+page.svelte index 4043e9e590..2f4c179bf0 100644 --- a/web/src/routes/(user)/workflows/[workflowId]/+page.svelte +++ b/web/src/routes/(user)/workflows/[workflowId]/+page.svelte @@ -30,16 +30,16 @@ IconButton, Input, modalManager, - Stack, Switch, - Text, Textarea, VStack, } from '@immich/ui'; import { mdiArrowLeft, + mdiAutoFix, mdiCodeJson, mdiContentSave, + mdiFilterVariant, mdiFlashOutline, mdiFormatListBulletedSquare, mdiInformationOutline, @@ -73,6 +73,12 @@ let editMode = $state('visual'); const workflowSummary = $derived({ trigger, steps }); const workflowJsonContent = $derived({ description, enabled, name, steps, trigger }); + const stepsWithConfigEntries = $derived( + steps.map((step) => ({ + step, + configEntries: getConfigEntries(step.config), + })), + ); const hasChanges = $derived( enabled !== savedWorkflow.enabled || @@ -89,11 +95,19 @@ } }; - const handleEditStep = async (step: WorkflowStepDto) => { + const replaceStep = (index: number, step: WorkflowStepDto) => { + steps = steps.map((current, i) => (i === index ? cloneDeep(step) : current)); + }; + + const handleEditStep = async (index: number) => { + const step = steps[index]; + if (!step) { + return; + } + const result = await modalManager.show(WorkflowEditStepModal, { trigger, step: cloneDeep(step) }); if (result) { - Object.assign(step, result); - steps = [...steps]; + replaceStep(index, result); } }; @@ -128,24 +142,25 @@ return String(value); } if (typeof value === 'string') { - return truncate(value); + return `"${truncate(value)}"`; } if (Array.isArray(value)) { if (value.length === 0) { return $t('none'); } const items = value.map((v) => (v !== null && typeof v === 'object' ? '{…}' : String(v))); - const joined = items.join(', '); + const joined = items.join(' · '); if (joined.length <= 28) { - return joined; + return `"${joined}"`; } return $t('items_count', { values: { count: value.length } }); } return '{…}'; }; - const getConfigEntries = (config: WorkflowStepDto['config']) => - Object.entries(config ?? {}).filter(([, value]) => value !== null && value !== undefined && value !== ''); + function getConfigEntries(config: WorkflowStepDto['config']) { + return Object.entries(config ?? {}).filter(([, value]) => value !== null && value !== undefined && value !== ''); + } const onChangeTrigger = async () => { const newTrigger = await modalManager.show(WorkflowTriggerPicker, { selected: trigger }); @@ -222,7 +237,7 @@ - + @@ -313,104 +328,111 @@
- - -
- -
- {$t('trigger')} - {$t('trigger_description')} + + +
+
+
-
- +
+ {getTriggerName($t, trigger)} + {getTriggerDescription($t, trigger)}
+ +
- - -
- {getTriggerName($t, trigger)} - {getTriggerDescription($t, trigger)} -
-
- - -
- - {$t('steps')} + {#snippet sequenceConnector()} +
+
+
- +
+ {/snippet} - - {#if steps.length === 0} - - {:else} - - {#each steps as step, index (index)} - {@const method = pluginManager.getMethod(step.method)} - {@const entries = getConfigEntries(step.config)} - {#if index > 0} -
+ {#each stepsWithConfigEntries as { step, configEntries }, index (index)} + {@const method = pluginManager.getMethod(step.method)} + {@const isFilter = method?.uiHints?.includes('filter') ?? false} + {@render sequenceConnector()} + + +
+
+ +
+
+ + {index + 1}. {pluginManager.getMethodLabel(step.method)} + + {#if method?.description} + {method.description} {/if} -
- - {index + 1} - -
- {pluginManager.getMethodLabel(step.method)} - {#if method?.description} - {method.description} - {/if} - {#if entries.length > 0} -
- {#each entries.slice(0, 3) as [key, value] (key)} - - {key}: - {formatConfigValue(value)} - - {/each} - {#if entries.length > 3} - - +{entries.length - 3} - - {/if} -
- {/if} -
-
- handleEditStep(step)} - /> - handleDeleteStep(index)} - /> -
-
- {/each} +
+
+ handleEditStep(index)} + /> + handleDeleteStep(index)} + /> +
+
+
- -
+ {#if configEntries.length > 0} + +
+ {#each configEntries as [key, value] (key)} + + {key}={formatConfigValue(value)} + + {/each} +
+
{/if} -
- + + {/each} + + {:else} {/if}