Skip to content

Commit

Permalink
Refactor DataPanel usage and improve data handling (#384)
Browse files Browse the repository at this point in the history
Replaced IDictionary with DataPanelModel to simplify data management and reduce complexity. Updated DataPanelItem to include a Label field and refactored various components to adopt the new model. Improved overall readability and consistency within data-related components.
  • Loading branch information
sfmskywalker authored Jan 28, 2025
1 parent 5de1164 commit e745daf
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 152 deletions.
25 changes: 12 additions & 13 deletions src/framework/Elsa.Studio.Shared/Components/DataPanel.razor
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,33 @@
<MudSimpleTable Outlined="true" Striped="false" Dense="true" Elevation="0" Bordered="false">
<tbody>
@{
var data = (HideEmptyValues
? Data.Where(x => !string.IsNullOrWhiteSpace(x.Value.Text))
: Data)
.ToDictionary(x => x.Key, x => x.Value);
var data = HideEmptyValues
? Data.Where(x => !string.IsNullOrWhiteSpace(x.Text)).ToList()
: Data;
}
@if (data.Any())
{
@foreach (var item in data)
{
<tr>
<td style="width: 200px;">@item.Key</td>
<td style="width: 200px;">@item.Label</td>
<td style="width: 50px;">
<MudIconButton Icon="@Icons.Material.Outlined.ContentCopy" Size="Size.Small" Title="Copy" OnClick="@(() => OnCopyClicked(item.Value.Text!))" Disabled="@(string.IsNullOrWhiteSpace(item.Value.Text))"/>
<MudIconButton Icon="@Icons.Material.Outlined.ContentCopy" Size="Size.Small" Title="Copy" OnClick="@(() => OnCopyClicked(item.Text!))" Disabled="@(string.IsNullOrWhiteSpace(item.Text))"/>
</td>
<td>
@if (!string.IsNullOrWhiteSpace(item.Value.Link))
@if (!string.IsNullOrWhiteSpace(item.Link))
{
<MudLink Href="@item.Value.Link">@item.Value.Text</MudLink>
<MudLink Href="@item.Link">@item.Text</MudLink>
}
else
{
@if (@item.Key == "Created" || @item.Key == "Updated" || item.Key == "Finished")
@if (item.Label == "Created" || item.Label == "Updated" || item.Label == "Finished")
{
<span><Timestamp Value="@Convert.ToDateTime(item.Value.Text)"></Timestamp></span>
<span><Timestamp Value="@Convert.ToDateTime(item.Text)"></Timestamp></span>
}
else
{
<span>@item.Value.Text</span>
<span>@item.Text</span>
}
}
</td>
Expand All @@ -57,7 +56,7 @@
/// The data to display.
/// </summary>
[Parameter]
public IDictionary<string, DataPanelItem> Data { get; set; } = new Dictionary<string, DataPanelItem>();
public DataPanelModel Data { get; set; } = new ();

/// <summary>
/// If true, empty values will be hidden.
Expand All @@ -77,7 +76,7 @@
[Parameter]
public string NoDataMessage { get; set; } = "No data available.";

[Inject] private IClipboard Clipboard { get; set; } = default!;
[Inject] private IClipboard Clipboard { get; set; } = null!;

private async Task OnCopyClicked(string value)
{
Expand Down
2 changes: 1 addition & 1 deletion src/framework/Elsa.Studio.Shared/Models/DataPanelItem.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace Elsa.Studio.Models;

public record DataPanelItem(string? Text = default, string? Link = default);
public record DataPanelItem(string Label, string? Text = null, string? Link = null);
19 changes: 19 additions & 0 deletions src/framework/Elsa.Studio.Shared/Models/DataPanelModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Elsa.Studio.Models;

public class DataPanelModel : List<DataPanelItem>
{
public DataPanelModel()
{
}

public DataPanelModel(IEnumerable<DataPanelItem> collection) : base(collection)
{
}

public void Add(string label, string? text = null, string? link = null) => Add(new DataPanelItem(label, text, link));
}

public static class DataPanelModelLinqExtensions
{
public static DataPanelModel ToDataPanelModel(this IEnumerable<DataPanelItem> items) => new(items);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ public static class ProblemDetailsExtensions
/// </summary>
public static ValidationErrors ToValidationErrors(this ProblemDetails problemDetails)
{
var validationErrors = problemDetails.Errors.Select(x => new ValidationError(string.Join(", ", x.Value))).ToList();
return new ValidationErrors(validationErrors);
var validationErrors =
from pair in problemDetails.Errors
from message in pair.Value
select new ValidationError(message);
return new(validationErrors.ToList());
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@using Elsa.Studio.Workflows.Services
@inject ILocalizer Localizer
<Well>
<MudText Typo="Typo.overline" GutterBottom="true" Align="Align.Left">@Localizer["Information"]</MudText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ public partial class InfoTab
[Parameter]
public ActivityDescriptor ActivityDescriptor { get; set; } = default!;

private IDictionary<string, DataPanelItem> ActivityInfo { get; } = new Dictionary<string, DataPanelItem>();
private DataPanelModel ActivityInfo { get; } = new();

/// <inheritdoc />
protected override void OnParametersSet()
{
ActivityDescriptor.ConstructionProperties.TryGetValue("WorkflowDefinitionId", out var link);

ActivityInfo["Type"] = new DataPanelItem(ActivityDescriptor.TypeName,
link == null ? null : $"/workflows/definitions/{link}/edit");
ActivityInfo["Description"] = new DataPanelItem(ActivityDescriptor.Description);
ActivityInfo.Add("Type", ActivityDescriptor.TypeName, link == null ? null : $"/workflows/definitions/{link}/edit");
ActivityInfo.Add("Description", ActivityDescriptor.Description);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ await result.OnSuccessAsync(response =>
await result.OnFailedAsync(errors =>
{
onFailure?.Invoke(errors);
Snackbar.Add(string.Join(Environment.NewLine, errors.Errors.Select(x => x.ErrorMessage)), Severity.Error, options => options.VisibleStateDuration = 5000);
foreach (var error in errors.Errors)
Snackbar.Add(error.ErrorMessage, Severity.Error, options => options.VisibleStateDuration = 5000);
return Task.CompletedTask;
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@ namespace Elsa.Studio.Workflows.Components.WorkflowDefinitionEditor.Components.W

public partial class Info
{
private IDictionary<string, DataPanelItem> _workflowInfo = new Dictionary<string, DataPanelItem>();
private DataPanelModel _workflowInfo = new ();

[Parameter] public WorkflowDefinition WorkflowDefinition { get; set; } = default!;
[Parameter] public WorkflowDefinition WorkflowDefinition { get; set; } = null!;

/// <inheritdoc />
protected override void OnParametersSet()
{
_workflowInfo = new Dictionary<string, DataPanelItem>
{
["Definition ID"] = new(WorkflowDefinition.DefinitionId),
["Version ID"] = new(WorkflowDefinition.Id),
["Version"] = new(WorkflowDefinition.Version.ToString()),
["Status"] = new(WorkflowDefinition.IsPublished ? "Published" : "Draft"),
["Readonly"] = new(WorkflowDefinition.IsReadonly ? "Yes" : "No")
};
_workflowInfo =
[
new DataPanelItem("Definition ID", WorkflowDefinition.DefinitionId),
new DataPanelItem("Version ID", WorkflowDefinition.Id),
new DataPanelItem("Version", WorkflowDefinition.Version.ToString()),
new DataPanelItem("Status", WorkflowDefinition.IsPublished ? "Published" : "Draft"),
new DataPanelItem("Readonly", WorkflowDefinition.IsReadonly ? "Yes" : "No")
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@ namespace Elsa.Studio.Workflows.Components.WorkflowInstanceViewer.Components;
/// Displays the details of an activity.
public partial class ActivityDetailsTab
{
/// <summary>
/// Represents a row in the table of activity executions.
/// </summary>
/// <param name="Number">The number of executions.</param>
/// <param name="ActivityExecution">The activity execution.</param>
public record ActivityExecutionRecordTableRow(int Number, ActivityExecutionRecord ActivityExecution);

/// The height of the visible pane.
[Parameter] public int VisiblePaneHeight { get; set; }

Expand All @@ -30,11 +23,11 @@ public record ActivityExecutionRecordTableRow(int Number, ActivityExecutionRecor

private ActivityExecutionRecord? SelectedItem { get; set; } = null!;

private IDictionary<string, DataPanelItem> ActivityInfo { get; set; } = new Dictionary<string, DataPanelItem>();
private IDictionary<string, DataPanelItem> ActivityData { get; set; } = new Dictionary<string, DataPanelItem>();
private IDictionary<string, DataPanelItem> OutcomesData { get; set; } = new Dictionary<string, DataPanelItem>();
private IDictionary<string, DataPanelItem> OutputData { get; set; } = new Dictionary<string, DataPanelItem>();
private IDictionary<string, DataPanelItem> ExceptionData { get; set; } = new Dictionary<string, DataPanelItem>();
private DataPanelModel ActivityInfo { get; set; } = new();
private DataPanelModel ActivityData { get; set; } = new();
private DataPanelModel OutcomesData { get; set; } = new();
private DataPanelModel OutputData { get; set; } = new();
private DataPanelModel ExceptionData { get; set; } = new();
private IDictionary<string, string?> SelectedActivityState { get; set; } = new Dictionary<string, string?>();
private IDictionary<string, string?> SelectedOutcomesData { get; set; } = new Dictionary<string, string?>();
private IDictionary<string, string?> SelectedOutputData { get; set; } = new Dictionary<string, string?>();
Expand Down Expand Up @@ -70,28 +63,28 @@ private void CreateDataModels()
var exception = execution?.Exception;
var workflowDefinitionId = activity.GetIsWorkflowDefinitionActivity() ? activity.GetWorkflowDefinitionId() : null;

var activityInfo = new Dictionary<string, DataPanelItem>
var activityInfo = new DataPanelModel
{
["ID"] = new(activityId),
["Name"] = new(activityName),
["Type"] = new(activityType,
new DataPanelItem("ID", activityId),
new DataPanelItem("Name", activityName),
new DataPanelItem("Type", activityType,
string.IsNullOrWhiteSpace(workflowDefinitionId)
? null
: $"/workflows/definitions/{workflowDefinitionId}/edit"),
["Version"] = new(activityVersion.ToString())
new DataPanelItem("Version", activityVersion.ToString())
};

var outcomesData = new Dictionary<string, DataPanelItem>();
var outputData = new Dictionary<string, DataPanelItem>();
var outcomesData = new DataPanelModel();
var outputData = new DataPanelModel();

if (execution != null)
{
activityInfo["Status"] = new(execution.Status.ToString());
activityInfo["Instance ID"] = new(execution.Id);
activityInfo.Add("Status", execution.Status.ToString());
activityInfo.Add("Instance ID", execution.Id);

if (execution.Payload != null)
if (execution.Payload.TryGetValue("Outcomes", out var outcomes))
outcomesData["Outcomes"] = new(outcomes.ToString());
outcomesData.Add("Outcomes", outcomes.ToString());

var outputDescriptors = activityDescriptor.Outputs;
var outputs = execution.Outputs;
Expand All @@ -101,34 +94,34 @@ private void CreateDataModels()
var outputValue = outputs != null
? outputs.TryGetValue(outputDescriptor.Name, out var value) ? value : null
: null;
outputData[outputDescriptor.Name] = new(outputValue?.ToString());
outputData.Add(outputDescriptor.Name, outputValue?.ToString());
}
}
else
{
activityInfo["Status"] = new("Not executed");
activityInfo.Add("Status", "Not executed");
}

var exceptionData = new Dictionary<string, DataPanelItem>();
var exceptionData = new DataPanelModel();

if (exception != null)
{
exceptionData["Message"] = new(exception.Message);
exceptionData["InnerException"] = new(exception.InnerException != null
exceptionData.Add("Message", exception.Message);
exceptionData.Add("InnerException", exception.InnerException != null
? exception.InnerException.Type + ": " + exception.InnerException.Message
: null);
exceptionData["StackTrace"] = new(exception.StackTrace);
exceptionData.Add("StackTrace", exception.StackTrace);
}

var activityStateData = new Dictionary<string, DataPanelItem>();
var activityStateData = new DataPanelModel();
var activityState = execution?.ActivityState;

if (activityState != null)
{
foreach (var inputDescriptor in activityDescriptor.Inputs)
{
var inputValue = activityState.TryGetValue(inputDescriptor.Name, out var value) ? value : null;
activityStateData[inputDescriptor.Name] = new(inputValue?.ToString());
activityStateData.Add(inputDescriptor.Name, inputValue?.ToString());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,56 +20,57 @@ public record ActivityExecutionRecordTableRow(int Number, ActivityExecutionRecor
[Parameter] public int VisiblePaneHeight { get; set; }

/// The activity to display executions for.
[Parameter] public JsonObject Activity { get; set; } = default!;
[Parameter] public JsonObject Activity { get; set; } = null!;

/// The activity execution record summaries.
[Parameter] public ICollection<ActivityExecutionRecordSummary> ActivityExecutionSummaries { get; set; } = new List<ActivityExecutionRecordSummary>();
[Inject] private IActivityExecutionService ActivityExecutionService { get; set; } = default!;

[Inject] private IActivityExecutionService ActivityExecutionService { get; set; } = null!;

private IEnumerable<ActivityExecutionRecordTableRow> Items => ActivityExecutionSummaries.Select((x, i) => new ActivityExecutionRecordTableRow(i + 1, x));
private ActivityExecutionRecord? SelectedItem { get; set; } = default!;
private IDictionary<string, DataPanelItem> SelectedActivityState { get; set; } = new Dictionary<string, DataPanelItem>();
private IDictionary<string, DataPanelItem> SelectedOutcomesData { get; set; } = new Dictionary<string, DataPanelItem>();
private IDictionary<string, DataPanelItem> SelectedOutputData { get; set; } = new Dictionary<string, DataPanelItem>();
private ActivityExecutionRecord? SelectedItem { get; set; } = null!;
private DataPanelModel SelectedActivityState { get; set; } = new();
private DataPanelModel SelectedOutcomesData { get; set; } = new();
private DataPanelModel SelectedOutputData { get; set; } = new();
private Timer? _refreshTimer;

/// Refreshes the component.
public async Task RefreshAsync()
{
await StopRefreshTimerAsync();
SelectedItem = null;
SelectedActivityState = new Dictionary<string, DataPanelItem>();
SelectedOutcomesData = new Dictionary<string, DataPanelItem>();
SelectedOutputData = new Dictionary<string, DataPanelItem>();
SelectedActivityState = new();
SelectedOutcomesData = new();
SelectedOutputData = new();
}

private void CreateSelectedItemDataModels(ActivityExecutionRecord? record)
{
if (record == null)
{
SelectedActivityState = new Dictionary<string, DataPanelItem>();
SelectedOutcomesData = new Dictionary<string, DataPanelItem>();
SelectedOutputData = new Dictionary<string, DataPanelItem>();
SelectedActivityState = new();
SelectedOutcomesData = new();
SelectedOutputData = new();
return;
}

var activityState = record.ActivityState?
.Where(x => !x.Key.StartsWith("_"))
.ToDictionary(x => x.Key, x => new DataPanelItem(x.Value?.ToString()));
.Select(x => new DataPanelItem(x.Key, x.Value?.ToString()))
.ToDataPanelModel();

var outcomesData = record.Payload?.TryGetValue("Outcomes", out var outcomesValue) == true
? new Dictionary<string, DataPanelItem> { ["Outcomes"] = new(outcomesValue!.ToString()!) }
: default;
? new DataPanelModel { new DataPanelItem("Outcomes", outcomesValue!.ToString()!) }
: null;

var outputData = new Dictionary<string, DataPanelItem>();
var outputData = new DataPanelModel();

if (record.Outputs != null)
foreach (var (key, value) in record.Outputs)
outputData[key] = new(value?.ToString());
outputData.Add(key, value?.ToString());

SelectedActivityState = activityState ?? new Dictionary<string, DataPanelItem>();
SelectedOutcomesData = outcomesData ?? new Dictionary<string, DataPanelItem>();
SelectedActivityState = activityState ?? new();
SelectedOutcomesData = outcomesData ?? new();
SelectedOutputData = outputData;
}

Expand All @@ -84,10 +85,10 @@ private async Task OnActivityExecutionClicked(TableRowClickEventArgs<ActivityExe
{
await StopRefreshTimerAsync();
var id = arg.Item?.ActivityExecutionSummary.Id;

if (id == null)
return;

await RefreshSelectedItemAsync(id);

if (SelectedItem == null)
Expand All @@ -105,7 +106,7 @@ async void Callback(object? _)
{
await RefreshSelectedItemAsync(id);

if (SelectedItem == null || SelectedItem.IsFused())
if (SelectedItem == null || SelectedItem.IsFused())
await StopRefreshTimerAsync();
}

Expand Down
Loading

0 comments on commit e745daf

Please # to comment.