mirror of
https://github.com/immich-app/immich.git
synced 2026-05-29 19:12:32 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 71dd3d092e |
@@ -7,7 +7,7 @@
|
||||
import { Route } from '$lib/route';
|
||||
import { getWorkflowActions, handleUpdateWorkflow } from '$lib/services/workflow.service';
|
||||
import { getTriggerDescription, getTriggerName } from '$lib/utils/workflow';
|
||||
import type { WorkflowResponseDto, WorkflowUpdateDto } from '@immich/sdk';
|
||||
import type { WorkflowResponseDto, WorkflowStepDto, WorkflowUpdateDto } from '@immich/sdk';
|
||||
import {
|
||||
ActionBar,
|
||||
AppShell,
|
||||
@@ -48,6 +48,8 @@
|
||||
import WorkflowJsonEditor from './WorkflowJsonEditor.svelte';
|
||||
import WorkflowStepCard from './WorkflowStepCard.svelte';
|
||||
import WorkflowSummary from './WorkflowSummary.svelte';
|
||||
import { flip } from 'svelte/animate';
|
||||
import { generateId } from '$lib/utils/generate-id';
|
||||
|
||||
type WorkflowJsonContent = Required<
|
||||
Pick<WorkflowUpdateDto, 'description' | 'enabled' | 'name' | 'steps' | 'trigger'>
|
||||
@@ -62,7 +64,8 @@
|
||||
let { data }: Props = $props();
|
||||
|
||||
let { id, enabled, name, description, trigger } = $derived(data.workflow);
|
||||
let steps = $state(data.workflow.steps);
|
||||
let steps = $state(data.workflow.steps.map((step) => ({ ...step, id: generateId() })));
|
||||
let tempSteps = $state<(WorkflowStepDto & { id: string })[]>();
|
||||
let savedWorkflow = $state(cloneDeep(data.workflow));
|
||||
let allowNavigation = $state(false);
|
||||
let isShowingNavigationDialog = $state(false);
|
||||
@@ -77,20 +80,23 @@
|
||||
name !== savedWorkflow.name ||
|
||||
description !== savedWorkflow.description ||
|
||||
!isEqual(trigger, savedWorkflow.trigger) ||
|
||||
!isEqual(steps, savedWorkflow.steps),
|
||||
!isEqual(
|
||||
steps.map(({ id: _, ...step }) => step),
|
||||
savedWorkflow.steps,
|
||||
),
|
||||
);
|
||||
|
||||
const handleAddStep = async () => {
|
||||
const step = await modalManager.show(WorkflowAddStepModal, { trigger });
|
||||
if (step) {
|
||||
steps.push(step);
|
||||
steps.push({ ...step, id: generateId() });
|
||||
}
|
||||
};
|
||||
|
||||
const handleInsertStep = async (index: number) => {
|
||||
const step = await modalManager.show(WorkflowAddStepModal, { trigger });
|
||||
if (step) {
|
||||
steps = [...steps.slice(0, index), step, ...steps.slice(index)];
|
||||
steps = [...steps.slice(0, index), { ...step, id: generateId() }, ...steps.slice(index)];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -102,23 +108,47 @@
|
||||
|
||||
const result = await modalManager.show(WorkflowEditStepModal, { trigger, step: cloneDeep(step) });
|
||||
if (result) {
|
||||
steps[index] = result;
|
||||
steps[index] = { ...result, id: generateId() };
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = (index: number, event: DragEvent) => {
|
||||
const handleDragEnd = (index: number, event: DragEvent) => {
|
||||
if (!event.dataTransfer) {
|
||||
return;
|
||||
}
|
||||
tempSteps = undefined;
|
||||
|
||||
const from = Number(event.dataTransfer.getData('text/plain'));
|
||||
|
||||
if (from === index) {
|
||||
return;
|
||||
}
|
||||
|
||||
const next = [...steps];
|
||||
const [moved] = next.splice(from, 1);
|
||||
next.splice(index, 0, moved);
|
||||
steps = next;
|
||||
};
|
||||
|
||||
const handleDragOver = (index: number, event: DragEvent) => {
|
||||
if (!event.dataTransfer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const from = Number(event.dataTransfer.getData('text/plain'));
|
||||
|
||||
if (from === index) {
|
||||
return;
|
||||
}
|
||||
|
||||
const next = [...steps];
|
||||
next.splice(index, 0, { ...next[from], id: generateId() });
|
||||
steps = next;
|
||||
event.dataTransfer.setData('text/plain', String(index));
|
||||
};
|
||||
|
||||
$effect(() => console.log(tempSteps));
|
||||
|
||||
const handleDeleteStep = async (index: number) => {
|
||||
const confirmed = await modalManager.showDialog({ title: $t('step_delete'), prompt: $t('step_delete_confirm') });
|
||||
if (confirmed) {
|
||||
@@ -131,7 +161,7 @@
|
||||
name = content.name;
|
||||
description = content.description;
|
||||
trigger = content.trigger;
|
||||
steps = cloneDeep(content.steps);
|
||||
steps = cloneDeep(content.steps).map((step) => ({ ...step, id: generateId() }));
|
||||
};
|
||||
|
||||
const onClose = () => goto(Route.workflows());
|
||||
@@ -344,15 +374,20 @@
|
||||
</CardHeader>
|
||||
</Card>
|
||||
|
||||
{#each steps as step, index (step.method + index)}
|
||||
<WorkflowStepCard
|
||||
{step}
|
||||
{index}
|
||||
onEdit={handleEditStep}
|
||||
onDelete={handleDeleteStep}
|
||||
onInsertBefore={handleInsertStep}
|
||||
onDrop={handleDrop}
|
||||
/>
|
||||
{#each tempSteps ?? steps as step, index (step.id)}
|
||||
<div class="w-full" animate:flip={{ duration: 120 }}>
|
||||
<WorkflowStepCard
|
||||
{step}
|
||||
{index}
|
||||
ghost={!!tempSteps}
|
||||
onEdit={handleEditStep}
|
||||
onDelete={handleDeleteStep}
|
||||
onInsertBefore={handleInsertStep}
|
||||
onDrop={() => {}}
|
||||
onDragOver={handleDragOver}
|
||||
onDragEnd={handleDragEnd}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<Button
|
||||
|
||||
@@ -1,26 +1,8 @@
|
||||
<script module lang="ts">
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import { getAlbumInfo } from '@immich/sdk';
|
||||
|
||||
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
||||
const albumNameCache = new Map<string, Promise<string>>();
|
||||
|
||||
const getAlbumName = (id: string): Promise<string> => {
|
||||
let albumName = albumNameCache.get(id);
|
||||
if (!albumName) {
|
||||
albumName = getAlbumInfo({ ...authManager.params, id })
|
||||
.then((album) => album.albumName)
|
||||
.catch(() => id);
|
||||
albumNameCache.set(id, albumName);
|
||||
}
|
||||
return albumName;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import { pluginManager } from '$lib/managers/plugin-manager.svelte';
|
||||
import type { JSONSchemaProperty } from '$lib/types';
|
||||
import type { WorkflowStepDto } from '@immich/sdk';
|
||||
import { getAlbumInfo, type WorkflowStepDto } from '@immich/sdk';
|
||||
import { Badge, Card, CardBody, CardDescription, CardHeader, CardTitle, Icon, IconButton } from '@immich/ui';
|
||||
import {
|
||||
mdiAutoFix,
|
||||
@@ -37,13 +19,16 @@
|
||||
type Props = {
|
||||
step: WorkflowStepDto;
|
||||
index: number;
|
||||
ghost: boolean;
|
||||
onEdit: (index: number) => void;
|
||||
onDelete: (index: number) => void;
|
||||
onInsertBefore: (index: number) => void;
|
||||
onDrop: (index: number, event: DragEvent) => void;
|
||||
onDragOver: (index: number, event: DragEvent) => void;
|
||||
onDragEnd: (index: number, event: DragEvent) => void;
|
||||
};
|
||||
|
||||
let { step, index, onEdit, onDelete, onInsertBefore, onDrop }: Props = $props();
|
||||
let { step, index, ghost, onEdit, onDelete, onInsertBefore, onDrop, onDragOver, onDragEnd }: Props = $props();
|
||||
|
||||
const method = $derived(pluginManager.getMethod(step.method));
|
||||
const isFilter = $derived(method?.uiHints?.includes('Filter') ?? false);
|
||||
@@ -58,6 +43,19 @@
|
||||
let isDropTarget = $state(false);
|
||||
let hoverDrag = $state(false);
|
||||
|
||||
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
||||
const albumNameCache = new Map<string, Promise<string>>();
|
||||
const getAlbumName = (id: string): Promise<string> => {
|
||||
let albumName = albumNameCache.get(id);
|
||||
if (!albumName) {
|
||||
albumName = getAlbumInfo({ ...authManager.params, id })
|
||||
.then((album) => album.albumName)
|
||||
.catch(() => id);
|
||||
albumNameCache.set(id, albumName);
|
||||
}
|
||||
return albumName;
|
||||
};
|
||||
|
||||
const truncate = (input: string, max = 24) => (input.length > max ? input.slice(0, max - 1) + '…' : input);
|
||||
|
||||
const formatConfigValue = (value: unknown): string => {
|
||||
@@ -115,23 +113,20 @@
|
||||
}
|
||||
event.preventDefault();
|
||||
|
||||
const from = Number(event.dataTransfer.getData('text/plain'));
|
||||
if (from === index) {
|
||||
return;
|
||||
}
|
||||
|
||||
onDrop(index, event);
|
||||
};
|
||||
|
||||
const handleDragOver = (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
isDropTarget = true;
|
||||
onDragOver(index, event);
|
||||
};
|
||||
|
||||
const handleDragEnd = () => {
|
||||
const handleDragEnd = (event: DragEvent) => {
|
||||
dragImage?.remove();
|
||||
dragImage = undefined;
|
||||
isDropTarget = false;
|
||||
onDragEnd(index, event);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user