-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(Dashboard): Multiple fixes and improvements
Signed-off-by: Charles d'Avernas <[email protected]>
- Loading branch information
Showing
29 changed files
with
403 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 154 additions & 0 deletions
154
...apse.Dashboard/Components/CreateWorkflowInstanceDialog/CreateWorkflowInstanceDialog.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
@* | ||
Copyright © 2024-Present The Synapse Authors | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*@ | ||
|
||
@using Json.Schema | ||
@using Neuroglia.Data.Infrastructure.ResourceOriented.Properties | ||
@using ServerlessWorkflow.Sdk | ||
@using ServerlessWorkflow.Sdk.Models | ||
@using System.Xml.Schema | ||
@using Synapse.Core.Infrastructure.Services | ||
@using System.Text.Json.Nodes | ||
@namespace Synapse.Dashboard.Components | ||
@inject MonacoInterop MonacoInterop | ||
@inject IExternalResourceProvider ExternalResourceProvider | ||
@inject IJsonSerializer JsonSerializer | ||
@inject IXmlSerializer XmlSerializer | ||
|
||
<Tabs> | ||
@if(schema != null) | ||
{ | ||
<Tab Title="Form" Active="true"> | ||
<Content> | ||
<div class="pt-3"> | ||
<DynamicForm Schema="schema" OnValueChanged="value => OnValueChanged(value)" /> | ||
</div> | ||
</Content> | ||
</Tab> | ||
} | ||
<Tab Title="Text"> | ||
<Content> | ||
<div class="pt-3"> | ||
<MonacoEditor OnTextChanged="OnTextChanged" ModelName="@modelName" Document="input" /> | ||
</div> | ||
</Content> | ||
</Tab> | ||
</Tabs> | ||
|
||
<div class="text-center"> | ||
<Button Outline="true" Color="ButtonColor.Primary" class="m-auto mt-3 w-100" @onclick="async _ => await OnStartAsync()"> | ||
<Icon Name="IconName.Play" /> | ||
Start | ||
</Button> | ||
</div> | ||
|
||
@code { | ||
|
||
WorkflowDefinition? workflowDefinition; | ||
JsonSchema? schema; | ||
string payload = string.Empty; | ||
string modelName = string.Empty; | ||
EquatableDictionary<string, object>? input; | ||
|
||
[Parameter] public WorkflowDefinition? WorkflowDefinition { get; set; } | ||
[Parameter] public EquatableDictionary<string, object>? Input { get; set; } | ||
[Parameter] public EventCallback<string> OnCreate { get; set; } | ||
[Parameter] public EventCallback<ProblemDetails> OnProblem { get; set; } | ||
|
||
void OnValueChanged(object? value) | ||
{ | ||
payload = value == null ? string.Empty : JsonSerializer.SerializeToText(value); | ||
} | ||
|
||
void OnTextChanged(string value) | ||
{ | ||
payload = value; | ||
} | ||
|
||
protected override async Task OnParametersSetAsync() | ||
{ | ||
await base.OnParametersSetAsync(); | ||
if (input != Input) input = Input; | ||
if (workflowDefinition != WorkflowDefinition) | ||
{ | ||
workflowDefinition = WorkflowDefinition; | ||
await LoadSchemaAsync(); | ||
} | ||
if (WorkflowDefinition?.Input?.Schema?.Document != null) | ||
{ | ||
modelName = WorkflowDefinition.Document.Name + "-" + WorkflowDefinition.Document.Version; | ||
await MonacoInterop.AddValidationSchemaAsync(JsonSerializer.SerializeToText(WorkflowDefinition.Input.Schema.Document), $"https://synapse.io/schemas/{modelName}.json", $"{modelName}*").ConfigureAwait(false); | ||
} | ||
} | ||
|
||
async Task OnStartAsync() | ||
{ | ||
if (schema != null) | ||
{ | ||
var node = string.IsNullOrWhiteSpace(payload) ? null : JsonSerializer.Deserialize<JsonNode>(payload); | ||
var evaluationOptions = new EvaluationOptions() | ||
{ | ||
OutputFormat = OutputFormat.List | ||
}; | ||
var evaluationResult = schema.Evaluate(node, evaluationOptions); | ||
if (!evaluationResult.IsValid) | ||
{ | ||
var errors = evaluationResult.Details.Where(d => d.Errors != null).SelectMany(d => d.Errors!).GroupBy(e => e.Key).Select(e => new KeyValuePair<string, string[]>(e.Key, e.Select(e => e.Value).ToArray())).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); | ||
var problemDetails = new ProblemDetails(ErrorTypes.Invalid, ProblemTitles.ValidationFailed, ErrorStatus.Validation, "Workflow instance input validation failed", errors: errors); | ||
if (OnProblem.HasDelegate) await OnProblem.InvokeAsync(problemDetails); | ||
return; | ||
} | ||
} | ||
if (OnCreate.HasDelegate) await OnCreate.InvokeAsync(payload); | ||
} | ||
|
||
async Task LoadSchemaAsync() | ||
{ | ||
var schemaDefinition = WorkflowDefinition?.Input?.Schema; | ||
if (schemaDefinition == null) return; | ||
if (schemaDefinition.Resource == null) | ||
{ | ||
switch (schemaDefinition.Format) | ||
{ | ||
case SchemaFormat.Avro: | ||
schema = Avro.Schema.Parse(JsonSerializer.SerializeToText(schemaDefinition.Document)).ToJsonSchema(); | ||
break; | ||
case SchemaFormat.Json: | ||
schema = JsonSchema.FromText(JsonSerializer.SerializeToText(schemaDefinition.Document)); | ||
break; | ||
case SchemaFormat.Xml: | ||
var xml = XmlSerializer.SerializeToText(schemaDefinition.Document); | ||
var stringReader = new StringReader(xml); | ||
schema = XmlSchema.Read(stringReader, null)!.ToJsonSchema(); | ||
break; | ||
default: | ||
throw new NotSupportedException($"The specified schema format '{schemaDefinition.Format}' is not supported"); | ||
} | ||
} | ||
else | ||
{ | ||
using var stream = await ExternalResourceProvider.ReadAsync(schemaDefinition.Resource).ConfigureAwait(false); | ||
using var streamReader = new StreamReader(stream); | ||
schema = schemaDefinition.Format switch | ||
{ | ||
SchemaFormat.Avro => Avro.Schema.Parse(await streamReader.ReadToEndAsync()).ToJsonSchema(), | ||
SchemaFormat.Json => await JsonSchema.FromStream(stream).ConfigureAwait(false), | ||
SchemaFormat.Xml => XmlSchema.Read(stream, null)!.ToJsonSchema(), | ||
_ => throw new NotSupportedException($"The specified schema format '{schemaDefinition.Format}' is not supported"), | ||
}; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
src/dashboard/Synapse.Dashboard/Components/DynamicForm/DynamicFormArray.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
@using Json.Schema | ||
@namespace Synapse.Dashboard | ||
|
||
@if(schema != null) | ||
{ | ||
if (itemsSchema != null) | ||
{ | ||
@foreach (var form in forms.OrderBy(kvp => kvp.Key)) | ||
{ | ||
<div @key="@form.Key"> | ||
@form.Value | ||
<Button Outline="true" Color="ButtonColor.Danger" Class="w-100" @onclick="@(() => OnRemoveItemAsync(form.Key))"> | ||
<Icon Name="IconName.Dash" /> | ||
Remove | ||
</Button> | ||
<hr /> | ||
</div> | ||
} | ||
<Button Outline="true" Color="ButtonColor.Success" Class="w-100" @onclick="OnAddItemAsync"> | ||
<Icon Name="IconName.Plus" /> | ||
Add | ||
</Button> | ||
} | ||
} | ||
|
||
@code { | ||
|
||
JsonSchema? schema; | ||
JsonSchema? itemsSchema; | ||
Dictionary<int, RenderFragment> forms = []; | ||
Dictionary<int, object> items = []; | ||
|
||
/// <summary> | ||
/// Gets/sets the form field's schema | ||
/// </summary> | ||
[Parameter] public JsonSchema Schema { get; set; } = null!; | ||
|
||
/// <summary> | ||
/// Gets/sets the handler to call whenever the field's value changes | ||
/// </summary> | ||
[Parameter] public EventCallback<object?> OnValueChanged { get; set; } | ||
|
||
/// <inheritdoc/> | ||
protected override void OnParametersSet() | ||
{ | ||
base.OnParametersSet(); | ||
if (schema != Schema) | ||
{ | ||
schema = Schema; | ||
itemsSchema = schema.GetItems(); | ||
} | ||
} | ||
|
||
async Task OnAddItemAsync() | ||
{ | ||
var key = forms.Count < 1 ? 0 : forms.Max(kvp => kvp.Key) + 1; | ||
forms[key] = CreateDynamicForm(key); | ||
items[key] = new { }; | ||
await OnValueChanged.InvokeAsync(items.Values); | ||
} | ||
|
||
async Task OnItemChangedAsync(int key, object value) | ||
{ | ||
items[key] = value; | ||
await this.OnValueChanged.InvokeAsync(items.Values); | ||
} | ||
|
||
async Task OnRemoveItemAsync(int key) | ||
{ | ||
var form = forms[key]; | ||
forms.Remove(key); | ||
items.Remove(key); | ||
await this.OnValueChanged.InvokeAsync(items.Values); | ||
} | ||
|
||
RenderFragment CreateDynamicForm(int key) => builder => | ||
{ | ||
builder.OpenComponent<DynamicForm>(0); | ||
builder.AddAttribute(1, "Schema", itemsSchema); | ||
builder.AddAttribute(2, "OnValueChanged", EventCallback.Factory.Create<object>(this, value => OnItemChangedAsync(key, value))); | ||
builder.CloseComponent(); | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.