diff --git a/src/modules/manager/workflowTemplates/components/TaskList.tsx b/src/modules/manager/workflowTemplates/components/TaskList.tsx index ef97b87..ffe7909 100644 --- a/src/modules/manager/workflowTemplates/components/TaskList.tsx +++ b/src/modules/manager/workflowTemplates/components/TaskList.tsx @@ -7,6 +7,7 @@ import AddTaskButton from "./AddTaskButton"; import { SelectableList } from "../../../../components/common/SelectableList"; import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { sortTasksTopologically } from "./workflowGraphUtils"; interface TaskListProps { tasks: TaskDefinition[]; @@ -34,18 +35,18 @@ const TaskList: React.FC = ({ }, }; - //if (tasks.length === 0) { onSelectTask(newTask); - //} onChange([...tasks, newTask]); }; + const sortedTasks = sortTasksTopologically(tasks); + return (
( <> diff --git a/src/modules/manager/workflowTemplates/components/workflowGraphUtils.ts b/src/modules/manager/workflowTemplates/components/workflowGraphUtils.ts index fd578d9..7c08c76 100644 --- a/src/modules/manager/workflowTemplates/components/workflowGraphUtils.ts +++ b/src/modules/manager/workflowTemplates/components/workflowGraphUtils.ts @@ -25,3 +25,41 @@ export const getAllDescendants = ( visit(guid); return descendants; }; + +export const sortTasksTopologically = ( + tasks: TaskDefinition[], +): TaskDefinition[] => { + // Build adjacency list: task -> its predecessors + const preds = new Map(); + const byId = new Map(); + + 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(); + const temp = new Set(); // 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; +};