refactor: workflow queries (#32654)
(cherry picked from commit 98680ad6993ed917e630f8f4d1dbd1fbb6c41936)
This commit is contained in:
@@ -15,7 +15,6 @@ import type {
|
||||
AdminConfigDto,
|
||||
TagResponseDto,
|
||||
UserAdminResponseDto,
|
||||
WorkflowResponseDto,
|
||||
} from '@immich/sdk';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import { BaseEventManager } from '$lib/utils/base-event-manager.svelte';
|
||||
@@ -96,10 +95,6 @@ export type Events = {
|
||||
|
||||
JobCreate: [{ dto: JobCreateDto }];
|
||||
|
||||
WorkflowCreate: [WorkflowResponseDto];
|
||||
WorkflowUpdate: [WorkflowResponseDto];
|
||||
WorkflowDelete: [WorkflowResponseDto];
|
||||
|
||||
ReleaseEvent: [ReleaseEventV1];
|
||||
|
||||
WebsocketConnect: [];
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
getWorkflowTriggers,
|
||||
searchPluginMethods,
|
||||
searchPluginTemplates,
|
||||
WorkflowTrigger,
|
||||
type PluginMethodResponseDto,
|
||||
type PluginTemplateResponseDto,
|
||||
@@ -12,6 +9,9 @@ import { SvelteMap } from 'svelte/reactivity';
|
||||
import { get } from 'svelte/store';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import { queryClient } from '$lib/queries/client';
|
||||
import { searchPluginMethodsQuery, searchPluginTemplatesQuery } from '$lib/queries/plugin.query';
|
||||
import { getWorkflowTriggersQuery } from '$lib/queries/workflow.query';
|
||||
|
||||
class PluginManager {
|
||||
#loading: Promise<void> | undefined;
|
||||
@@ -78,9 +78,9 @@ class PluginManager {
|
||||
|
||||
private async load() {
|
||||
const [methods, triggers, templates] = await Promise.all([
|
||||
searchPluginMethods({}),
|
||||
getWorkflowTriggers(),
|
||||
searchPluginTemplates(),
|
||||
queryClient.query(searchPluginMethodsQuery()),
|
||||
queryClient.query(getWorkflowTriggersQuery()),
|
||||
queryClient.query(searchPluginTemplatesQuery()),
|
||||
]);
|
||||
|
||||
this.#methods = methods;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { searchPluginMethods, WorkflowTrigger, type PluginMethodResponseDto } from '@immich/sdk';
|
||||
import { WorkflowTrigger, type PluginMethodResponseDto } from '@immich/sdk';
|
||||
import { Badge, BasicModal, ListButton, LoadingSpinner, Stack, Text } from '@immich/ui';
|
||||
import { createQuery } from '@tanstack/svelte-query';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { queryClient } from '$lib/queries/client';
|
||||
import { searchPluginMethodsQuery } from '$lib/queries/plugin.query';
|
||||
|
||||
type Props = {
|
||||
trigger: WorkflowTrigger;
|
||||
@@ -10,16 +13,17 @@
|
||||
};
|
||||
|
||||
const { trigger, selectedKey, onClose }: Props = $props();
|
||||
|
||||
const query = createQuery(
|
||||
() => searchPluginMethodsQuery({ trigger }),
|
||||
() => queryClient,
|
||||
);
|
||||
</script>
|
||||
|
||||
<BasicModal title={$t('add_step')} onClose={() => onClose()} size="medium">
|
||||
{#await searchPluginMethods({ trigger })}
|
||||
<div class="flex w-full place-content-center place-items-center">
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
{:then methods}
|
||||
{#if query.data}
|
||||
<Stack>
|
||||
{#each methods as method (method.key)}
|
||||
{#each query.data as method (method.key)}
|
||||
<ListButton selected={method.key === selectedKey} onclick={() => onClose(method)}>
|
||||
<div class="grow text-start">
|
||||
<Text fontWeight="medium" class="flex items-center gap-1"
|
||||
@@ -37,5 +41,9 @@
|
||||
</ListButton>
|
||||
{/each}
|
||||
</Stack>
|
||||
{/await}
|
||||
{:else}
|
||||
<div class="flex w-full place-content-center place-items-center">
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
{/if}
|
||||
</BasicModal>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { executeMutation } from '$lib/queries/client';
|
||||
import { createWorkflowMutation } from '$lib/queries/workflow.query';
|
||||
import { Route } from '$lib/route';
|
||||
import { handleCreateWorkflow } from '$lib/services/workflow.service';
|
||||
import { WorkflowTrigger, type WorkflowResponseDto } from '@immich/sdk';
|
||||
import { Field, FormModal, Input, Textarea, VStack } from '@immich/ui';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -18,18 +19,16 @@
|
||||
let trigger = $state<WorkflowTrigger>(workflow.trigger);
|
||||
|
||||
const onSubmit = async () => {
|
||||
const response = await handleCreateWorkflow({
|
||||
name,
|
||||
description,
|
||||
trigger,
|
||||
steps: workflow.steps,
|
||||
enabled: false,
|
||||
});
|
||||
|
||||
if (response) {
|
||||
await goto(Route.viewWorkflow({ id: response.id }));
|
||||
onClose();
|
||||
}
|
||||
await executeMutation(
|
||||
createWorkflowMutation,
|
||||
[{ workflowCreateDto: { name, description, trigger, steps: workflow.steps, enabled: false } }],
|
||||
{
|
||||
onSuccess: (response) => {
|
||||
onClose();
|
||||
void goto(Route.viewWorkflow(response));
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { DateTime } from 'luxon';
|
||||
import { Route } from '$lib/route';
|
||||
import { handleUpdateWorkflow } from '$lib/services/workflow.service';
|
||||
import { executeMutation } from '$lib/queries/client';
|
||||
import { updateWorkflowMutation } from '$lib/queries/workflow.query';
|
||||
|
||||
type Props = {
|
||||
workflow: WorkflowResponseDto;
|
||||
@@ -37,14 +38,13 @@
|
||||
let hasNext = $state(true);
|
||||
let loading = $state(false);
|
||||
|
||||
const setLogging = async (logging: boolean) => {
|
||||
const success = await handleUpdateWorkflow(workflow.id, { logging });
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
workflow = { ...workflow, logging };
|
||||
reset();
|
||||
};
|
||||
const setLogging = (logging: boolean) =>
|
||||
executeMutation(updateWorkflowMutation, [{ id: workflow.id, workflowUpdateDto: { logging } }], {
|
||||
onSuccess: () => {
|
||||
workflow = { ...workflow, logging };
|
||||
reset();
|
||||
},
|
||||
});
|
||||
|
||||
const reset = () => {
|
||||
entries = [];
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { pluginManager } from '$lib/managers/plugin-manager.svelte';
|
||||
import { handleCreateWorkflow } from '$lib/services/workflow.service';
|
||||
import { executeMutation } from '$lib/queries/client';
|
||||
import { createWorkflowMutation } from '$lib/queries/workflow.query';
|
||||
import { Route } from '$lib/route';
|
||||
import { type PluginTemplateResponseDto } from '@immich/sdk';
|
||||
import { Badge, FormModal, Icon, ListButton, Text } from '@immich/ui';
|
||||
import { mdiFlashOutline } from '@mdi/js';
|
||||
@@ -19,17 +22,15 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const success = await handleCreateWorkflow({
|
||||
trigger: selected.trigger,
|
||||
steps: selected.steps,
|
||||
name: selected.title,
|
||||
description: selected.description,
|
||||
enabled: false,
|
||||
});
|
||||
const { trigger, steps, title: name, description } = selected;
|
||||
const workflowCreateDto = { trigger, steps, name, description, enabled: false };
|
||||
|
||||
if (success) {
|
||||
onClose();
|
||||
}
|
||||
await executeMutation(createWorkflowMutation, [{ workflowCreateDto }], {
|
||||
onSuccess: (response) => {
|
||||
onClose();
|
||||
void goto(Route.viewWorkflow(response));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const isSelected = (template: PluginTemplateResponseDto) => selected?.key === template.key;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { searchPluginMethods, searchPluginTemplates, type WorkflowTrigger } from '@immich/sdk';
|
||||
import { queryOptions } from '@tanstack/svelte-query';
|
||||
|
||||
export const searchPluginMethodsQuery = (filter: { trigger?: WorkflowTrigger } = {}) =>
|
||||
queryOptions({
|
||||
queryKey: ['plugins', 'methods', filter],
|
||||
queryFn: ({ signal }) => searchPluginMethods(filter, { signal }),
|
||||
});
|
||||
|
||||
export const searchPluginTemplatesQuery = () =>
|
||||
queryOptions({
|
||||
queryKey: ['plugins', 'templates'],
|
||||
queryFn: ({ signal }) => searchPluginTemplates({ signal }),
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
import {
|
||||
createWorkflow,
|
||||
deleteWorkflow,
|
||||
getWorkflowForShare,
|
||||
getWorkflowTriggers,
|
||||
searchWorkflows,
|
||||
updateWorkflow,
|
||||
type WorkflowResponseDto,
|
||||
} from '@immich/sdk';
|
||||
import { queryOptions } from '@tanstack/svelte-query';
|
||||
import { asMutation, queryClient } from '$lib/queries/client';
|
||||
|
||||
const findOrFail = (workflows: WorkflowResponseDto[], id: string) => {
|
||||
const workflow = workflows.find((workflow) => workflow.id === id);
|
||||
if (!workflow) {
|
||||
throw new Error(`Workflow ${id} not found`);
|
||||
}
|
||||
return workflow;
|
||||
};
|
||||
|
||||
export const searchWorkflowsQuery = () =>
|
||||
queryOptions({
|
||||
queryKey: ['workflows'],
|
||||
queryFn: ({ signal }) => searchWorkflows({}, { signal }),
|
||||
});
|
||||
|
||||
export const getWorkflowQuery = (id: string) =>
|
||||
queryOptions({
|
||||
...searchWorkflowsQuery(),
|
||||
select: (workflows) => findOrFail(workflows, id),
|
||||
});
|
||||
|
||||
export const getWorkflowForShareQuery = (id: string) =>
|
||||
queryOptions({
|
||||
queryKey: ['workflows', id, 'share'],
|
||||
queryFn: ({ signal }) => getWorkflowForShare({ id }, { signal }),
|
||||
staleTime: 0,
|
||||
});
|
||||
|
||||
export const getWorkflowTriggersQuery = () =>
|
||||
queryOptions({
|
||||
queryKey: ['workflows', 'triggers'],
|
||||
queryFn: ({ signal }) => getWorkflowTriggers({ signal }),
|
||||
});
|
||||
|
||||
export const createWorkflowMutation = () =>
|
||||
asMutation(createWorkflow, {
|
||||
onSuccess: (workflow) =>
|
||||
queryClient.setQueryData(searchWorkflowsQuery().queryKey, (workflows) =>
|
||||
workflows ? [...workflows, workflow] : workflows,
|
||||
),
|
||||
meta: { success: { toast: true }, error: { toast: 'errors.unable_to_create' } },
|
||||
});
|
||||
|
||||
export const updateWorkflowMutation = () =>
|
||||
asMutation(updateWorkflow, {
|
||||
onSuccess: (workflow) =>
|
||||
queryClient.setQueryData(searchWorkflowsQuery().queryKey, (workflows) =>
|
||||
workflows?.map((item) => (item.id === workflow.id ? workflow : item)),
|
||||
),
|
||||
meta: { success: { toast: 'workflow_update_success' }, error: { toast: 'errors.unable_to_update_workflow' } },
|
||||
});
|
||||
|
||||
export const deleteWorkflowMutation = () =>
|
||||
asMutation(deleteWorkflow, {
|
||||
onSuccess: (_, [{ id }]) => {
|
||||
queryClient.setQueryData(searchWorkflowsQuery().queryKey, (workflows) =>
|
||||
workflows?.filter((workflow) => workflow.id !== id),
|
||||
);
|
||||
queryClient.removeQueries({ queryKey: getWorkflowForShareQuery(id).queryKey });
|
||||
},
|
||||
meta: { success: { toast: 'workflow_deleted' }, error: { toast: 'errors.unable_to_delete_workflow' } },
|
||||
});
|
||||
@@ -1,13 +1,5 @@
|
||||
import {
|
||||
createWorkflow,
|
||||
deleteWorkflow,
|
||||
updateWorkflow,
|
||||
WorkflowTrigger,
|
||||
type WorkflowCreateDto,
|
||||
type WorkflowResponseDto,
|
||||
type WorkflowUpdateDto,
|
||||
} from '@immich/sdk';
|
||||
import { modalManager, toastManager, type ActionItem } from '@immich/ui';
|
||||
import { WorkflowTrigger, type WorkflowResponseDto } from '@immich/sdk';
|
||||
import { modalManager, type ActionItem } from '@immich/ui';
|
||||
import {
|
||||
mdiCodeJson,
|
||||
mdiContentCopy,
|
||||
@@ -23,13 +15,14 @@ import {
|
||||
} from '@mdi/js';
|
||||
import type { MessageFormatter } from 'svelte-i18n';
|
||||
import { goto } from '$app/navigation';
|
||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import { page } from '$app/state';
|
||||
import WorkflowDuplicateModal from '$lib/modals/WorkflowDuplicateModal.svelte';
|
||||
import WorkflowLogsModal from '$lib/modals/WorkflowLogsModal.svelte';
|
||||
import WorkflowTemplatePickerModal from '$lib/modals/WorkflowTemplatePickerModal.svelte';
|
||||
import { executeMutation } from '$lib/queries/client';
|
||||
import { createWorkflowMutation, deleteWorkflowMutation, updateWorkflowMutation } from '$lib/queries/workflow.query';
|
||||
import { Route } from '$lib/route';
|
||||
import { copyToClipboard, downloadJson } from '$lib/utils';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
|
||||
export const getWorkflowsActions = ($t: MessageFormatter) => {
|
||||
@@ -37,11 +30,11 @@ export const getWorkflowsActions = ($t: MessageFormatter) => {
|
||||
title: $t('create_workflow'),
|
||||
icon: mdiPlus,
|
||||
onAction: () =>
|
||||
handleCreateWorkflow({
|
||||
trigger: WorkflowTrigger.AssetCreate,
|
||||
steps: [],
|
||||
enabled: false,
|
||||
}),
|
||||
executeMutation(
|
||||
createWorkflowMutation,
|
||||
[{ workflowCreateDto: { trigger: WorkflowTrigger.AssetCreate, steps: [], enabled: false } }],
|
||||
{ onSuccess: (workflow) => void goto(Route.viewWorkflow(workflow)) },
|
||||
),
|
||||
};
|
||||
|
||||
const UseTemplate: ActionItem = {
|
||||
@@ -57,7 +50,8 @@ export const getWorkflowActions = ($t: MessageFormatter, workflow: WorkflowRespo
|
||||
const ToggleEnabled: ActionItem = {
|
||||
title: workflow.enabled ? $t('disable') : $t('enable'),
|
||||
icon: workflow.enabled ? mdiPause : mdiPlay,
|
||||
onAction: () => handleUpdateWorkflow(workflow.id, { enabled: !workflow.enabled }),
|
||||
onAction: () =>
|
||||
executeMutation(updateWorkflowMutation, [{ id: workflow.id, workflowUpdateDto: { enabled: !workflow.enabled } }]),
|
||||
};
|
||||
|
||||
const CopyJson: ActionItem = {
|
||||
@@ -133,34 +127,7 @@ export const getWorkflowShowSchemaAction = (
|
||||
onAction: onToggle,
|
||||
});
|
||||
|
||||
export const handleCreateWorkflow = async (dto: WorkflowCreateDto) => {
|
||||
const $t = await getFormatter();
|
||||
|
||||
try {
|
||||
const response = await createWorkflow({ workflowCreateDto: dto });
|
||||
eventManager.emit('WorkflowCreate', response);
|
||||
toastManager.success();
|
||||
return response;
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_create'));
|
||||
}
|
||||
};
|
||||
|
||||
export const handleUpdateWorkflow = async (id: string, dto: WorkflowUpdateDto) => {
|
||||
const $t = await getFormatter();
|
||||
|
||||
try {
|
||||
const response = await updateWorkflow({ id, workflowUpdateDto: dto });
|
||||
eventManager.emit('WorkflowUpdate', response);
|
||||
toastManager.primary($t('workflow_update_success'), { closable: true });
|
||||
return true;
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_update_workflow'));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const handleDeleteWorkflow = async (workflow: WorkflowResponseDto): Promise<boolean> => {
|
||||
const handleDeleteWorkflow = async (workflow: WorkflowResponseDto) => {
|
||||
const $t = await getFormatter();
|
||||
|
||||
const confirmed = await modalManager.showDialog({
|
||||
@@ -169,16 +136,14 @@ export const handleDeleteWorkflow = async (workflow: WorkflowResponseDto): Promi
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await deleteWorkflow({ id: workflow.id });
|
||||
eventManager.emit('WorkflowDelete', workflow);
|
||||
toastManager.primary($t('workflow_deleted'));
|
||||
return true;
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_delete_workflow'));
|
||||
return false;
|
||||
}
|
||||
await executeMutation(deleteWorkflowMutation, [{ id: workflow.id }], {
|
||||
onSuccess: () => {
|
||||
if (page.params.workflowId === workflow.id) {
|
||||
void goto(Route.workflows());
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import emptyWorkflows from '$lib/assets/empty-workflows.svg';
|
||||
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 { createPreloadedQuery, queryClient } from '$lib/queries/client';
|
||||
import { getWorkflowForShareQuery, searchWorkflowsQuery } from '$lib/queries/workflow.query';
|
||||
import { Route } from '$lib/route';
|
||||
import { getWorkflowActions, getWorkflowsActions, getWorkflowShowSchemaAction } from '$lib/services/workflow.service';
|
||||
import { getWorkflowForShare, type WorkflowResponseDto } from '@immich/sdk';
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
@@ -31,7 +30,8 @@
|
||||
|
||||
let { data }: Props = $props();
|
||||
|
||||
let workflows = $state<WorkflowResponseDto[]>(data.workflows);
|
||||
const query = createPreloadedQuery(searchWorkflowsQuery);
|
||||
const workflows = $derived(query.data);
|
||||
|
||||
const expandedIds = new SvelteSet<string>();
|
||||
|
||||
@@ -44,22 +44,8 @@
|
||||
};
|
||||
|
||||
const { Create, UseTemplate } = $derived(getWorkflowsActions($t));
|
||||
|
||||
const onWorkflowCreate = async (response: WorkflowResponseDto) => {
|
||||
await goto(Route.viewWorkflow(response));
|
||||
};
|
||||
|
||||
const onWorkflowUpdate = (response: WorkflowResponseDto) => {
|
||||
workflows = workflows.map((workflow) => (workflow.id === response.id ? response : workflow));
|
||||
};
|
||||
|
||||
const onWorkflowDelete = (response: WorkflowResponseDto) => {
|
||||
workflows = workflows.filter(({ id }) => id !== response.id);
|
||||
};
|
||||
</script>
|
||||
|
||||
<OnEvents {onWorkflowCreate} {onWorkflowUpdate} {onWorkflowDelete} />
|
||||
|
||||
<UserPageLayout title={data.meta.title} actions={[UseTemplate, Create]} scrollbar={false}>
|
||||
<section class="flex place-content-center sm:mx-4">
|
||||
<Container center size="large" class="pb-28">
|
||||
@@ -129,7 +115,7 @@
|
||||
</a>
|
||||
|
||||
{#if expandedIds.has(workflow.id)}
|
||||
{#await getWorkflowForShare({ id: workflow.id }) then result}
|
||||
{#await queryClient.query(getWorkflowForShareQuery(workflow.id)) then result}
|
||||
<div class="border-t border-gray-200 p-4 dark:border-gray-800">
|
||||
<CodeBlock code={JSON.stringify(result, null, 2)} lineNumbers />
|
||||
<Button
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { searchWorkflows } from '@immich/sdk';
|
||||
import { pluginManager } from '$lib/managers/plugin-manager.svelte';
|
||||
import { queryClient } from '$lib/queries/client';
|
||||
import { searchWorkflowsQuery } from '$lib/queries/workflow.query';
|
||||
import { authenticate } from '$lib/utils/auth';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import type { PageLoad } from './$types';
|
||||
@@ -7,11 +8,10 @@ import type { PageLoad } from './$types';
|
||||
export const load = (async ({ url }) => {
|
||||
await authenticate(url);
|
||||
|
||||
const [workflows] = await Promise.all([searchWorkflows({}), pluginManager.ready()]);
|
||||
await Promise.all([queryClient.query(searchWorkflowsQuery()), pluginManager.ready()]);
|
||||
const $t = await getFormatter();
|
||||
|
||||
return {
|
||||
workflows,
|
||||
meta: {
|
||||
title: $t('workflows'),
|
||||
},
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { beforeNavigate, goto, invalidate } from '$app/navigation';
|
||||
import OnEvents from '$lib/components/OnEvents.svelte';
|
||||
import { beforeNavigate, goto } from '$app/navigation';
|
||||
import WorkflowAddStepModal from '$lib/modals/WorkflowAddStepModal.svelte';
|
||||
import WorkflowEditStepModal from '$lib/modals/WorkflowEditStepModal.svelte';
|
||||
import WorkflowTriggerPicker from '$lib/modals/WorkflowTriggerPicker.svelte';
|
||||
import { createPreloadedQuery, executeMutation } from '$lib/queries/client';
|
||||
import { getWorkflowQuery, updateWorkflowMutation } from '$lib/queries/workflow.query';
|
||||
import { Route } from '$lib/route';
|
||||
import { getWorkflowActions, handleUpdateWorkflow } from '$lib/services/workflow.service';
|
||||
import { getWorkflowActions } from '$lib/services/workflow.service';
|
||||
import { generateId } from '$lib/utils/generate-id';
|
||||
import { getTriggerDescription, getTriggerName } from '$lib/utils/workflow';
|
||||
import type { WorkflowResponseDto, WorkflowUpdateDto } from '@immich/sdk';
|
||||
import type { WorkflowUpdateDto } from '@immich/sdk';
|
||||
import {
|
||||
ActionBar,
|
||||
AppShell,
|
||||
@@ -46,7 +47,7 @@
|
||||
import { cloneDeep, isEqual } from 'lodash-es';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { flip } from 'svelte/animate';
|
||||
import type { PageData } from './$types';
|
||||
import type { PageProps } from './$types';
|
||||
import WorkflowJsonEditor from './WorkflowJsonEditor.svelte';
|
||||
import WorkflowStepCard from './WorkflowStepCard.svelte';
|
||||
import WorkflowSummary from './WorkflowSummary.svelte';
|
||||
@@ -57,15 +58,14 @@
|
||||
|
||||
type EditMode = 'visual' | 'json';
|
||||
|
||||
type Props = {
|
||||
data: PageData;
|
||||
};
|
||||
let { params }: PageProps = $props();
|
||||
|
||||
let { data }: Props = $props();
|
||||
const query = createPreloadedQuery(() => getWorkflowQuery(params.workflowId));
|
||||
const workflow = $derived(query.data);
|
||||
|
||||
let { id, enabled, name, description, trigger } = $state(data.workflow);
|
||||
let steps = $state(data.workflow.steps.map((step) => ({ ...step, id: generateId() })));
|
||||
let savedWorkflow = $derived(cloneDeep(data.workflow));
|
||||
let { id, enabled, name, description, trigger } = $state(query.data);
|
||||
let steps = $state(query.data.steps.map((step) => ({ ...step, id: generateId() })));
|
||||
const savedWorkflow = $derived(cloneDeep(workflow));
|
||||
let allowNavigation = $state(false);
|
||||
let isShowingNavigationDialog = $state(false);
|
||||
let isSaving = $state(false);
|
||||
@@ -188,22 +188,6 @@
|
||||
}
|
||||
};
|
||||
|
||||
const onWorkflowUpdate = async (response: WorkflowResponseDto) => {
|
||||
if (id !== response.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.workflow = response;
|
||||
savedWorkflow = cloneDeep(response);
|
||||
await invalidate('workflow:data');
|
||||
};
|
||||
|
||||
const onWorkflowDelete = async (response: WorkflowResponseDto) => {
|
||||
if (id === response.id) {
|
||||
await goto(Route.workflows());
|
||||
}
|
||||
};
|
||||
|
||||
const confirmNavigation = async () => {
|
||||
if (!hasChanges) {
|
||||
return true;
|
||||
@@ -231,12 +215,9 @@
|
||||
|
||||
isSaving = true;
|
||||
try {
|
||||
const submitted = { enabled, name, description, trigger, steps: cloneDeep(steps) };
|
||||
const saved = await handleUpdateWorkflow(id, submitted);
|
||||
|
||||
if (saved) {
|
||||
Object.assign(savedWorkflow, submitted);
|
||||
}
|
||||
await executeMutation(updateWorkflowMutation, [
|
||||
{ id, workflowUpdateDto: { enabled, name, description, trigger, steps: cloneDeep(steps) } },
|
||||
]);
|
||||
} finally {
|
||||
isSaving = false;
|
||||
}
|
||||
@@ -270,8 +251,6 @@
|
||||
);
|
||||
</script>
|
||||
|
||||
<OnEvents {onWorkflowUpdate} {onWorkflowDelete} />
|
||||
|
||||
<AppShell class="">
|
||||
<AppShellBar>
|
||||
<ActionBar
|
||||
@@ -283,8 +262,8 @@
|
||||
actions={[Logs, Duplicate, CopyJson, Download, Delete].map((item) => ({ ...item, color: undefined }))}
|
||||
>
|
||||
<ControlBarHeader>
|
||||
<ControlBarTitle>{data.workflow.name}</ControlBarTitle>
|
||||
<ControlBarDescription>{data.workflow.description}</ControlBarDescription>
|
||||
<ControlBarTitle>{workflow.name}</ControlBarTitle>
|
||||
<ControlBarDescription>{workflow.description}</ControlBarDescription>
|
||||
</ControlBarHeader>
|
||||
<ControlBarContent class="flex items-center justify-end gap-6">
|
||||
{#if hasChanges}
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
import { searchWorkflows } from '@immich/sdk';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { pluginManager } from '$lib/managers/plugin-manager.svelte';
|
||||
import { queryClient } from '$lib/queries/client';
|
||||
import { getWorkflowQuery } from '$lib/queries/workflow.query';
|
||||
import { Route } from '$lib/route';
|
||||
import { authenticate } from '$lib/utils/auth';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load = (async ({ url, params, depends }) => {
|
||||
export const load = (async ({ url, params }) => {
|
||||
await authenticate(url);
|
||||
const [[workflow]] = await Promise.all([searchWorkflows({ id: params.workflowId }), pluginManager.ready()]);
|
||||
await Promise.all([
|
||||
queryClient.query(getWorkflowQuery(params.workflowId)).catch(() => redirect(307, Route.workflows())),
|
||||
pluginManager.ready(),
|
||||
]);
|
||||
const $t = await getFormatter();
|
||||
|
||||
if (!workflow) {
|
||||
redirect(307, Route.workflows());
|
||||
}
|
||||
|
||||
depends('workflow:data');
|
||||
|
||||
return {
|
||||
workflow,
|
||||
meta: {
|
||||
title: $t('edit_workflow'),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user