Skip to content

Commit 511d103

Browse files
authored
Merge pull request #444 from serverlessworkflow/feat-dashboard-suspend-resume-cancel
Added suspend/resume/cancel actions to workflow instances in the Dashboard
2 parents 192bdf8 + fbf7627 commit 511d103

File tree

21 files changed

+271
-42
lines changed

21 files changed

+271
-42
lines changed

src/api/Synapse.Api.Application/Synapse.Api.Application.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<NeutralLanguage>en</NeutralLanguage>
88
<GenerateDocumentationFile>True</GenerateDocumentationFile>
99
<VersionPrefix>1.0.0</VersionPrefix>
10-
<VersionSuffix>alpha5</VersionSuffix>
10+
<VersionSuffix>alpha5.1</VersionSuffix>
1111
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1212
<FileVersion>$(VersionPrefix)</FileVersion>
1313
<Authors>The Synapse Authors</Authors>

src/api/Synapse.Api.Client.Core/Synapse.Api.Client.Core.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<NeutralLanguage>en</NeutralLanguage>
88
<GenerateDocumentationFile>True</GenerateDocumentationFile>
99
<VersionPrefix>1.0.0</VersionPrefix>
10-
<VersionSuffix>alpha5</VersionSuffix>
10+
<VersionSuffix>alpha5.1</VersionSuffix>
1111
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1212
<FileVersion>$(VersionPrefix)</FileVersion>
1313
<Authors>The Synapse Authors</Authors>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<NeutralLanguage>en</NeutralLanguage>
88
<GenerateDocumentationFile>True</GenerateDocumentationFile>
99
<VersionPrefix>1.0.0</VersionPrefix>
10-
<VersionSuffix>alpha5</VersionSuffix>
10+
<VersionSuffix>alpha5.1</VersionSuffix>
1111
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1212
<FileVersion>$(VersionPrefix)</FileVersion>
1313
<Authors>The Synapse Authors</Authors>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<OutputType>Library</OutputType>
99
<GenerateDocumentationFile>True</GenerateDocumentationFile>
1010
<VersionPrefix>1.0.0</VersionPrefix>
11-
<VersionSuffix>alpha5</VersionSuffix>
11+
<VersionSuffix>alpha5.1</VersionSuffix>
1212
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1313
<FileVersion>$(VersionPrefix)</FileVersion>
1414
<Authors>The Synapse Authors</Authors>

src/api/Synapse.Api.Server/Synapse.Api.Server.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<NeutralLanguage>en</NeutralLanguage>
88
<GenerateDocumentationFile>True</GenerateDocumentationFile>
99
<VersionPrefix>1.0.0</VersionPrefix>
10-
<VersionSuffix>alpha5</VersionSuffix>
10+
<VersionSuffix>alpha5.1</VersionSuffix>
1111
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1212
<FileVersion>$(VersionPrefix)</FileVersion>
1313
<Authors>The Synapse Authors</Authors>

src/cli/Synapse.Cli/Synapse.Cli.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<NeutralLanguage>en</NeutralLanguage>
99
<GenerateDocumentationFile>True</GenerateDocumentationFile>
1010
<VersionPrefix>1.0.0</VersionPrefix>
11-
<VersionSuffix>alpha5</VersionSuffix>
11+
<VersionSuffix>alpha5.1</VersionSuffix>
1212
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1313
<FileVersion>$(VersionPrefix)</FileVersion>
1414
<Authors>The Synapse Authors</Authors>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<NeutralLanguage>en</NeutralLanguage>
88
<GenerateDocumentationFile>True</GenerateDocumentationFile>
99
<VersionPrefix>1.0.0</VersionPrefix>
10-
<VersionSuffix>alpha5</VersionSuffix>
10+
<VersionSuffix>alpha5.1</VersionSuffix>
1111
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1212
<FileVersion>$(VersionPrefix)</FileVersion>
1313
<Authors>The Synapse Authors</Authors>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<NeutralLanguage>en</NeutralLanguage>
88
<GenerateDocumentationFile>True</GenerateDocumentationFile>
99
<VersionPrefix>1.0.0</VersionPrefix>
10-
<VersionSuffix>alpha5</VersionSuffix>
10+
<VersionSuffix>alpha5.1</VersionSuffix>
1111
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1212
<FileVersion>$(VersionPrefix)</FileVersion>
1313
<Authors>The Synapse Authors</Authors>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<NeutralLanguage>en</NeutralLanguage>
88
<GenerateDocumentationFile>True</GenerateDocumentationFile>
99
<VersionPrefix>1.0.0</VersionPrefix>
10-
<VersionSuffix>alpha5</VersionSuffix>
10+
<VersionSuffix>alpha5.1</VersionSuffix>
1111
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1212
<FileVersion>$(VersionPrefix)</FileVersion>
1313
<Authors>The Synapse Authors</Authors>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<NeutralLanguage>en</NeutralLanguage>
88
<GenerateDocumentationFile>True</GenerateDocumentationFile>
99
<VersionPrefix>1.0.0</VersionPrefix>
10-
<VersionSuffix>alpha5</VersionSuffix>
10+
<VersionSuffix>alpha5.1</VersionSuffix>
1111
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1212
<FileVersion>$(VersionPrefix)</FileVersion>
1313
<Authors>The Synapse Authors</Authors>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<NeutralLanguage>en</NeutralLanguage>
99
<GenerateDocumentationFile>True</GenerateDocumentationFile>
1010
<VersionPrefix>1.0.0</VersionPrefix>
11-
<VersionSuffix>alpha5</VersionSuffix>
11+
<VersionSuffix>alpha5.1</VersionSuffix>
1212
<AssemblyVersion>$(VersionPrefix)</AssemblyVersion>
1313
<FileVersion>$(VersionPrefix)</FileVersion>
1414
<Authors>The Synapse Authors</Authors>

src/dashboard/Synapse.Dashboard/Components/WorkflowInstancesList/WorkflowInstancesList.razor

+154-19
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@
5858
<div class="dropdown d-flex align-content-center">
5959
<button class="btn btn-sm btn-dark" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false" title="" @onclick:stopPropagation="true"><i class="bi bi-three-dots-vertical"></i></button>
6060
<ul class="dropdown-menu">
61-
<li><a class="dropdown-item @(selectedInstanceNames.Count() == 0 ? "text-mute" : "text-danger")" href="#" @onclick="OnDeleteSelected" @onclick:preventDefault="true" @onclick:stopPropagation="true"><Icon Name="IconName.Trash" /> Delete selected</a></li>
61+
<li><button class="dropdown-item @(selectedInstanceNames.Count() == 0 ? "text-mute" : "")" disabled="@(selectedInstanceNames.Count() == 0)" @onclick="OnSuspendSelectedClickedAsync" @onclick:preventDefault="true" @onclick:stopPropagation="true"><Icon Name="IconName.Pause" /> Suspend selected</button></li>
62+
<li><button class="dropdown-item @(selectedInstanceNames.Count() == 0 ? "text-mute" : "")" disabled="@(selectedInstanceNames.Count() == 0)" @onclick="OnResumeSelectedClickedAsync" @onclick:preventDefault="true" @onclick:stopPropagation="true"><Icon Name="IconName.Play" /> Resume selected</button></li>
63+
<li><button class="dropdown-item @(selectedInstanceNames.Count() == 0 ? "text-mute" : "")" disabled="@(selectedInstanceNames.Count() == 0)" @onclick="OnCancelSelectedClickedAsync" @onclick:preventDefault="true" @onclick:stopPropagation="true"><Icon Name="IconName.X" /> Cancel selected</button></li>
64+
<li><button class="dropdown-item @(selectedInstanceNames.Count() == 0 ? "text-mute" : "text-danger")" disabled="@(selectedInstanceNames.Count() == 0)" @onclick="OnDeleteSelected" @onclick:preventDefault="true" @onclick:stopPropagation="true"><Icon Name="IconName.Trash" /> Delete selected</button></li>
6265
</ul>
6366
</div>
6467
</div>
@@ -68,9 +71,9 @@
6871
<tr>
6972
@foreach (var column in knownColumns)
7073
{
71-
if ((Columns.Count() == 0 && column != "Delete") || Columns.Contains(column))
74+
if ((Columns.Count() == 0 && !DirectActions.Contains(column)) || Columns.Contains(column))
7275
{
73-
<th class="sticky-header text-@GetColumnAlignment(column)">@(column != "Action" && column != "Delete" ? column : "")</th>
76+
<th class="sticky-header text-@GetColumnAlignment(column)">@(column != "Actions" && !DirectActions.Contains(column) ? column : "")</th>
7477
}
7578
}
7679
<th class="sticky-header text-center align-middle">
@@ -85,7 +88,7 @@
8588
<tr @onclick="async _ => await OnShowClickedAsync(instance)" class="cursor-pointer @(ActiveRow == instance.GetName() ? "table-active" : "")">
8689
@foreach (var column in knownColumns)
8790
{
88-
if ((Columns.Count() == 0 && column != "Delete") || Columns.Contains(column))
91+
if ((Columns.Count() == 0 && !DirectActions.Contains(column)) || Columns.Contains(column))
8992
{
9093
<td class="text-@GetColumnAlignment(column)">
9194
@switch(column)
@@ -144,16 +147,44 @@
144147
<div class="dropdown">
145148
<button class="btn btn-sm btn-dark" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false" title="" @onclick:stopPropagation="true"><i class="bi bi-three-dots-vertical"></i></button>
146149
<ul class="dropdown-menu">
147-
<li><a class="dropdown-item" href="#" @onclick="async _ => await OnShowClickedAsync(instance)" @onclick:preventDefault="true" @onclick:stopPropagation="true"><Icon Name="IconName.Eye" /> View</a></li>
148-
<li><a class="dropdown-item text-danger" href="#" @onclick="async _ => await OnDeleteClickedAsync(instance)" @onclick:preventDefault="true" @onclick:stopPropagation="true"><Icon Name="IconName.Trash" /> Delete</a></li>
150+
@if (instance.Status?.Phase == WorkflowInstanceStatusPhase.Running)
151+
{
152+
<li><button class="dropdown-item" @onclick="async _ => await OnSuspendClickedAsync(instance)" @onclick:stopPropagation="true"><Icon Name="IconName.Pause" /> Suspend</button></li>
153+
}
154+
@if (instance.Status?.Phase == WorkflowInstanceStatusPhase.Suspended)
155+
{
156+
<li><button class="dropdown-item" @onclick="async _ => await OnResumeClickedAsync(instance)" @onclick:stopPropagation="true"><Icon Name="IconName.Play" /> Resume</button></li>
157+
}
158+
@if (instance.IsOperative)
159+
{
160+
<li><button class="dropdown-item" @onclick="async _ => await OnCancelClickedAsync(instance)" @onclick:stopPropagation="true"><Icon Name="IconName.X" /> Cancel</button></li>
161+
}
162+
<li><button class="dropdown-item" @onclick="async _ => await OnReplayClickedAsync(instance)" @onclick:stopPropagation="true"><Icon Name="IconName.ArrowClockwise" /> Replay</button></li>
163+
<li><button class="dropdown-item text-danger" @onclick="async _ => await OnDeleteClickedAsync(instance)" @onclick:stopPropagation="true"><Icon Name="IconName.Trash" /> Delete</button></li>
149164
</ul>
150165
</div>
151166
break;
167+
case "Resume":
168+
@if (instance.Status?.Phase == WorkflowInstanceStatusPhase.Running)
169+
{
170+
<button class="btn btn-sm text-primary" @onclick="async _ => await OnSuspendClickedAsync(instance)" @onclick:stopPropagation="true" title="Suspend"><Icon Name="IconName.Pause" /></button>
171+
}
172+
@if (instance.Status?.Phase == WorkflowInstanceStatusPhase.Suspended)
173+
{
174+
<button class="btn btn-sm text-primary" @onclick="async _ => await OnResumeClickedAsync(instance)" @onclick:stopPropagation="true" title="Resume"><Icon Name="IconName.Play" /></button>
175+
}
176+
break;
177+
case "Cancel":
178+
@if (instance.IsOperative)
179+
{
180+
<button class="btn btn-sm text-warning" @onclick="async _ => await OnCancelClickedAsync(instance)" @onclick:stopPropagation="true" title="Cancel"><Icon Name="IconName.X" /></button>
181+
}
182+
break;
152183
case "Replay":
153-
<button class="btn btn-sm text-primary" @onclick="async _ => await OnReplayClickedAsync(instance)" @onclick:stopPropagation="true"><Icon Name="IconName.ArrowClockwise" /></button>
184+
<button class="btn btn-sm text-primary" @onclick="async _ => await OnReplayClickedAsync(instance)" @onclick:stopPropagation="true" title="Replay"><Icon Name="IconName.ArrowClockwise" /></button>
154185
break;
155186
case "Delete":
156-
<button class="btn btn-sm text-danger" @onclick="async _ => await OnDeleteClickedAsync(instance)" @onclick:stopPropagation="true"><Icon Name="IconName.Trash" /></button>
187+
<button class="btn btn-sm text-danger" @onclick="async _ => await OnDeleteClickedAsync(instance)" @onclick:stopPropagation="true" title="Delete"><Icon Name="IconName.Trash" /></button>
157188
break;
158189
default:
159190
break;
@@ -208,9 +239,21 @@
208239
[Parameter] public EventCallback<string?> OnToggleSelected { get; set; }
209240
[Parameter] public EventCallback<WorkflowInstance> OnDelete { get; set; }
210241
[Parameter] public EventCallback<WorkflowInstance> OnReplay { get; set; }
242+
[Parameter] public EventCallback<WorkflowInstance> OnSuspend { get; set; }
243+
[Parameter] public EventCallback<WorkflowInstance> OnResume { get; set; }
244+
[Parameter] public EventCallback<WorkflowInstance> OnCancel { get; set; }
211245
[Parameter] public EventCallback OnDeleteSelected { get; set; }
246+
[Parameter] public EventCallback OnSuspendSelected { get; set; }
247+
[Parameter] public EventCallback OnResumeSelected { get; set; }
248+
[Parameter] public EventCallback OnCancelSelected { get; set; }
212249

213-
IEnumerable<string> knownColumns = [
250+
public static IEnumerable<string> DirectActions = [
251+
"Resume",
252+
"Cancel",
253+
"Replay",
254+
"Delete"
255+
];
256+
static IEnumerable<string> knownColumns = [
214257
"Name",
215258
"Namespace",
216259
"Definition",
@@ -221,8 +264,7 @@
221264
"Duration",
222265
"Operator",
223266
"Actions",
224-
"Replay",
225-
"Delete"
267+
..DirectActions
226268
];
227269

228270
ElementReference checkboxAll = default!;
@@ -324,11 +366,14 @@
324366
/// <returns></returns>
325367
string GetColumnAlignment(string column)
326368
{
327-
return column == "Name" || column == "Namespace"
328-
? "start"
329-
: column == "Action"
330-
? "end"
331-
: "center";
369+
return (
370+
column == "Name" || column == "Namespace"
371+
? "start"
372+
: column == "Action"
373+
? "end"
374+
: "center"
375+
)
376+
+ (DirectActions.Contains(column) ? " p-0": "");
332377
}
333378

334379
/// <summary>
@@ -385,7 +430,7 @@
385430
/// <summary>
386431
/// Handles the click on the show button
387432
/// </summary>
388-
/// <param name="instance"></param>
433+
/// <param name="instance">The instance to show</param>
389434
/// <returns></returns>
390435
protected async Task OnShowClickedAsync(WorkflowInstance instance)
391436
{
@@ -398,7 +443,7 @@
398443
/// <summary>
399444
/// Handles the click on the delete button
400445
/// </summary>
401-
/// <param name="instance"></param>
446+
/// <param name="instance">The instance to delete</param>
402447
/// <returns></returns>
403448
protected async Task OnDeleteClickedAsync(WorkflowInstance instance)
404449
{
@@ -411,7 +456,7 @@
411456
/// <summary>
412457
/// Handles the click on the replay button
413458
/// </summary>
414-
/// <param name="instance"></param>
459+
/// <param name="instance">The instance to replay</param>
415460
/// <returns></returns>
416461
protected async Task OnReplayClickedAsync(WorkflowInstance instance)
417462
{
@@ -420,4 +465,94 @@
420465
await this.OnReplay.InvokeAsync(instance);
421466
}
422467
}
468+
469+
/// <summary>
470+
/// Handles the click on the suspend button
471+
/// </summary>
472+
/// <param name="instance">The instance to suspend</param>
473+
/// <returns></returns>
474+
protected async Task OnSuspendClickedAsync(WorkflowInstance instance)
475+
{
476+
if (this.OnSuspend.HasDelegate)
477+
{
478+
await this.OnSuspend.InvokeAsync(instance);
479+
}
480+
}
481+
482+
/// <summary>
483+
/// Handles the click on the resume button
484+
/// </summary>
485+
/// <param name="instance">The instance to resume</param>
486+
/// <returns></returns>
487+
protected async Task OnResumeClickedAsync(WorkflowInstance instance)
488+
{
489+
if (this.OnResume.HasDelegate)
490+
{
491+
await this.OnResume.InvokeAsync(instance);
492+
}
493+
}
494+
495+
/// <summary>
496+
/// Handles the click on the cancel button
497+
/// </summary>
498+
/// <param name="instance">The instance to cancel</param>
499+
/// <returns></returns>
500+
protected async Task OnCancelClickedAsync(WorkflowInstance instance)
501+
{
502+
if (this.OnCancel.HasDelegate)
503+
{
504+
await this.OnCancel.InvokeAsync(instance);
505+
}
506+
}
507+
508+
protected async Task OnSuspendSelectedClickedAsync()
509+
{
510+
var selected = selectedInstanceNames.ToList();
511+
var nonRuningInstances = (WorkflowInstances??[]).Where(instance => selected.Contains(instance.GetName()) && instance.Status?.Phase != WorkflowInstanceStatusPhase.Running);
512+
foreach(var instance in nonRuningInstances)
513+
{
514+
if (this.OnToggleSelected.HasDelegate)
515+
{
516+
await OnToggleSelected.InvokeAsync(instance.GetName());
517+
}
518+
}
519+
if (this.OnSuspendSelected.HasDelegate)
520+
{
521+
await OnSuspendSelected.InvokeAsync();
522+
}
523+
}
524+
525+
protected async Task OnResumeSelectedClickedAsync()
526+
{
527+
var selected = selectedInstanceNames.ToList();
528+
var nonSuspendedInstances = (WorkflowInstances ?? []).Where(instance => selected.Contains(instance.GetName()) && instance.Status?.Phase != WorkflowInstanceStatusPhase.Suspended);
529+
foreach (var instance in nonSuspendedInstances)
530+
{
531+
if (this.OnToggleSelected.HasDelegate)
532+
{
533+
await OnToggleSelected.InvokeAsync(instance.GetName());
534+
}
535+
}
536+
if (this.OnResumeSelected.HasDelegate)
537+
{
538+
await OnResumeSelected.InvokeAsync();
539+
}
540+
}
541+
542+
protected async Task OnCancelSelectedClickedAsync()
543+
{
544+
var selected = selectedInstanceNames.ToList();
545+
var nonOperativeInstances = (WorkflowInstances ?? []).Where(instance => selected.Contains(instance.GetName()) && !instance.IsOperative);
546+
foreach (var instance in nonOperativeInstances)
547+
{
548+
if (this.OnToggleSelected.HasDelegate)
549+
{
550+
await OnToggleSelected.InvokeAsync(instance.GetName());
551+
}
552+
}
553+
if (this.OnCancelSelected.HasDelegate)
554+
{
555+
await OnCancelSelected.InvokeAsync();
556+
}
557+
}
423558
}

src/dashboard/Synapse.Dashboard/Extensions/StatusExtensions.cs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public static class StatusExtensions
4343
//CorrelationContextStatus.Completed => "success",
4444
WorkflowInstanceStatusPhase.Waiting => "cinereous",
4545
TaskInstanceStatus.Suspended => "icterine",
46+
//WorkflowInstanceStatusPhase.Suspended => "icterine",
4647
TaskInstanceStatus.Skipped => "cinereous",
4748
WorkflowInstanceStatusPhase.Pending => "mute",
4849
//TaskInstanceStatus.Pending => "mute",

0 commit comments

Comments
 (0)