From 0546bc900c2dbbe51ff967efb7e8cf97a7cd6f02 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 26 May 2026 13:06:20 -0500 Subject: [PATCH] chore: workflow UI (#28536) * wip: confirm before existing and disable/enable save button condition * fix: get correct workflow detail * wip: add back workflow summary * wip: add back json editor * wip: step property badge * wip: redesign card flow * wip: redesign card flow * redesign workflow summary * wworkflow summary styling * wip * drag and drop * list redesign * refactor * refactor * remove deadcode * refactor * insert steps * push down when dropped * fix: query by workflow id --------- Co-authored-by: Jason Rasmussen --- i18n/en.json | 3 + .../src/repositories/workflow.repository.ts | 1 + web/src/lib/modals/PluginMethodPicker.svelte | 2 +- .../lib/modals/WorkflowAddStepModal.svelte | 2 +- .../lib/modals/WorkflowEditStepModal.svelte | 2 +- .../lib/modals/WorkflowTriggerPicker.svelte | 2 +- web/src/routes/(user)/workflows/+page.svelte | 139 ++---- .../workflows/[workflowId]/+page.svelte | 466 ++++++++++++------ .../[workflowId]/WorkflowJsonEditor.svelte | 99 +++- .../[workflowId]/WorkflowStepCard.svelte | 195 ++++++++ .../[workflowId]/WorkflowStepDragImage.svelte | 43 ++ .../[workflowId]/WorkflowSummary.svelte | 255 ++++++---- 12 files changed, 842 insertions(+), 367 deletions(-) create mode 100644 web/src/routes/(user)/workflows/[workflowId]/WorkflowStepCard.svelte create mode 100644 web/src/routes/(user)/workflows/[workflowId]/WorkflowStepDragImage.svelte diff --git a/i18n/en.json b/i18n/en.json index 97f4575567d97..e73ac13e60a6d 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -976,6 +976,7 @@ "downloading_asset_filename": "Downloading asset {filename}", "downloading_from_icloud": "Downloading from iCloud", "downloading_media": "Downloading media", + "drag_to_reorder": "Drag to reorder", "drop_files_to_upload": "Drop files anywhere to upload", "duplicates": "Duplicates", "duplicates_description": "Resolve each group by indicating which, if any, are duplicates.", @@ -2254,6 +2255,7 @@ "step_delete_confirm": "Are you sure you want to delete this step?", "step_details": "Step details", "steps": "Steps", + "steps_count": "{count, plural, one {# step} other {# steps}}", "stop_casting": "Stop casting", "stop_motion_photo": "Stop Motion Photo", "stop_photo_sharing": "Stop sharing your photos?", @@ -2476,6 +2478,7 @@ "week": "Week", "welcome": "Welcome", "welcome_to_immich": "Welcome to Immich", + "when": "When", "width": "Width", "wifi_name": "Wi-Fi Name", "workflow": "Workflow", diff --git a/server/src/repositories/workflow.repository.ts b/server/src/repositories/workflow.repository.ts index cd5aa6431fff0..69ecb83ae9619 100644 --- a/server/src/repositories/workflow.repository.ts +++ b/server/src/repositories/workflow.repository.ts @@ -47,6 +47,7 @@ export class WorkflowRepository { @GenerateSql({ params: [DummyValue.UUID] }) search(dto: WorkflowSearchDto & { ownerId?: string }) { return this.queryBuilder() + .$if(!!dto.id, (qb) => qb.where('id', '=', dto.id!)) .$if(!!dto.ownerId, (qb) => qb.where('ownerId', '=', dto.ownerId!)) .$if(!!dto.trigger, (qb) => qb.where('trigger', '=', dto.trigger!)) .$if(dto.enabled !== undefined, (qb) => qb.where('enabled', '=', dto.enabled!)) diff --git a/web/src/lib/modals/PluginMethodPicker.svelte b/web/src/lib/modals/PluginMethodPicker.svelte index 7000fed2cc3a4..bbfa2ca83f63c 100644 --- a/web/src/lib/modals/PluginMethodPicker.svelte +++ b/web/src/lib/modals/PluginMethodPicker.svelte @@ -12,7 +12,7 @@ const { trigger, selectedKey, onClose }: Props = $props(); - + {#await searchPluginMethods({ trigger })}
diff --git a/web/src/lib/modals/WorkflowAddStepModal.svelte b/web/src/lib/modals/WorkflowAddStepModal.svelte index 889e175de05e0..d347a1feb3e28 100644 --- a/web/src/lib/modals/WorkflowAddStepModal.svelte +++ b/web/src/lib/modals/WorkflowAddStepModal.svelte @@ -38,7 +38,7 @@ {#if method} - +
{method.title} diff --git a/web/src/lib/modals/WorkflowEditStepModal.svelte b/web/src/lib/modals/WorkflowEditStepModal.svelte index b9887c8a6af10..5375edc7d35aa 100644 --- a/web/src/lib/modals/WorkflowEditStepModal.svelte +++ b/web/src/lib/modals/WorkflowEditStepModal.svelte @@ -35,7 +35,7 @@ {#if method} - +
{method.title} diff --git a/web/src/lib/modals/WorkflowTriggerPicker.svelte b/web/src/lib/modals/WorkflowTriggerPicker.svelte index 48ab02130eeda..489b89caf58ae 100644 --- a/web/src/lib/modals/WorkflowTriggerPicker.svelte +++ b/web/src/lib/modals/WorkflowTriggerPicker.svelte @@ -17,7 +17,7 @@ const onSubmit = () => onClose(selected); - +
{#each pluginManager.triggers as item (item.trigger)} (selected = item.trigger)}> diff --git a/web/src/routes/(user)/workflows/+page.svelte b/web/src/routes/(user)/workflows/+page.svelte index 15a4c4621ea68..f4d4b67a33f74 100644 --- a/web/src/routes/(user)/workflows/+page.svelte +++ b/web/src/routes/(user)/workflows/+page.svelte @@ -4,26 +4,24 @@ import UserPageLayout from '$lib/components/layouts/UserPageLayout.svelte'; import OnEvents from '$lib/components/OnEvents.svelte'; import EmptyPlaceholder from '$lib/components/shared-components/EmptyPlaceholder.svelte'; - import { pluginManager } from '$lib/managers/plugin-manager.svelte'; import { Route } from '$lib/route'; import { getWorkflowActions, getWorkflowsActions, getWorkflowShowSchemaAction } from '$lib/services/workflow.service'; import { getWorkflowForShare, type WorkflowResponseDto } from '@immich/sdk'; import { + Badge, Button, Card, - CardBody, CardDescription, CardHeader, CardTitle, CodeBlock, Container, + Icon, IconButton, MenuItemType, menuManager, - Text, - VStack, } from '@immich/ui'; - import { mdiClose, mdiDotsVertical } from '@mdi/js'; + import { mdiClose, mdiDotsVertical, mdiFlashOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; import { SvelteSet } from 'svelte/reactivity'; import type { PageData } from './$types'; @@ -46,20 +44,6 @@ } }; - const getTriggerLabel = (triggerType: string) => { - const labels: Record = { - AssetCreate: $t('asset_created'), - PersonRecognized: $t('person_recognized'), - }; - return labels[triggerType] || triggerType; - }; - - const formatTimestamp = (createdAt: string) => - new Intl.DateTimeFormat(undefined, { - dateStyle: 'medium', - timeStyle: 'short', - }).format(new Date(createdAt)); - const showWorkflowMenu = (event: MouseEvent, workflow: WorkflowResponseDto) => { const { ToggleEnabled, Edit, Delete } = getWorkflowActions($t, workflow); void menuManager.show({ @@ -92,12 +76,6 @@ -{#snippet chipItem(title: string)} - - {title} - -{/snippet} -
@@ -111,92 +89,77 @@ class="mx-auto mt-10" /> {:else} -
+
{#each workflows as workflow (workflow.id)} - - -
- - diff --git a/web/src/routes/(user)/workflows/[workflowId]/+page.svelte b/web/src/routes/(user)/workflows/[workflowId]/+page.svelte index 057ecdb72c4c2..050d9dd605b47 100644 --- a/web/src/routes/(user)/workflows/[workflowId]/+page.svelte +++ b/web/src/routes/(user)/workflows/[workflowId]/+page.svelte @@ -1,5 +1,5 @@ - + {data.workflow.name} {data.workflow.description} - - + +
+ + +
+ +
- - -
- -
- - {$t('workflow_info')} - + {#if editMode === 'visual'} + + +
+ +
+ + {$t('workflow_info')} + +
-
- + - - -
- - + + +
+ + + +
+ + + name ?? '', (value) => (name = value || null)} + /> -
+ +