Skip to content

Commit 5d1443b

Browse files
authored
Merge pull request #533 from serverlessworkflow/feat-add-workflow-labels
Enabled label management when creating or editing a workflow
2 parents b20f4de + f3ae224 commit 5d1443b

File tree

13 files changed

+625
-347
lines changed

13 files changed

+625
-347
lines changed

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

Lines changed: 110 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
limitations under the License.
1515
*@
1616

17+
@namespace Synapse.Dashboard.Components
1718
@using Json.Schema
1819
@using Neuroglia.Data.Infrastructure.ResourceOriented.Properties
1920
@using ServerlessWorkflow.Sdk
2021
@using ServerlessWorkflow.Sdk.Models
2122
@using System.Xml.Schema
2223
@using Synapse.Core.Infrastructure.Services
2324
@using System.Text.Json.Nodes
24-
@namespace Synapse.Dashboard.Components
2525
@inject MonacoInterop MonacoInterop
2626
@inject IExternalResourceProvider ExternalResourceProvider
2727
@inject IJsonSerializer JsonSerializer
@@ -38,7 +38,7 @@
3838
</Content>
3939
</Tab>
4040
}
41-
<Tab Title="Text">
41+
<Tab Title="Raw">
4242
<Content>
4343
<div class="pt-3">
4444
<MonacoEditor OnTextChanged="OnTextChanged" ModelName="@modelName" Document="input" />
@@ -49,19 +49,37 @@
4949

5050
<Accordion class="py-3">
5151
<AccordionItem Title="Advanced Settings">
52-
<Content>
53-
@if (Operators != null && Operators.Count() > 0)
54-
{
55-
<label for="operator">Select an Operator to run the Workflow:</label>
56-
<select id="operator" class="form-select" @onchange="OnSelectOperatorChanged">
57-
<option value="">Any Operator</option>
58-
@foreach (var op in Operators)
59-
{
60-
var name = op.GetName() + "." + op.GetNamespace();
61-
<option value="@name" selected="@(name == operatorName)">@name</option>
62-
}
63-
</select>
64-
}
52+
<Content>
53+
<div>
54+
@if (Operators != null && Operators.Count() > 0)
55+
{
56+
<label for="operator" class="fw-bolder mb-2">Run on:</label>
57+
<select id="operator" class="form-select" @onchange="(e) => SetOperator(e.Value?.ToString())">
58+
<option value="">Any Operator</option>
59+
@foreach (var op in Operators)
60+
{
61+
var name = op.GetName() + "." + op.GetNamespace();
62+
<option value="@name" selected="@(name == operatorName)">@name</option>
63+
}
64+
</select>
65+
}
66+
</div>
67+
<div class="mt-4">
68+
<DictionaryEditor Title="Labels"
69+
KeyPlaceholder="Enter label key"
70+
ValuePlaceholder="Enter label value"
71+
Entries="parameters.Labels"
72+
OnAddEntry="(kvp) => AddLabel(kvp.Key, kvp.Value)"
73+
OnRemoveEntry="RemoveLabel" />
74+
</div>
75+
<div class="mt-4">
76+
<DictionaryEditor Title="Annotations"
77+
KeyPlaceholder="Enter annotation key"
78+
ValuePlaceholder="Enter annotation value"
79+
Entries="parameters.Annotations"
80+
OnAddEntry="(kvp) => AddAnnotation(kvp.Key, kvp.Value)"
81+
OnRemoveEntry="RemoveAnnotation" />
82+
</div>
6583
</Content>
6684
</AccordionItem>
6785
</Accordion>
@@ -77,33 +95,37 @@
7795

7896
WorkflowDefinition? workflowDefinition;
7997
JsonSchema? schema;
80-
string payload = string.Empty;
8198
string modelName = string.Empty;
8299
EquatableDictionary<string, object>? input;
100+
CreateWorkflowInstanceParameters parameters = new();
83101
string? operatorName;
84102

85103
[Parameter] public WorkflowDefinition? WorkflowDefinition { get; set; }
86104
[Parameter] public IEnumerable<Operator> Operators { get; set; } = [];
87-
[Parameter] public string? OperatorName { get; set; } = null;
88105
[Parameter] public EquatableDictionary<string, object>? Input { get; set; }
106+
[Parameter] public EquatableDictionary<string, string>? Labels { get; set; }
107+
[Parameter] public EquatableDictionary<string, string>? Annotations { get; set; }
89108
[Parameter] public EventCallback<CreateWorkflowInstanceParameters> OnCreate { get; set; }
90109
[Parameter] public EventCallback<ProblemDetails> OnProblem { get; set; }
91110

92111
void OnValueChanged(object? value)
93112
{
94-
payload = value == null ? string.Empty : JsonSerializer.SerializeToText(value);
113+
parameters.Input = value == null ? string.Empty : JsonSerializer.SerializeToText(value);
95114
}
96115

97116
void OnTextChanged(string value)
98117
{
99-
payload = value;
118+
parameters.Input = value;
100119
}
101120

102121
protected override async Task OnParametersSetAsync()
103122
{
104123
await base.OnParametersSetAsync();
105124
if (input != Input) input = Input;
106-
if (operatorName != OperatorName) operatorName = OperatorName;
125+
if (Labels != null && Labels.Count > 0) SetLabels(Labels);
126+
else SetLabels(null);
127+
if (Annotations != null && Annotations.Count > 0) SetAnnotations(Annotations);
128+
else SetAnnotations(null);
107129
if (workflowDefinition != WorkflowDefinition)
108130
{
109131
workflowDefinition = WorkflowDefinition;
@@ -116,16 +138,80 @@
116138
}
117139
}
118140

119-
protected void OnSelectOperatorChanged(ChangeEventArgs e)
141+
protected void SetLabels(EquatableDictionary<string, string>? labels)
142+
{
143+
parameters.Labels = labels != null ? [.. labels] : [];
144+
if (labels != null) operatorName = labels.TryGetValue(SynapseDefaults.Resources.Labels.Operator, out var label) ? label : null;
145+
}
146+
147+
protected void AddLabel(string key, string value)
148+
{
149+
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value))
150+
{
151+
return;
152+
}
153+
if (parameters.Labels.ContainsKey(key))
154+
{
155+
parameters.Labels.Remove(key);
156+
}
157+
parameters.Labels.Add(key, value);
158+
}
159+
160+
protected void RemoveLabel(string key)
161+
{
162+
if (string.IsNullOrWhiteSpace(key))
163+
{
164+
return;
165+
}
166+
if (parameters.Labels.ContainsKey(key))
167+
{
168+
parameters.Labels.Remove(key);
169+
}
170+
}
171+
172+
protected void SetOperator(string? operatorName)
173+
{
174+
if (string.IsNullOrEmpty(operatorName))
175+
RemoveLabel(SynapseDefaults.Resources.Labels.Operator);
176+
else
177+
AddLabel(SynapseDefaults.Resources.Labels.Operator, operatorName);
178+
}
179+
180+
protected void SetAnnotations(EquatableDictionary<string, string>? annotations)
181+
{
182+
parameters.Annotations = annotations != null ? [.. annotations] : [];
183+
}
184+
185+
protected void AddAnnotation(string key, string value)
186+
{
187+
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value))
188+
{
189+
return;
190+
}
191+
if (parameters.Annotations.ContainsKey(key))
192+
{
193+
parameters.Annotations.Remove(key);
194+
}
195+
parameters.Annotations.Add(key, value);
196+
}
197+
198+
protected void RemoveAnnotation(string key)
120199
{
121-
operatorName = e.Value?.ToString();
200+
if (string.IsNullOrWhiteSpace(key))
201+
{
202+
return;
203+
}
204+
if (parameters.Annotations.ContainsKey(key))
205+
{
206+
parameters.Annotations.Remove(key);
207+
}
122208
}
123209

124210
async Task OnStartAsync()
125211
{
126212
if (schema != null)
127213
{
128-
var node = string.IsNullOrWhiteSpace(payload) ? null : JsonSerializer.Deserialize<JsonNode>(payload);
214+
var node = string.IsNullOrWhiteSpace(parameters.Input) ? null : JsonSerializer.Deserialize<JsonNode>(parameters.Input);
129215
var evaluationOptions = new EvaluationOptions()
130216
{
131217
OutputFormat = OutputFormat.List
@@ -141,10 +227,7 @@
141227
}
142228
if (OnCreate.HasDelegate)
143229
{
144-
await OnCreate.InvokeAsync(new CreateWorkflowInstanceParameters() {
145-
Input = payload,
146-
Operator = operatorName
147-
});
230+
await OnCreate.InvokeAsync(parameters);
148231
}
149232
}
150233

src/dashboard/Synapse.Dashboard/Components/CreateWorkflowInstanceDialog/CreateWorkflowInstanceParameters.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ public record CreateWorkflowInstanceParameters
2424
public string? Input { get; set; }
2525

2626
/// <summary>
27-
/// Gets/sets the workflow instance operator.
27+
/// Gets/sets the workflow instance's labels.
2828
/// </summary>
29-
public string? Operator { get; set; }
29+
public EquatableDictionary<string, string> Labels { get; set; } = [];
30+
31+
/// <summary>
32+
/// Gets/sets the workflow instance's annotations.
33+
/// </summary>
34+
public EquatableDictionary<string, string> Annotations { get; set; } = [];
3035
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
@*
2+
Copyright © 2024-Present The Synapse Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*@
16+
17+
@namespace Synapse.Dashboard.Components
18+
19+
<div class="fw-bolder mb-2">@Title:</div>
20+
<div class="border rounded p-3">
21+
<table class="table">
22+
<tbody>
23+
<tr>
24+
<td class="ps-0 py-0 pe-2">
25+
<input name="label-key" type="text" class="form-control border-0" placeholder="@KeyPlaceholder" @bind="newKey" />
26+
</td>
27+
<td class="ps-0 py-0 pe-2">
28+
<input name="label-value" type="text" class="form-control border-0" placeholder="@ValuePlaceholder" @bind="newValue" />
29+
</td>
30+
<td class="text-end pt-2 fit">
31+
<Button Color="ButtonColor.Primary" Size="ButtonSize.Small" Outline="true" class="m-1" @onclick="_ => AddLabel()">
32+
<Icon Color="IconColor.Primary" Name="IconName.Plus" />
33+
</Button>
34+
</td>
35+
</tr>
36+
@foreach (KeyValuePair<string, string> entry in Entries)
37+
{
38+
<tr>
39+
<td class="pt-2 ps-2">@entry.Key</td>
40+
<td class="pt-2 ps-2">@entry.Value</td>
41+
<td class="text-end pt-2 fit">
42+
<Button Color="ButtonColor.Primary" Size="ButtonSize.Small" Outline="true" class="m-1" @onclick="() => RemoveLabel(entry.Key)">
43+
<Icon Color="IconColor.Primary" Name="IconName.Trash" />
44+
</Button>
45+
</td>
46+
</tr>
47+
}
48+
</tbody>
49+
</table>
50+
</div>
51+
52+
53+
@code {
54+
private string newKey = string.Empty;
55+
private string newValue = string.Empty;
56+
57+
[Parameter] public string Title { get; set; } = "Labels";
58+
[Parameter] public string KeyPlaceholder { get; set; } = "Enter label key";
59+
[Parameter] public string ValuePlaceholder { get; set; } = "Enter label value";
60+
[Parameter] public EquatableDictionary<string, string> Entries { get; set; } = new();
61+
[Parameter] public EventCallback<KeyValuePair<string, string>> OnAddEntry { get; set; }
62+
[Parameter] public EventCallback<string> OnRemoveEntry { get; set; }
63+
64+
private void AddLabel()
65+
{
66+
if (string.IsNullOrWhiteSpace(newKey) || string.IsNullOrWhiteSpace(newValue)) return;
67+
var entry = new KeyValuePair<string, string>(newKey.Trim(), newValue.Trim());
68+
if (OnAddEntry.HasDelegate)
69+
{
70+
OnAddEntry.InvokeAsync(entry);
71+
}
72+
newKey = string.Empty;
73+
newValue = string.Empty;
74+
}
75+
76+
private void RemoveLabel(string key)
77+
{
78+
if (string.IsNullOrWhiteSpace(key)) return;
79+
if (OnRemoveEntry.HasDelegate)
80+
{
81+
OnRemoveEntry.InvokeAsync(key);
82+
}
83+
}
84+
85+
}

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ public record CreateWorkflowViewState
6262
/// </summary>
6363
public string? WorkflowDefinitionText { get; set; }
6464

65+
/// <summary>
66+
/// Gets/sets the workflow's labels
67+
/// </summary>
68+
public EquatableDictionary<string, string> Labels { get; set; } = [];
69+
70+
/// <summary>
71+
/// Gets/sets the workflow's annotations
72+
/// </summary>
73+
public EquatableDictionary<string, string> Annotations { get; set; } = [];
74+
6575
/// <summary>
6676
/// Gets/sets a boolean indicating whether or not the state is being loaded
6777
/// </summary>
@@ -102,11 +112,6 @@ public record CreateWorkflowViewState
102112
/// </summary>
103113
public EquatableList<Operator>? Operators { get; set; }
104114

105-
/// <summary>
106-
/// Gets/sets the active operator filter
107-
/// </summary>
108-
public string? Operator { get; set; } = null;
109-
110115
/// <summary>
111116
/// Gets/sets the list of <see cref="ProblemDetails"/> errors that occurred when trying to save the resource, if any
112117
/// </summary>

0 commit comments

Comments
 (0)