Skip to content

Commit fb2169e

Browse files
committed
fix(Dashboard): refactoring if transitions
Signed-off-by: Jean-Baptiste Bianchi <[email protected]>
1 parent ef95e92 commit fb2169e

File tree

9 files changed

+101
-116
lines changed

9 files changed

+101
-116
lines changed

src/api/Synapse.Api.Http/Synapse.Api.Http.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@
4343
</ItemGroup>
4444

4545
<ItemGroup>
46-
<PackageReference Include="Neuroglia.Mediation.AspNetCore" Version="4.18.0" />
47-
<PackageReference Include="Neuroglia.Security.AspNetCore" Version="4.18.0" />
48-
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.1.0" />
46+
<PackageReference Include="Neuroglia.Mediation.AspNetCore" Version="4.16.1" />
47+
<PackageReference Include="Neuroglia.Security.AspNetCore" Version="4.16.1" />
48+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.0.0" />
4949
</ItemGroup>
5050

5151
<ItemGroup>

src/core/Synapse.Core.Infrastructure/Synapse.Core.Infrastructure.csproj

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,13 @@
4444

4545
<ItemGroup>
4646
<PackageReference Include="IdentityModel" Version="7.0.0" />
47-
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" />
48-
<PackageReference Include="Neuroglia.Data.Expressions.Abstractions" Version="4.18.0" />
49-
<PackageReference Include="Neuroglia.Data.Infrastructure.Redis" Version="4.18.0" />
50-
<PackageReference Include="Neuroglia.Data.Infrastructure.ResourceOriented.Redis" Version="4.18.0" />
51-
<PackageReference Include="Neuroglia.Mediation" Version="4.18.0" />
52-
<PackageReference Include="Neuroglia.Plugins" Version="4.18.0" />
53-
<PackageReference Include="Neuroglia.Serialization.Xml" Version="4.18.0" />
54-
<PackageReference Include="ServerlessWorkflow.Sdk.IO" Version="1.0.0-alpha5.2" />
47+
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.0" />
48+
<PackageReference Include="Neuroglia.Data.Expressions.Abstractions" Version="4.16.1" />
49+
<PackageReference Include="Neuroglia.Data.Infrastructure.Redis" Version="4.16.1" />
50+
<PackageReference Include="Neuroglia.Data.Infrastructure.ResourceOriented.Redis" Version="4.16.1" />
51+
<PackageReference Include="Neuroglia.Mediation" Version="4.16.1" />
52+
<PackageReference Include="Neuroglia.Plugins" Version="4.16.1" />
53+
<PackageReference Include="ServerlessWorkflow.Sdk.IO" Version="1.0.0-alpha5.1" />
5554
</ItemGroup>
5655

5756
<ItemGroup>

src/core/Synapse.Core/Synapse.Core.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@
6767
<PackageReference Include="Apache.Avro" Version="1.12.0" />
6868
<PackageReference Include="Docker.DotNet" Version="3.125.15" />
6969
<PackageReference Include="KubernetesClient" Version="15.0.1" />
70-
<PackageReference Include="Neuroglia.Data.Infrastructure.ResourceOriented" Version="4.18.0" />
71-
<PackageReference Include="Neuroglia.Eventing.CloudEvents" Version="4.18.0" />
70+
<PackageReference Include="Neuroglia.Data.Infrastructure.ResourceOriented" Version="4.16.1" />
71+
<PackageReference Include="Neuroglia.Eventing.CloudEvents" Version="4.16.1" />
7272
<PackageReference Include="Semver" Version="3.0.0" />
7373
<PackageReference Include="ServerlessWorkflow.Sdk" Version="1.0.0-alpha5.2" />
7474
</ItemGroup>

src/correlator/Synapse.Correlator/Synapse.Correlator.csproj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@
3636
<PackageReference Include="Microsoft.Extensions.Configuration.KeyPerFile" Version="9.0.0" />
3737
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
3838
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
39-
<PackageReference Include="Neuroglia.Data.Expressions.JavaScript" Version="4.18.0" />
40-
<PackageReference Include="Neuroglia.Data.Expressions.JQ" Version="4.18.0" />
41-
<PackageReference Include="Neuroglia.Eventing.CloudEvents.AspNetCore" Version="4.18.0" />
42-
<PackageReference Include="Neuroglia.Mediation.AspNetCore" Version="4.18.0" />
43-
<PackageReference Include="Neuroglia.Eventing.CloudEvents.Infrastructure" Version="4.18.0" />
44-
<PackageReference Include="Neuroglia.Security.AspNetCore" Version="4.18.0" />
45-
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.1.0" />
46-
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.1.0" />
39+
<PackageReference Include="Neuroglia.Data.Expressions.JavaScript" Version="4.16.1" />
40+
<PackageReference Include="Neuroglia.Data.Expressions.JQ" Version="4.16.1" />
41+
<PackageReference Include="Neuroglia.Eventing.CloudEvents.AspNetCore" Version="4.16.1" />
42+
<PackageReference Include="Neuroglia.Mediation.AspNetCore" Version="4.16.1" />
43+
<PackageReference Include="Neuroglia.Eventing.CloudEvents.Infrastructure" Version="4.16.1" />
44+
<PackageReference Include="Neuroglia.Security.AspNetCore" Version="4.16.1" />
45+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.0.0" />
46+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.0.0" />
4747
</ItemGroup>
4848

4949
<ItemGroup>

src/dashboard/Synapse.Dashboard/Pages/Workflows/Create/State.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
// limitations under the License.
1313

1414
using ServerlessWorkflow.Sdk.Models;
15-
using Synapse.Resources;
1615

1716
namespace Synapse.Dashboard.Pages.Workflows.Create;
1817

src/dashboard/Synapse.Dashboard/Services/WorkflowGraphBuilder.cs

Lines changed: 69 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
using ServerlessWorkflow.Sdk.Models;
1818
using ServerlessWorkflow.Sdk.Models.Calls;
1919
using ServerlessWorkflow.Sdk.Models.Tasks;
20-
using Synapse.Dashboard.Components.DocumentDetailsStateManagement;
2120
using System.Diagnostics;
2221

2322
namespace Synapse.Dashboard.Services;
@@ -32,7 +31,8 @@ public class WorkflowGraphBuilder(ILogger<WorkflowGraphBuilder> logger, IYamlSer
3231
: IWorkflowGraphBuilder
3332
{
3433

35-
const string _portSuffix = "-port";
34+
const string _clusterEntrySuffix = "-cluster-entry";
35+
const string _clusterExitSuffix = "-cluster-exit";
3636
const string _trySuffix = "-try";
3737
const string _catchSuffix = "-catch";
3838
const double characterSize = 8d;
@@ -78,65 +78,51 @@ public IGraphViewModel Build(WorkflowDefinition workflow)
7878
nextNode = (NodeViewModel)clusterViewModel.AllNodes.Values.First();
7979
}
8080
}
81-
this.BuildEdge(graph, startNode, nextNode);
8281
sw.Stop();
8382
this.Logger.LogTrace("WorkflowGraphBuilder.Build took {elapsedTime} ms", sw.ElapsedMilliseconds);
8483
return graph;
8584
}
8685

87-
/// <summary>
88-
/// Builds a new start <see cref="NodeViewModel"/>
89-
/// </summary>
90-
/// <param name="hasSuccessor">A boolean indicating whether or not the node has successor</param>
91-
/// <returns>A new <see cref="NodeViewModel"/></returns>
92-
protected virtual NodeViewModel BuildStartNode(bool hasSuccessor = false) => new StartNodeViewModel(hasSuccessor);
86+
protected record TaskContext(ClusterViewModel? taskGroup, int taskIndex, string taskName, TaskDefinition definition)
87+
{
88+
public virtual int? Index { get; } = taskIndex;
89+
public virtual string? Name { get; } = taskName;
90+
public virtual TaskDefinition? Definition { get; } = definition;
91+
}
9392

94-
/// <summary>
95-
/// Returns the name, index and reference of the next node
96-
/// </summary>
97-
/// <param name="context">The rendering context for the task nodes</param>
98-
/// <param name="ignoreConditionalTasks">If true, skips <see cref="TaskDefinition"/> with an if clause</param>
99-
/// <param name="transition">A transition, if different from the context task definition's</param>
100-
/// <returns>The next task <see cref="TaskIdentity"/></returns>
101-
protected TaskIdentity? GetNextTaskIdentity(TaskNodeRenderingContext context, bool ignoreConditionalTasks, string? transition = null)
93+
protected record RenderingContext(WorkflowDefinition workflow, GraphViewModel graph, Map<string, TaskDefinition> tasksList, INodeViewModel node, TaskContext? task = null, RenderingContext? parent = null, INodeViewModel? entryNode = null, INodeViewModel? exitNode = null)
10294
{
103-
transition = !string.IsNullOrWhiteSpace(transition) ? transition : context.TaskDefinition.Then;
104-
if (transition == FlowDirective.End) return null;
105-
if (transition == FlowDirective.Exit)
95+
public virtual WorkflowDefinition Workflow { get; } = workflow;
96+
public virtual GraphViewModel Graph { get; } = graph;
97+
public virtual Map<string, TaskDefinition> TasksList { get; } = tasksList;
98+
public virtual RenderingContext? Parent { get; } = parent;
99+
public virtual TaskContext? Task { get; } = task;
100+
public virtual INodeViewModel Node { get; } = node;
101+
public virtual INodeViewModel EntryNode { get; } = entryNode;
102+
public virtual INodeViewModel ExitNode { get; } = exitNode;
103+
}
104+
105+
protected virtual void BuildTransitions(RenderingContext context)
106+
{
107+
Map<string, TaskDefinition> transitions = [];
108+
MapEntry<string, TaskDefinition>? nextTask = this.GetNextTask(context.TasksList, context.Task?.Name);
109+
if (nextTask != null)
106110
{
107-
if (context.ParentContext == null)
111+
transitions.Add(nextTask);
112+
while (!string.IsNullOrWhiteSpace(nextTask?.Value.If))
108113
{
109-
return null;
114+
nextTask = this.GetNextTask(context.TasksList, nextTask.Key);
115+
if (nextTask != null)
116+
{
117+
transitions.Add(nextTask);
118+
}
110119
}
111-
return this.GetNextTaskIdentity(context.ParentContext, ignoreConditionalTasks);
112120
}
113-
var nextTaskName = string.IsNullOrWhiteSpace(transition) || transition == FlowDirective.Continue
114-
? context.Workflow.GetTaskAfter(new(context.TaskName, context.TaskDefinition), context.ParentReference, ignoreConditionalTasks)?.Key
115-
: transition;
116-
if (string.IsNullOrWhiteSpace(nextTaskName))
121+
foreach (var transition in transitions)
117122
{
118-
if (context.ParentContext == null)
119-
{
120-
return null;
121-
}
122-
return this.GetNextTaskIdentity(context.ParentContext, ignoreConditionalTasks);
123-
}
124-
var nextTaskIndex = context.Workflow.IndexOf(nextTaskName, context.ParentReference);
125-
var nextTaskReference = $"{context.ParentReference}/{nextTaskIndex}/{nextTaskName}";
126-
return new(nextTaskName, nextTaskIndex, nextTaskReference, context);
127-
}
123+
var transitionNode = this.BuildTaskNode();
124+
this.BuildEdge(context.Graph, context.Node, transitionNode);
128125

129-
/// <summary>
130-
/// Gets a <see cref="NodeViewModel"/> by reference in the provided <see cref="TaskNodeRenderingContext"/>
131-
/// </summary>
132-
/// <param name="context">The source <see cref="TaskNodeRenderingContext"/></param>
133-
/// <param name="reference">The reference to look for</param>
134-
/// <returns></returns>
135-
protected NodeViewModel GetNodeByReference(TaskNodeRenderingContext context, string reference)
136-
{
137-
if (context.Graph.AllClusters.ContainsKey(reference))
138-
{
139-
return (NodeViewModel)context.Graph.AllClusters[reference].AllNodes.First().Value;
140126
}
141127
if (context.Graph.AllNodes.ContainsKey(reference))
142128
{
@@ -145,36 +131,32 @@ protected NodeViewModel GetNodeByReference(TaskNodeRenderingContext context, str
145131
throw new IndexOutOfRangeException($"Unable to find the task with reference '{reference}' in the provided context.");
146132
}
147133

148-
/// <summary>
149-
/// Gets the next <see cref="NodeViewModel"/> in the graph
150-
/// </summary>
151-
/// <param name="context">The rendering context for the task nodes</param>
152-
/// <param name="currentNode">The current task node</param>
153-
/// <param name="ignoreConditionalTasks">If true, skips <see cref="TaskDefinition"/> with an if clause</param>
154-
/// <param name="transition">A transition, if different from the context task definition's</param>
155-
/// <returns>The next task <see cref="NodeViewModel"/></returns>
156-
/// <exception cref="Exception"></exception>
157-
protected NodeViewModel GetNextNode(TaskNodeRenderingContext context, NodeViewModel currentNode, bool ignoreConditionalTasks = false, string? transition = null)
134+
protected virtual MapEntry<string, TaskDefinition>? GetNextTask(Map<string, TaskDefinition> tasksList, string? taskName, string? transition = null) //RenderingContext context, string? transition = null)
158135
{
159-
var nextTaskIdentity = this.GetNextTaskIdentity(context, ignoreConditionalTasks, transition);
160-
if (nextTaskIdentity == null)
136+
if (transition == FlowDirective.End || transition == FlowDirective.Exit) return null;
137+
int index;
138+
if (!string.IsNullOrWhiteSpace(transition) && transition != FlowDirective.Continue)
161139
{
162-
return context.EndNode;
140+
index = tasksList.Keys.ToList().IndexOf(transition);
163141
}
164-
var nextTask = context.Workflow.GetComponent<TaskDefinition>(nextTaskIdentity.Reference) ?? throw new Exception($"Failed to find the task at '{nextTaskIdentity.Reference}' in workflow '{context.Workflow.Document.Name}.{context.Workflow.Document.Namespace}:{context.Workflow.Document.Version}'");
165-
if (!context.Graph.AllNodes.ContainsKey(nextTaskIdentity.Reference) && !context.Graph.AllClusters.ContainsKey(nextTaskIdentity.Reference))
142+
else if (!string.IsNullOrWhiteSpace(taskName))
166143
{
167-
this.BuildTaskNode(new(nextTaskIdentity.Context.Workflow, nextTaskIdentity.Context.Graph, nextTaskIdentity.Index, nextTaskIdentity.Name, nextTask, nextTaskIdentity.Context.TaskGroup, nextTaskIdentity.Context.ParentReference, nextTaskIdentity.Context.ParentContext, nextTaskIdentity.Context.EndNode, currentNode));
144+
index = tasksList.Keys.ToList().IndexOf(taskName) + 1;
168145
}
169-
if (string.IsNullOrEmpty(nextTask.If))
146+
else
170147
{
171-
return this.GetNodeByReference(context, nextTaskIdentity.Reference);
148+
index = 0;
172149
}
173-
var nextNode = this.GetNodeByReference(context, nextTaskIdentity.Reference);
174-
this.BuildEdge(context.Graph, currentNode, nextNode);
175-
return this.GetNextNode(context, currentNode, true, transition);
150+
return tasksList.ElementAt(index);
176151
}
177152

153+
/// <summary>
154+
/// Builds a new start <see cref="NodeViewModel"/>
155+
/// </summary>
156+
/// <param name="hasSuccessor">A boolean indicating whether or not the node has successor</param>
157+
/// <returns>A new <see cref="NodeViewModel"/></returns>
158+
protected virtual NodeViewModel BuildStartNode(bool hasSuccessor = false) => new StartNodeViewModel(hasSuccessor);
159+
178160
/// <summary>
179161
/// Builds a new <see cref="WorkflowClusterViewModel"/> for the specified task
180162
/// </summary>
@@ -263,25 +245,30 @@ protected virtual NodeViewModel BuildDoTaskNode(TaskNodeRenderingContext<DoTaskD
263245
ArgumentNullException.ThrowIfNull(context);
264246
var taskCount = context.TaskDefinition.Do.Count;
265247
var cluster = new DoTaskNodeViewModel(context.TaskReference, context.TaskName, $"{taskCount} task{(taskCount > 1 ? "s" : "")}");
266-
var port = new PortNodeViewModel(context.TaskReference + _portSuffix);
267-
cluster.AddChild(port);
248+
var entryPort = new PortNodeViewModel(context.TaskReference + _clusterEntrySuffix);
249+
var exitPort = new PortNodeViewModel(context.TaskReference + _clusterExitSuffix);
250+
cluster.AddChild(entryPort);
251+
cluster.AddChild(exitPort);
268252
if (context.TaskGroup == null) context.Graph.AddCluster(cluster);
269253
else context.TaskGroup.AddChild(cluster);
270254
var innerContext = new TaskNodeRenderingContext(context.Workflow, context.Graph, 0, context.TaskDefinition.Do.First().Key, context.TaskDefinition.Do.First().Value, cluster, context.TaskReference + "/do", context, context.EndNode, context.PreviousNode);
271255
this.BuildTaskNode(innerContext);
272256
if (taskCount > 0)
273257
{
274-
var firstDoNode = (NodeViewModel)cluster.AllNodes.Skip(1).First().Value;
275-
this.BuildEdge(context.Graph, port, firstDoNode);
258+
var firstDoNode = (NodeViewModel)cluster.AllNodes.Skip(2).First().Value;
259+
var lastDoNode = (NodeViewModel)cluster.AllNodes.Last().Value;
260+
this.BuildEdge(context.Graph, entryPort, firstDoNode);
261+
this.BuildEdge(context.Graph, lastDoNode, exitPort);
276262
if (taskCount > 1 && !string.IsNullOrWhiteSpace(context.TaskDefinition.Do.First().Value.If))
277263
{
278-
this.BuildEdge(context.Graph, port, this.GetNextNode(innerContext, firstDoNode));
264+
this.BuildEdge(context.Graph, entryPort, this.GetNextNode(innerContext, firstDoNode));
279265
}
280266
}
281267
else
282268
{
283-
this.BuildEdge(context.Graph, port, this.GetNextNode(context, cluster));
269+
this.BuildEdge(context.Graph, entryPort, exitPort);
284270
}
271+
this.BuildEdge(context.Graph, exitPort, this.GetNextNode(context, cluster));
285272
return cluster;
286273
}
287274

@@ -324,7 +311,7 @@ protected virtual NodeViewModel BuildForTaskNode(TaskNodeRenderingContext<ForTas
324311
{
325312
ArgumentNullException.ThrowIfNull(context);
326313
var cluster = new ForTaskNodeViewModel(context.TaskReference, context.TaskName, this.YamlSerializer.SerializeToText(context.TaskDefinition.For));
327-
var port = new PortNodeViewModel(context.TaskReference + _portSuffix);
314+
var port = new PortNodeViewModel(context.TaskReference + _clusterEntrySuffix);
328315
cluster.AddChild(port);
329316
if (context.TaskGroup == null) context.Graph.AddCluster(cluster);
330317
else context.TaskGroup.AddChild(cluster);
@@ -349,8 +336,8 @@ protected virtual NodeViewModel BuildForkTaskNode(TaskNodeRenderingContext<ForkT
349336
{
350337
ArgumentNullException.ThrowIfNull(context);
351338
var cluster = new ForkTaskNodeViewModel(context.TaskReference, context.TaskName, this.YamlSerializer.SerializeToText(context.TaskDefinition.Fork));
352-
var entryPort = new PortNodeViewModel(context.TaskReference + _portSuffix);
353-
var exitPort = new PortNodeViewModel(context.TaskReference + "-exit" + _portSuffix);
339+
var entryPort = new PortNodeViewModel(context.TaskReference + _clusterEntrySuffix);
340+
var exitPort = new PortNodeViewModel(context.TaskReference + "-exit" + _clusterExitSuffix);
354341
cluster.AddChild(entryPort);
355342
if (context.TaskGroup == null) context.Graph.AddCluster(cluster);
356343
else context.TaskGroup.AddChild(cluster);
@@ -499,13 +486,13 @@ protected virtual NodeViewModel BuildTryTaskNode(TaskNodeRenderingContext<TryTas
499486
ArgumentNullException.ThrowIfNull(context);
500487
var taskCount = context.TaskDefinition.Try.Count;
501488
var containerCluster = new TryTaskNodeViewModel(context.TaskReference, context.TaskName, $"{taskCount} task{(taskCount > 1 ? "s" : "")}");
502-
var containerPort = new PortNodeViewModel(context.TaskReference + _portSuffix);
489+
var containerPort = new PortNodeViewModel(context.TaskReference + _clusterEntrySuffix);
503490
containerCluster.AddChild(containerPort);
504491
if (context.TaskGroup == null) context.Graph.AddCluster(containerCluster);
505492
else context.TaskGroup.AddChild(containerCluster);
506493

507494
var tryCluster = new TryNodeViewModel(context.TaskReference + _trySuffix, context.TaskName, string.Empty);
508-
var tryPort = new PortNodeViewModel(context.TaskReference + _trySuffix + _portSuffix);
495+
var tryPort = new PortNodeViewModel(context.TaskReference + _trySuffix + _clusterEntrySuffix);
509496
tryCluster.AddChild(tryPort);
510497
containerCluster.AddChild(tryCluster);
511498
this.BuildEdge(context.Graph, containerPort, tryPort);
@@ -531,7 +518,7 @@ protected virtual NodeViewModel BuildTryTaskNode(TaskNodeRenderingContext<TryTas
531518
else
532519
{
533520
var catchCluster = new CatchDoNodeViewModel(context.TaskReference + _catchSuffix, context.TaskName, catchContent);
534-
var catchPort = new PortNodeViewModel(context.TaskReference + _catchSuffix + _portSuffix);
521+
var catchPort = new PortNodeViewModel(context.TaskReference + _catchSuffix + _clusterEntrySuffix);
535522
catchCluster.AddChild(catchPort);
536523
containerCluster.AddChild(catchCluster);
537524
this.BuildEdge(context.Graph, tryCluster.AllNodes.Values.Last(), catchPort);
@@ -588,7 +575,7 @@ protected virtual IEdgeViewModel BuildEdge(IGraphViewModel graph, INodeViewModel
588575
edge.LabelPosition = EdgeLabelPosition.Center;
589576
edge.Width = edge.Label.Length * characterSize;
590577
}
591-
if (target.Id.EndsWith(_portSuffix))
578+
if (target.Id.EndsWith(_clusterEntrySuffix))
592579
{
593580
edge.EndMarkerId = null;
594581
}

0 commit comments

Comments
 (0)