webui/src/modules/manager/workflowTemplates/components/workflowGraphUtils.ts

66 lines
1.7 KiB
TypeScript

import { TaskDefinition } from "../services/WorkflowTemplateService";
export const getAllDescendants = (
guid: string,
tasks: TaskDefinition[],
): Set<string> => {
const descendants = new Set<string>();
const visit = (current: string) => {
for (const t of tasks) {
const preds = (t.config.predecessors as string[]) ?? [];
// If t depends on current, it's a child
if (
preds.includes(current) &&
!descendants.has(t.config.guid as string)
) {
const childGuid = t.config.guid as string;
descendants.add(childGuid);
visit(childGuid); // recursively find grandchildren
}
}
};
visit(guid);
return descendants;
};
export const sortTasksTopologically = (
tasks: TaskDefinition[],
): TaskDefinition[] => {
// Build adjacency list: task -> its predecessors
const preds = new Map<string, string[]>();
const byId = new Map<string, TaskDefinition>();
tasks.forEach((t) => {
const guid = t.config.guid as string;
byId.set(guid, t);
preds.set(guid, (t.config.predecessors as string[]) ?? []);
});
const result: TaskDefinition[] = [];
const visited = new Set<string>();
const temp = new Set<string>(); // for cycle detection (should never trigger now)
const visit = (guid: string) => {
if (visited.has(guid)) return;
if (temp.has(guid)) throw new Error("Cycle detected unexpectedly");
temp.add(guid);
for (const p of preds.get(guid) ?? []) {
visit(p);
}
temp.delete(guid);
visited.add(guid);
result.push(byId.get(guid)!);
};
// Visit all tasks
tasks.forEach((t) => visit(t.config.guid as string));
return result;
};