Skip to content

Commit 0d7af28

Browse files
committed
feat(Dashboard): enable label & annotation management when creating or editing workflows
Signed-off-by: Jean-Baptiste Bianchi <jb.bianchi@neuroglia.io>
1 parent b20f4de commit 0d7af28

File tree

13 files changed

+635
-347
lines changed

13 files changed

+635
-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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy