From 1e238e7a48267d5d338a74b8c6cfd23a2d508db1 Mon Sep 17 00:00:00 2001 From: Alex Tran Date: Fri, 5 Dec 2025 16:37:10 +0000 Subject: [PATCH] refactor ActionItem --- web/src/lib/services/workflow.service.ts | 116 +++++++++++++++- .../(user)/utilities/workflows/+page.svelte | 125 ++++++------------ 2 files changed, 152 insertions(+), 89 deletions(-) diff --git a/web/src/lib/services/workflow.service.ts b/web/src/lib/services/workflow.service.ts index 9f92f2021d..3fe4691c25 100644 --- a/web/src/lib/services/workflow.service.ts +++ b/web/src/lib/services/workflow.service.ts @@ -1,6 +1,12 @@ +import { goto } from '$app/navigation'; +import { AppRoute } from '$lib/constants'; +import { handleError } from '$lib/utils/handle-error'; +import { getFormatter } from '$lib/utils/i18n'; import { + createWorkflow, + deleteWorkflow, PluginTriggerType, - updateWorkflow as updateWorkflowApi, + updateWorkflow, type PluginActionResponseDto, type PluginContextType, type PluginFilterResponseDto, @@ -10,6 +16,9 @@ import { type WorkflowResponseDto, type WorkflowUpdateDto, } from '@immich/sdk'; +import { modalManager, toastManager, type ActionItem } from '@immich/ui'; +import { mdiCodeJson, mdiDelete, mdiPause, mdiPencil, mdiPlay } from '@mdi/js'; +import type { MessageFormatter } from 'svelte-i18n'; export interface WorkflowPayload { name: string; @@ -295,5 +304,108 @@ export const handleUpdateWorkflow = async ( triggerType, }; - return updateWorkflowApi({ id: workflowId, workflowUpdateDto: updateDto }); + return updateWorkflow({ id: workflowId, workflowUpdateDto: updateDto }); +}; + +export const getWorkflowActions = ($t: MessageFormatter, workflow: WorkflowResponseDto) => { + const ToggleEnabled: ActionItem = { + title: workflow.enabled ? $t('disable') : $t('enable'), + icon: workflow.enabled ? mdiPause : mdiPlay, + color: workflow.enabled ? 'danger' : 'primary', + onAction: async () => { + await handleToggleWorkflowEnabled(workflow); + }, + }; + + const Edit: ActionItem = { + title: $t('edit'), + icon: mdiPencil, + onAction: () => handleNavigateToWorkflow(workflow), + }; + + const Delete: ActionItem = { + title: $t('delete'), + icon: mdiDelete, + color: 'danger', + onAction: async () => { + await handleDeleteWorkflow(workflow); + }, + }; + + return { ToggleEnabled, Edit, Delete }; +}; + +export const getWorkflowShowSchemaAction = ( + $t: MessageFormatter, + isExpanded: boolean, + onToggle: () => void, +): ActionItem => ({ + title: isExpanded ? $t('hide_schema') : $t('show_schema'), + icon: mdiCodeJson, + onAction: onToggle, +}); + +export const handleCreateWorkflow = async (): Promise => { + const $t = await getFormatter(); + + try { + const workflow = await createWorkflow({ + workflowCreateDto: { + name: $t('untitled_workflow'), + triggerType: PluginTriggerType.AssetCreate, + filters: [], + actions: [], + enabled: false, + }, + }); + + await goto(`${AppRoute.WORKFLOWS}/${workflow.id}`); + return workflow; + } catch (error) { + handleError(error, $t('errors.unable_to_create')); + } +}; + +export const handleToggleWorkflowEnabled = async ( + workflow: WorkflowResponseDto, +): Promise => { + const $t = await getFormatter(); + + try { + const updated = await updateWorkflow({ + id: workflow.id, + workflowUpdateDto: { enabled: !workflow.enabled }, + }); + + toastManager.success($t('workflow_updated')); + return updated; + } catch (error) { + handleError(error, $t('errors.unable_to_update_workflow')); + } +}; + +export const handleDeleteWorkflow = async (workflow: WorkflowResponseDto): Promise => { + const $t = await getFormatter(); + + const confirmed = await modalManager.showDialog({ + prompt: $t('workflow_delete_prompt'), + confirmColor: 'danger', + }); + + if (!confirmed) { + return false; + } + + try { + await deleteWorkflow({ id: workflow.id }); + toastManager.success($t('workflow_deleted')); + return true; + } catch (error) { + handleError(error, $t('errors.unable_to_delete_workflow')); + return false; + } +}; + +export const handleNavigateToWorkflow = async (workflow: WorkflowResponseDto): Promise => { + await goto(`${AppRoute.WORKFLOWS}/${workflow.id}`); }; diff --git a/web/src/routes/(user)/utilities/workflows/+page.svelte b/web/src/routes/(user)/utilities/workflows/+page.svelte index 39f131aa29..af66adb31d 100644 --- a/web/src/routes/(user)/utilities/workflows/+page.svelte +++ b/web/src/routes/(user)/utilities/workflows/+page.svelte @@ -1,19 +1,16 @@ {#snippet chipItem(title: string)} @@ -232,37 +213,7 @@ color="secondary" icon={mdiDotsVertical} aria-label={$t('menu')} - onclick={(event: MouseEvent) => { - void menuManager.show({ - target: event.currentTarget as HTMLElement, - position: 'top-left', - items: [ - { - title: workflow.enabled ? $t('disable') : $t('enable'), - color: workflow.enabled ? 'danger' : 'primary', - icon: workflow.enabled ? mdiPause : mdiPlay, - onAction: () => void handleToggleEnabled(workflow), - }, - { - title: $t('edit'), - icon: mdiPencil, - onAction: () => void handleEditWorkflow(workflow), - }, - { - title: expandedWorkflows.has(workflow.id) ? $t('hide_schema') : $t('show_schema'), - icon: mdiCodeJson, - onAction: () => toggleShowingSchema(workflow.id), - }, - MenuItemType.Divider, - { - title: $t('delete'), - icon: mdiDelete, - color: 'danger', - onAction: () => void handleDeleteWorkflow(workflow), - }, - ], - }); - }} + onclick={(event: MouseEvent) => showWorkflowMenu(event, workflow)} />