Files
immich/server/src/utils/workflow.ts
T
Alex 8682be4774 feat: workflow template (#28553)
* 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

* feat: workflow template

* simplify

* move template to manifest

* feat: hash manifest file

* fix: template column

* fix: migration

* fix: workflow lookup

* chore: clean up

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2026-05-26 16:47:05 -04:00

69 lines
2.2 KiB
TypeScript

import { WorkflowTrigger, WorkflowType } from 'src/enum';
import { PluginMethodSearchResponse } from 'src/repositories/plugin.repository';
export const triggerMap: Record<WorkflowTrigger, WorkflowType[]> = {
[WorkflowTrigger.AssetCreate]: [WorkflowType.AssetV1],
[WorkflowTrigger.PersonRecognized]: [WorkflowType.AssetPersonV1],
};
export const getWorkflowTriggers = () =>
Object.entries(triggerMap).map(([trigger, types]) => ({ trigger: trigger as WorkflowTrigger, types }));
/** some types extend other types and have implied compatibility */
const inferredMap: Record<WorkflowType, WorkflowType[]> = {
[WorkflowType.AssetV1]: [],
[WorkflowType.AssetPersonV1]: [WorkflowType.AssetV1],
};
const withImpliedItems = (type: WorkflowType): WorkflowType[] => {
const childTypes = inferredMap[type];
const results = [type];
for (const child of childTypes) {
results.push(...withImpliedItems(child));
}
return results;
};
export const isMethodCompatible = (pluginMethod: { types: WorkflowType[] }, trigger: WorkflowTrigger) => {
const validTypes = triggerMap[trigger];
const pluginCompatibility = pluginMethod.types.map((type) => withImpliedItems(type));
for (const requested of validTypes) {
for (const pluginCompatibilityGroup of pluginCompatibility) {
if (pluginCompatibilityGroup.includes(requested)) {
return true;
}
}
}
return false;
};
export const resolveMethod = (methods: PluginMethodSearchResponse[], method: string) => {
const result = parseMethodString(method);
if (!result) {
return;
}
const { pluginName, methodName } = result;
return methods.find((method) => method.pluginName === pluginName && method.name === methodName);
};
export const asPluginKey = (method: { pluginName: string; name: string }) => {
return `${method.pluginName}#${method.name}`;
};
const METHOD_REGEX = /^(?<name>[^@#\s]+)(?:@(?<version>[^#\s]*))?#(?<method>[^@#\s]+)$/;
export const parseMethodString = (method: string) => {
const matches = METHOD_REGEX.exec(method);
if (!matches) {
return;
}
const pluginName = matches.groups?.name;
const version = matches.groups?.version;
const methodName = matches.groups?.method;
return { pluginName, version, methodName };
};