diff --git a/i18n/en.json b/i18n/en.json index e73ac13e60..e781b937a8 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -2417,6 +2417,7 @@ "use_browser_locale_description": "Format dates, times, and numbers based on your browser locale", "use_current_connection": "Use current connection", "use_custom_date_range": "Use custom date range instead", + "use_template": "Use template", "user": "User", "user_has_been_deleted": "This user has been deleted.", "user_id": "User ID", @@ -2491,6 +2492,7 @@ "workflow_name": "Workflow name", "workflow_navigation_prompt": "Are you sure you want to leave without saving your changes?", "workflow_summary": "Workflow summary", + "workflow_templates": "Workflow templates", "workflow_update_success": "Workflow updated successfully", "workflow_updated": "Workflow updated", "workflows": "Workflows", diff --git a/web/src/lib/modals/WorkflowTemplatePicker.svelte b/web/src/lib/modals/WorkflowTemplatePicker.svelte new file mode 100644 index 0000000000..95bb4c4eec --- /dev/null +++ b/web/src/lib/modals/WorkflowTemplatePicker.svelte @@ -0,0 +1,35 @@ + + + +
+ {#each workflowTemplates as template (template.id)} + (selected = template)}> +
+
+ +
+
+ {template.name} + {template.description} +
+
+
+ {/each} +
+
diff --git a/web/src/lib/services/workflow.service.ts b/web/src/lib/services/workflow.service.ts index 98e0383d2c..1634d74530 100644 --- a/web/src/lib/services/workflow.service.ts +++ b/web/src/lib/services/workflow.service.ts @@ -10,10 +10,11 @@ import { type WorkflowUpdateDto, } from '@immich/sdk'; import { modalManager, toastManager, type ActionItem } from '@immich/ui'; -import { mdiCodeJson, mdiDelete, mdiPause, mdiPencil, mdiPlay, mdiPlus } from '@mdi/js'; +import { mdiCodeJson, mdiDelete, mdiFileDocumentMultipleOutline, mdiPause, mdiPencil, mdiPlay, mdiPlus } from '@mdi/js'; import type { MessageFormatter } from 'svelte-i18n'; import { goto } from '$app/navigation'; import { eventManager } from '$lib/managers/event-manager.svelte'; +import WorkflowTemplatePicker from '$lib/modals/WorkflowTemplatePicker.svelte'; import { Route } from '$lib/route'; import { handleError } from '$lib/utils/handle-error'; import { getFormatter } from '$lib/utils/i18n'; @@ -33,7 +34,25 @@ export const getWorkflowsActions = ($t: MessageFormatter) => { }), }; - return { Create }; + const UseTemplate: ActionItem = { + title: $t('use_template'), + icon: mdiFileDocumentMultipleOutline, + onAction: async () => { + const template = await modalManager.show(WorkflowTemplatePicker, {}); + if (!template) { + return; + } + await handleCreateWorkflow({ + trigger: template.trigger, + steps: template.steps, + name: template.name, + description: template.description, + enabled: false, + }); + }, + }; + + return { Create, UseTemplate }; }; export const getWorkflowActions = ($t: MessageFormatter, workflow: WorkflowResponseDto) => { diff --git a/web/src/lib/templates/workflow-templates.ts b/web/src/lib/templates/workflow-templates.ts new file mode 100644 index 0000000000..cd70f347bf --- /dev/null +++ b/web/src/lib/templates/workflow-templates.ts @@ -0,0 +1,56 @@ +import { WorkflowTrigger, type WorkflowStepDto } from '@immich/sdk'; +import { mdiAccountGroupOutline, mdiMonitorScreenshot } from '@mdi/js'; + +export type WorkflowTemplate = { + id: string; + name: string; + description: string; + icon: string; + trigger: WorkflowTrigger; + steps: WorkflowStepDto[]; +}; + +export const workflowTemplates: WorkflowTemplate[] = [ + { + id: '1', + name: 'Archive screenshots to album', + description: 'Add uploads with "screenshot" in the filename to an album and archive them', + icon: mdiMonitorScreenshot, + trigger: WorkflowTrigger.AssetCreate, + steps: [ + { + method: 'immich-plugin-core#assetFileFilter', + config: { + pattern: 'screenshot', + matchType: 'contains', + caseSensitive: false, + }, + }, + { + method: 'immich-plugin-core#assetAddToAlbums', + config: { albumIds: [] }, + }, + { + method: 'immich-plugin-core#assetArchive', + config: { inverse: false }, + }, + ], + }, + { + id: '2', + name: 'Add person to album', + description: 'Add assets to an album when a specific person is recognized', + icon: mdiAccountGroupOutline, + trigger: WorkflowTrigger.PersonRecognized, + steps: [ + { + method: 'immich-plugin-core#filterPerson', + config: { personIds: [], matchAny: true }, + }, + { + method: 'immich-plugin-core#assetAddToAlbums', + config: { albumIds: [] }, + }, + ], + }, +]; diff --git a/web/src/routes/(user)/workflows/+page.svelte b/web/src/routes/(user)/workflows/+page.svelte index f4d4b67a33..49addc83d1 100644 --- a/web/src/routes/(user)/workflows/+page.svelte +++ b/web/src/routes/(user)/workflows/+page.svelte @@ -59,7 +59,7 @@ }); }; - const { Create } = $derived(getWorkflowsActions($t)); + const { Create, UseTemplate } = $derived(getWorkflowsActions($t)); const onWorkflowCreate = async (response: WorkflowResponseDto) => { await goto(Route.viewWorkflow(response)); @@ -76,7 +76,7 @@ - +
{#if workflows.length === 0}