Skip to content

Commit 36ef782

Browse files
committed
fix(Dashboard): handled conditional tasks in the graph
Signed-off-by: Jean-Baptiste Bianchi <[email protected]>
1 parent 9c6de69 commit 36ef782

File tree

2 files changed

+58
-18
lines changed

2 files changed

+58
-18
lines changed

src/core/Synapse.Core/Extensions/WorkflowDefinitionExtensions.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
1313

14-
using System.Runtime.CompilerServices;
15-
1614
namespace Synapse;
1715

1816
/// <summary>
@@ -27,8 +25,9 @@ public static class WorkflowDefinitionExtensions
2725
/// <param name="workflow">The <see cref="WorkflowDefinition"/> that defines the specified <see cref="TaskDefinition"/></param>
2826
/// <param name="task">The name/definition mapping of the <see cref="TaskDefinition"/> to get the following <see cref="TaskDefinition"/> of</param>
2927
/// <param name="parentReference">A reference to the component that defines the next <see cref="TaskDefinition"/></param>
28+
/// <param name="ignoreConditionalTasks">If true, ignore <see cref="TaskDefinition"/> with an if clause</param>
3029
/// <returns>A name/definition mapping of the next <see cref="TaskDefinition"/>, if any</returns>
31-
public static MapEntry<string, TaskDefinition>? GetTaskAfter(this WorkflowDefinition workflow, MapEntry<string, TaskDefinition> task, string parentReference)
30+
public static MapEntry<string, TaskDefinition>? GetTaskAfter(this WorkflowDefinition workflow, MapEntry<string, TaskDefinition> task, string parentReference, bool ignoreConditionalTasks = false)
3231
{
3332
ArgumentNullException.ThrowIfNull(workflow);
3433
ArgumentNullException.ThrowIfNull(task);
@@ -37,6 +36,13 @@ public static class WorkflowDefinitionExtensions
3736
var taskIndex = taskMap.Select(e => e.Key).ToList().IndexOf(task.Key);
3837
var nextIndex = taskIndex < 0 ? -1 : taskIndex + 1;
3938
if (nextIndex < 0 || nextIndex >= taskMap.Count) return null;
39+
var taskEntry = taskMap.ElementAt(nextIndex);
40+
while(ignoreConditionalTasks && !string.IsNullOrEmpty(taskEntry?.Value?.If))
41+
{
42+
nextIndex++;
43+
if (nextIndex < 0 || nextIndex >= taskMap.Count) return null;
44+
taskEntry = taskMap.ElementAt(nextIndex);
45+
}
4046
return taskMap.ElementAt(nextIndex);
4147
}
4248

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

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@ public IGraphViewModel Build(WorkflowDefinition workflow)
8888
/// Returns the name, index and reference of the next node
8989
/// </summary>
9090
/// <param name="context">The rendering context for the task nodes</param>
91-
/// <param name="currentNode">The current task node</param>
91+
/// <param name="ignoreConditionalTasks">If true, skips <see cref="TaskDefinition"/> with an if clause</param>
9292
/// <param name="transition">A transition, if different from the context task definition's</param>
9393
/// <returns>The next task <see cref="TaskIdentity"/></returns>
94-
protected TaskIdentity? GetNextTaskIdentity(TaskNodeRenderingContext context, NodeViewModel currentNode, string? transition = null)
94+
protected TaskIdentity? GetNextTaskIdentity(TaskNodeRenderingContext context, bool ignoreConditionalTasks, string? transition = null)
9595
{
9696
transition = !string.IsNullOrWhiteSpace(transition) ? transition : context.TaskDefinition.Then;
9797
if (transition == FlowDirective.End) return null;
@@ -101,35 +101,55 @@ public IGraphViewModel Build(WorkflowDefinition workflow)
101101
{
102102
return null;
103103
}
104-
return this.GetNextTaskIdentity(context.ParentContext, currentNode);
104+
return this.GetNextTaskIdentity(context.ParentContext, ignoreConditionalTasks);
105105
}
106106
var nextTaskName = string.IsNullOrWhiteSpace(transition) || transition == FlowDirective.Continue
107-
? context.Workflow.GetTaskAfter(new(context.TaskName, context.TaskDefinition), context.ParentReference)?.Key
107+
? context.Workflow.GetTaskAfter(new(context.TaskName, context.TaskDefinition), context.ParentReference, ignoreConditionalTasks)?.Key
108108
: transition;
109109
if (string.IsNullOrWhiteSpace(nextTaskName))
110110
{
111111
if (context.ParentContext == null)
112112
{
113113
return null;
114114
}
115-
return this.GetNextTaskIdentity(context.ParentContext, currentNode);
115+
return this.GetNextTaskIdentity(context.ParentContext, ignoreConditionalTasks);
116116
}
117117
var nextTaskIndex = context.Workflow.IndexOf(nextTaskName, context.ParentReference);
118118
var nextTaskReference = $"{context.ParentReference}/{nextTaskIndex}/{nextTaskName}";
119119
return new(nextTaskName, nextTaskIndex, nextTaskReference, context);
120120
}
121121

122+
/// <summary>
123+
/// Gets a <see cref="NodeViewModel"/> by reference in the provided <see cref="TaskNodeRenderingContext"/>
124+
/// </summary>
125+
/// <param name="context">The source <see cref="TaskNodeRenderingContext"/></param>
126+
/// <param name="reference">The reference to look for</param>
127+
/// <returns></returns>
128+
protected NodeViewModel GetNodeByReference(TaskNodeRenderingContext context, string reference)
129+
{
130+
if (context.Graph.AllClusters.ContainsKey(reference))
131+
{
132+
return (NodeViewModel)context.Graph.AllClusters[reference].AllNodes.First().Value;
133+
}
134+
if (context.Graph.AllNodes.ContainsKey(reference))
135+
{
136+
return (NodeViewModel)context.Graph.AllNodes[reference];
137+
}
138+
throw new IndexOutOfRangeException($"Unabled to find the task with reference '{reference}' in the provided context.");
139+
}
140+
122141
/// <summary>
123142
/// Gets the next <see cref="NodeViewModel"/> in the graph
124143
/// </summary>
125144
/// <param name="context">The rendering context for the task nodes</param>
126145
/// <param name="currentNode">The current task node</param>
146+
/// <param name="ignoreConditionalTasks">If true, skips <see cref="TaskDefinition"/> with an if clause</param>
127147
/// <param name="transition">A transition, if different from the context task definition's</param>
128148
/// <returns>The next task <see cref="NodeViewModel"/></returns>
129149
/// <exception cref="Exception"></exception>
130-
protected NodeViewModel GetNextNode(TaskNodeRenderingContext context, NodeViewModel currentNode, string? transition = null)
150+
protected NodeViewModel GetNextNode(TaskNodeRenderingContext context, NodeViewModel currentNode, bool ignoreConditionalTasks = false, string? transition = null)
131151
{
132-
var nextTaskIdentity = this.GetNextTaskIdentity(context, currentNode, transition);
152+
var nextTaskIdentity = this.GetNextTaskIdentity(context, ignoreConditionalTasks, transition);
133153
if (nextTaskIdentity == null)
134154
{
135155
return context.EndNode;
@@ -139,11 +159,13 @@ protected NodeViewModel GetNextNode(TaskNodeRenderingContext context, NodeViewMo
139159
{
140160
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));
141161
}
142-
if (context.Graph.AllClusters.ContainsKey(nextTaskIdentity.Reference))
162+
if (string.IsNullOrEmpty(nextTask.If))
143163
{
144-
return (NodeViewModel)context.Graph.AllClusters[nextTaskIdentity.Reference].AllNodes.First().Value;
164+
return this.GetNodeByReference(context, nextTaskIdentity.Reference);
145165
}
146-
return (NodeViewModel)context.Graph.AllNodes[nextTaskIdentity.Reference];
166+
var nextNode = this.GetNodeByReference(context, nextTaskIdentity.Reference);
167+
this.BuildEdge(context.Graph, currentNode, nextNode);
168+
return this.GetNextNode(context, currentNode, true, transition);
147169
}
148170

149171
/// <summary>
@@ -239,10 +261,16 @@ protected virtual NodeViewModel BuildDoTaskNode(TaskNodeRenderingContext<DoTaskD
239261
cluster.AddChild(port);
240262
if (context.TaskGroup == null) context.Graph.AddCluster(cluster);
241263
else context.TaskGroup.AddChild(cluster);
242-
this.BuildTaskNode(new(context.Workflow, context.Graph, 0, context.TaskDefinition.Do.First().Key, context.TaskDefinition.Do.First().Value, cluster, context.TaskReference + "/do", context, context.EndNode, context.PreviousNode));
264+
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);
265+
this.BuildTaskNode(innerContext);
243266
if (taskCount > 0)
244267
{
245-
this.BuildEdge(context.Graph, port, (NodeViewModel)cluster.AllNodes.Skip(1).First().Value);
268+
var firstDoNode = (NodeViewModel)cluster.AllNodes.Skip(1).First().Value;
269+
this.BuildEdge(context.Graph, port, firstDoNode);
270+
if (taskCount > 1 && !string.IsNullOrWhiteSpace(context.TaskDefinition.Do.First().Value.If))
271+
{
272+
this.BuildEdge(context.Graph, port, this.GetNextNode(innerContext, firstDoNode));
273+
}
246274
}
247275
else
248276
{
@@ -445,7 +473,7 @@ protected virtual NodeViewModel BuildSwitchTaskNode(TaskNodeRenderingContext<Swi
445473
else context.TaskGroup.AddChild(node);
446474
foreach (var switchCase in context.TaskDefinition.Switch)
447475
{
448-
var switchCaseNode = this.GetNextNode(context, node, switchCase.Value.Then);
476+
var switchCaseNode = this.GetNextNode(context, node, false, switchCase.Value.Then);
449477
this.BuildEdge(context.Graph, node, switchCaseNode, switchCase.Key);
450478
}
451479
if (!context.TaskDefinition.Switch.Any(switchCase => string.IsNullOrEmpty(switchCase.Value.When)))
@@ -475,10 +503,16 @@ protected virtual NodeViewModel BuildTryTaskNode(TaskNodeRenderingContext<TryTas
475503
tryCluster.AddChild(tryPort);
476504
containerCluster.AddChild(tryCluster);
477505
this.BuildEdge(context.Graph, containerPort, tryPort);
478-
this.BuildTaskNode(new(context.Workflow, context.Graph, 0, context.TaskDefinition.Try.First().Key, context.TaskDefinition.Try.First().Value, tryCluster, context.TaskReference + "/try", context, context.EndNode, context.PreviousNode));
506+
var innerContext = new TaskNodeRenderingContext(context.Workflow, context.Graph, 0, context.TaskDefinition.Try.First().Key, context.TaskDefinition.Try.First().Value, tryCluster, context.TaskReference + "/try", context, context.EndNode, context.PreviousNode);
507+
this.BuildTaskNode(innerContext);
479508
if (taskCount > 0)
480509
{
481-
this.BuildEdge(context.Graph, tryPort, tryCluster.AllNodes.Values.Skip(1).First());
510+
var firstNode = (NodeViewModel)tryCluster.AllNodes.Skip(1).First().Value;
511+
this.BuildEdge(context.Graph, tryPort, firstNode);
512+
if (taskCount > 1 && !string.IsNullOrWhiteSpace(context.TaskDefinition.Try.First().Value.If))
513+
{
514+
this.BuildEdge(context.Graph, tryPort, this.GetNextNode(innerContext, firstNode));
515+
}
482516
}
483517
var catchContent = this.YamlSerializer.SerializeToText(context.TaskDefinition.Catch);
484518
if (context.TaskDefinition.Catch.Do == null || context.TaskDefinition.Catch.Do.Count == 0)

0 commit comments

Comments
 (0)