Skip to content

Commit 0259709

Browse files
committed
feat(ui): Add flow diagram views for workflows and folder groups
Introduce interactive flow diagram visualizations that display when selecting workflows or folders in the tree view, showing task sequences with conditions and connections.
1 parent 77756af commit 0259709

18 files changed

Lines changed: 1291 additions & 6 deletions

ui/src/components/workflow-visualizer/WorkflowVisualizer.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import './styles/index.css';
1414
// Extended selection types for tree view
1515
export type TreeSelectionType =
1616
| { type: 'none' }
17+
| { type: 'folder'; workflows: Workflow[]; name: string }
18+
| { type: 'workflow'; workflow: Workflow }
1719
| { type: 'workflow-condition'; workflow: Workflow; condition: JsonLogicValue }
1820
| { type: 'task'; task: Task; workflow: Workflow }
1921
| { type: 'task-condition'; task: Task; workflow: Workflow; condition: JsonLogicValue }
@@ -49,6 +51,16 @@ export interface WorkflowVisualizerProps {
4951
// Get display info for the current selection
5052
function getSelectionInfo(selection: TreeSelectionType): { title: string; subtitle: string } | null {
5153
switch (selection.type) {
54+
case 'folder':
55+
return {
56+
title: selection.name,
57+
subtitle: `${selection.workflows.length} Workflows`,
58+
};
59+
case 'workflow':
60+
return {
61+
title: selection.workflow.name,
62+
subtitle: 'Workflow Flow',
63+
};
5264
case 'workflow-condition':
5365
return {
5466
title: 'Workflow Condition',
@@ -136,7 +148,9 @@ function VisualizerInner({
136148
setSelection(newSelection);
137149

138150
// Fire callbacks for external consumers
139-
if (newSelection.type === 'workflow-condition') {
151+
if (newSelection.type === 'workflow') {
152+
onWorkflowSelect?.(newSelection.workflow);
153+
} else if (newSelection.type === 'workflow-condition') {
140154
onWorkflowSelect?.(newSelection.workflow);
141155
} else if (
142156
newSelection.type === 'task' ||
@@ -253,7 +267,7 @@ function VisualizerInner({
253267
</div>
254268
</div>
255269
)}
256-
<DetailsPanel selection={selection} />
270+
<DetailsPanel selection={selection} onSelect={handleSelection} />
257271
</div>
258272
</div>
259273
</div>

ui/src/components/workflow-visualizer/components/FolderNode.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
import { Folder } from 'lucide-react';
2+
import type { Workflow } from '../../../types';
23
import type { TreeSelectionType } from '../WorkflowVisualizer';
34
import type { FolderTreeNode } from '../utils/folderTree';
45
import { TreeNode } from './TreeNode';
56
import { WorkflowNode } from './WorkflowNode';
67
import { TREE_COLORS } from './colors';
78
import { NODE_IDS } from '../constants';
89

10+
function collectAllWorkflows(folder: FolderTreeNode): Workflow[] {
11+
const workflows = [...folder.workflows];
12+
for (const child of folder.folders.values()) {
13+
workflows.push(...collectAllWorkflows(child));
14+
}
15+
return workflows.sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));
16+
}
17+
918
interface FolderNodeProps {
1019
folder: FolderTreeNode;
1120
level: number;
@@ -42,10 +51,14 @@ export function FolderNode({
4251
icon={<Folder size={14} />}
4352
iconColor={TREE_COLORS.folder}
4453
isExpanded={isExpanded}
54+
isSelected={selection.type === 'folder' && selection.name === folder.name}
4555
hasChildren={hasChildren}
4656
level={level}
4757
onToggle={() => toggleNode(folderId)}
48-
onClick={() => toggleNode(folderId)}
58+
onClick={() => {
59+
onSelect({ type: 'folder', workflows: collectAllWorkflows(folder), name: folder.name });
60+
if (!isExpanded) toggleNode(folderId);
61+
}}
4962
>
5063
{/* Render child folders first (alphabetically) */}
5164
{sortedFolders.map((childFolder) => (

ui/src/components/workflow-visualizer/components/WorkflowNode.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,14 @@ export function WorkflowNode({
4242
icon={<Layers size={14} />}
4343
iconColor={TREE_COLORS.workflow}
4444
isExpanded={isExpanded}
45+
isSelected={selection.type === 'workflow' && selection.workflow.id === workflow.id}
4546
hasChildren={hasChildren}
4647
level={level}
4748
onToggle={() => toggleNode(workflowId)}
48-
onClick={() => toggleNode(workflowId)}
49+
onClick={() => {
50+
onSelect({ type: 'workflow', workflow });
51+
if (!isExpanded) toggleNode(workflowId);
52+
}}
4953
debugState={debugMode ? workflowDebugState.state : null}
5054
>
5155
{/* Workflow Condition */}

0 commit comments

Comments
 (0)