Skip to content

Commit 7a272cf

Browse files
committed
group io in mermaid
1 parent d65bd65 commit 7a272cf

2 files changed

Lines changed: 27 additions & 2 deletions

File tree

src/WorkflowGraph/Visualization.Siren.fs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ module WorkflowGraphSiren =
106106
let elements = ResizeArray<FlowchartElement>()
107107
let edgeKeys = ResizeArray<string>()
108108

109+
let addGroupedNodes (groupId: string) (groupLabel: string) (nodes: WorkflowGraphNode []) =
110+
if nodes.Length > 0 then
111+
let grouped = ResizeArray<FlowchartElement>()
112+
nodes
113+
|> Array.iter (fun node -> grouped.Add(nodeToElement node))
114+
elements.Add(flowchart.subgraphNamed(groupId, quoteMermaidLabel groupLabel, grouped))
115+
109116
let addRenderedEdge (sourceNodeId: WorkflowGraphNodeId) (targetNodeId: WorkflowGraphNodeId) (label: string option) =
110117
let labelKey = defaultArg label ""
111118
let key = $"{sourceNodeId}::{targetNodeId}::{labelKey}"
@@ -184,9 +191,9 @@ module WorkflowGraphSiren =
184191
|> Map.tryFind stepNodeId
185192
|> Option.filter processingUnitNodeIds.Contains
186193

187-
rootInputNodes |> Array.iter (nodeToElement >> elements.Add)
194+
addGroupedNodes "wg_initial_inputs" "Initial Inputs" rootInputNodes
188195
processingUnitNodes |> Array.iter (nodeToElement >> elements.Add)
189-
rootOutputNodes |> Array.iter (nodeToElement >> elements.Add)
196+
addGroupedNodes "wg_final_outputs" "Workflow Outputs" rootOutputNodes
190197

191198
if hasCalls |> not && processingUnitNodeIds.Contains graph.RootProcessingUnitNodeId then
192199
for inputNode in rootInputNodes do

tests/WorkflowGraph/Visualization.Siren.Tests.fs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,24 @@ let tests_visualization =
122122
Expect.stringContains mermaid "port_unit_parent__in__child[child-port]" ""
123123
Expect.stringContains mermaid "port_unit_parent__in__child-->|child-port|unit_parent" ""
124124

125+
testCase "initial inputs and final outputs are rendered as groups" <| fun () ->
126+
let graph = buildSimpleWorkflowGraph ()
127+
let mermaid = WorkflowGraphSiren.toMermaid graph
128+
Expect.stringContains mermaid "subgraph wg_initial_inputs[Initial Inputs]" ""
129+
Expect.stringContains mermaid "subgraph wg_final_outputs[Workflow Outputs]" ""
130+
131+
testCase "group ordering keeps inputs above processing and outputs below" <| fun () ->
132+
let graph = buildSimpleWorkflowGraph ()
133+
let mermaid = WorkflowGraphSiren.toMermaid graph
134+
let inputGroupIndex = mermaid.IndexOf("subgraph wg_initial_inputs", System.StringComparison.Ordinal)
135+
let processingIndex = mermaid.IndexOf("unit_root__step1__run", System.StringComparison.Ordinal)
136+
let outputGroupIndex = mermaid.IndexOf("subgraph wg_final_outputs", System.StringComparison.Ordinal)
137+
Expect.isTrue (inputGroupIndex >= 0) "Input group missing"
138+
Expect.isTrue (processingIndex >= 0) "Processing node missing"
139+
Expect.isTrue (outputGroupIndex >= 0) "Output group missing"
140+
Expect.isTrue (inputGroupIndex < processingIndex) "Input group should be emitted before processing nodes"
141+
Expect.isTrue (processingIndex < outputGroupIndex) "Output group should be emitted after processing nodes"
142+
125143
testCaseCrossAsync "fromGraph workflow fixture contains processing units and labeled dependency edges" (crossAsync {
126144
let! content = FileSystemHelper.readFileTextAsync workflowFixturePath
127145
let graph = content |> Decode.decodeCWLProcessingUnit |> Builder.build

0 commit comments

Comments
 (0)