Browse Source

feat: Add widget for editing workflow definition propertites

pull/1568/head
colin 3 weeks ago
parent
commit
5d72cd90f4
  1. 2
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/AbpElsaNextStudioBlazorModule.cs
  2. 18
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/EditPropertyDialog.razor
  3. 80
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/EditPropertyDialog.razor.cs
  4. 17
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/PropertyModel.cs
  5. 21
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/PropertyModelValidator.cs
  6. 52
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/WorkflowDefinitionPropertitesEditor.razor
  7. 95
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/WorkflowDefinitionPropertitesEditor.razor.cs
  8. 15
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Extensions/ServiceCollectionExtensions.cs
  9. 12
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/en.json
  10. 12
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/zh-Hans.json
  11. 19
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Widgets/WorkflowDefinitionPropertitesEditorWidget.cs
  12. 4
      aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/_Imports.razor

2
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/AbpElsaNextStudioBlazorModule.cs

@ -9,6 +9,7 @@ using Elsa.Studio.WorkflowContexts.Extensions;
using Elsa.Studio.Workflows.Designer.Options;
using Elsa.Studio.Workflows.Extensions;
using LINGYUN.Abp.ElsaNext.Localization;
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Extensions;
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Navigation;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@ -81,6 +82,7 @@ public class AbpElsaNextStudioBlazorModule : AbpModule
context.Services.AddWorkflowsModule();
context.Services.AddWorkflowContextsModule();
context.Services.AddSettingsModule();
context.Services.AddAbpElsaStudioModule();
Configure<DesignerOptions>(configuration.GetSection("DesignerOptions"));

18
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/EditPropertyDialog.razor

@ -0,0 +1,18 @@
@inject ILocalizer Localizer
@inherits StudioComponentBase
<MudDialog>
<DialogContent>
<EditForm EditContext="_editContext" OnValidSubmit="OnValidSubmit">
<FluentValidationValidator @ref="_fluentValidationValidator" Validator="_validator" DisableAssemblyScanning="true" />
<MudStack>
<MudTextField Label="@Localizer["Key"]" ReadOnly="_isEdit" @bind-Value="_model.Key" For="@(() => _model.Key)" HelperText="@Localizer["The key of the property."]" Variant="Variant.Outlined" Margin="Margin.Dense" />
<MudTextField Label="@Localizer["Value"]" @bind-Value="_model.Value" For="@(() => _model.Value)" HelperText="@Localizer["The value of the property."]" Variant="Variant.Outlined" Margin="Margin.Dense" />
</MudStack>
</EditForm>
</DialogContent>
<DialogActions>
<MudButton OnClick="OnCancelClicked">@Localizer["Cancel"]</MudButton>
<MudButton Color="Color.Primary" OnClick="OnSubmitClicked">@Localizer["Ok"]</MudButton>
</DialogActions>
</MudDialog>

80
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/EditPropertyDialog.razor.cs

@ -0,0 +1,80 @@
using Blazored.FluentValidation;
using Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using MudBlazor;
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor.Components.WorkflowProperties.Tabs.Properties.Sections.Properties;
public partial class EditPropertyDialog
{
private bool _isEdit = false;
private readonly PropertyModel _model = new();
private EditContext _editContext = null!;
private PropertyModelValidator _validator = null!;
private FluentValidationValidator _fluentValidationValidator = null!;
[Parameter] public WorkflowDefinition WorkflowDefinition { get; set; } = null!;
[Parameter] public PropertyModel? Property { get; set; }
[CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!;
protected override async Task OnParametersSetAsync()
{
_editContext = new(_model);
_validator = new(WorkflowDefinition, Localizer);
if (Property == null)
{
_model.Key = GetNewPropertyKey(WorkflowDefinition.CustomProperties);
_isEdit = false;
}
else
{
_model.Key = Property.Key;
_model.Value = Property.Value;
_isEdit = true;
}
}
private string GetNewPropertyKey(IDictionary<string, object> existingPropertites)
{
var count = 0;
while (true)
{
var key = $"Property{++count}";
if (existingPropertites.All(x => x.Key != key))
{
return key;
}
}
}
private Task OnCancelClicked()
{
MudDialog.Cancel();
return Task.CompletedTask;
}
private async Task OnSubmitClicked()
{
if (!await _fluentValidationValidator.ValidateAsync())
{
return;
}
await OnValidSubmit();
}
private Task OnValidSubmit()
{
var property = Property ?? new PropertyModel();
property.Key = _model.Key;
property.Value = _model.Value;
MudDialog.Close(property);
return Task.CompletedTask;
}
}

17
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/PropertyModel.cs

@ -0,0 +1,17 @@
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor.Components.WorkflowProperties.Tabs.Properties.Sections.Properties;
public class PropertyModel
{
public string Key { get; set; } = null!;
public string Value { get; set; } = null!;
public PropertyModel()
{
}
public PropertyModel(string key, string value)
{
Key = key;
Value = value;
}
}

21
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/PropertyModelValidator.cs

@ -0,0 +1,21 @@
using Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
using Elsa.Studio.Localization;
using FluentValidation;
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor.Components.WorkflowProperties.Tabs.Properties.Sections.Properties;
public class PropertyModelValidator : AbstractValidator<PropertyModel>
{
public PropertyModelValidator(WorkflowDefinition workflowDefinition, ILocalizer localizer)
{
RuleFor(x => x.Key).NotEmpty().WithMessage(localizer["Please enter a key for the property."]);
RuleFor(x => x.Value)
.Must((context, name, cancellationToken) =>
{
var existingKey = workflowDefinition.CustomProperties.Where(x => x.Key == name).Select(x => x.Key).FirstOrDefault();
return existingKey == null || existingKey == context.Key;
})
.WithMessage(localizer["A property with this key already exists in the current scope."]);
}
}

52
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/WorkflowDefinitionPropertitesEditor.razor

@ -0,0 +1,52 @@
@inject ILocalizer Localizer
@inherits StudioComponentBase
<VerticalWell ExtraPadding="40">
<MudText Typo="Typo.overline">@Localizer["Propertites"]</MudText>
<MudStack>
<MudButton StartIcon="@Icons.Material.Outlined.Add"
Variant="Variant.Filled"
Color="Color.Primary"
Class="align-self-end"
OnClick="OnAddPropertyClicked"
Disabled="IsReadOnly">
@Localizer["Add property"]
</MudButton>
@if (!Properties.Any())
{
<MudAlert Severity="Severity.Normal" Variant="Variant.Text" Icon="@Icons.Material.Outlined.Info"> @Localizer["There are currently no propertites defined."]</MudAlert>
}
else
{
<VerticalWell ExtraPadding="160">
<MudSimpleTable Dense="true" Bordered="false" Striped="false" Elevation="0" Outlined="true" FixedHeader="true">
<thead>
<tr>
<th>@Localizer["Key"]</th>
<th>@Localizer["Value"]</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var property in Properties)
{
<tr>
<td>@property.Key</td>
<td>@property.Value</td>
<td style="text-align: right;">
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Size="Size.Small" Dense="true" Disabled="IsReadOnly">
<MudMenuItem Icon="@Icons.Material.Outlined.Edit" OnClick="@(() => OnEditClicked(property))">@Localizer["Edit"]</MudMenuItem>
<MudMenuItem Icon="@Icons.Material.Outlined.Delete" OnClick="@(() => OnDeleteClicked(property))">@Localizer["Delete"]</MudMenuItem>
</MudMenu>
</td>
</tr>
}
</tbody>
</MudSimpleTable>
</VerticalWell>
}
</MudStack>
</VerticalWell>
<MudDivider />

95
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/WorkflowDefinitionPropertitesEditor.razor.cs

@ -0,0 +1,95 @@
using Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
using Elsa.Studio.Workflows.UI.Contracts;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor.Components.WorkflowProperties.Tabs.Properties.Sections.Properties;
public partial class WorkflowDefinitionPropertitesEditor
{
[Parameter]
public WorkflowDefinition WorkflowDefinition { get; set; } = default!;
[Parameter]
public EventCallback WorkflowDefinitionUpdated { get; set; }
[CascadingParameter] public IWorkspace? Workspace { get; set; }
[Inject] IDialogService DialogService { get; set; } = default!;
private bool IsReadOnly => Workspace?.IsReadOnly ?? true;
private ICollection<PropertyModel> Properties => WorkflowDefinition.CustomProperties
.Select(x => new PropertyModel(x.Key, x.Value.ToString()!))
.ToList();
private async Task RaiseWorkflowDefinitionUpdatedAsync()
{
if (WorkflowDefinitionUpdated.HasDelegate)
{
await InvokeAsync(WorkflowDefinitionUpdated.InvokeAsync);
}
}
private async Task OnEditClicked(PropertyModel property)
{
await OpenPropertyEditorDialog(property);
}
private async Task OnDeleteClicked(PropertyModel property)
{
var result = await DialogService.ShowMessageBoxAsync(Localizer["Delete selected property?"], Localizer["Are you sure you want to delete the selected property?"], yesText: Localizer["Delete"], cancelText: Localizer["Cancel"]);
if (result != true)
{
return;
}
WorkflowDefinition.CustomProperties.RemoveAll(x => x.Key == property.Key);
await RaiseWorkflowDefinitionUpdatedAsync();
}
private async Task OnAddPropertyClicked()
{
await OpenPropertyEditorDialog(null);
}
private async Task OpenPropertyEditorDialog(PropertyModel? property)
{
var isNew = property == null;
var parameters = new DialogParameters<EditPropertyDialog>
{
[nameof(EditPropertyDialog.WorkflowDefinition)] = WorkflowDefinition
};
if (!isNew)
{
parameters[nameof(EditPropertyDialog.Property)] = property;
}
var options = new DialogOptions
{
MaxWidth = MaxWidth.Medium,
FullWidth = true,
CloseButton = true,
CloseOnEscapeKey = true
};
var title = property == null ? Localizer["Create property"] : Localizer["Edit property"];
var dialog = await DialogService.ShowAsync<EditPropertyDialog>(title, parameters, options);
var result = await dialog.Result;
if (result?.Canceled != false)
{
return;
}
if (result.Data is PropertyModel newProperty)
{
WorkflowDefinition.CustomProperties[newProperty.Key] = newProperty.Value;
}
await RaiseWorkflowDefinitionUpdatedAsync();
}
}

15
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Extensions/ServiceCollectionExtensions.cs

@ -0,0 +1,15 @@
using Elsa.Studio.Contracts;
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Widgets;
using Microsoft.Extensions.DependencyInjection;
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor.Extensions;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddAbpElsaStudioModule(this IServiceCollection services)
{
services.AddScoped<IWidget, WorkflowDefinitionPropertitesEditorWidget>();
return services;
}
}

12
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/en.json

@ -5,6 +5,18 @@
"Menu:WorkflowDefinitions": "Workflow Definitions",
"Menu:WorkflowInstances": "Workflow Instances",
"Menu:Settings": "Settings",
"Propertites": "Propertites",
"Key": "Key",
"Create property": "Create property",
"Edit property": "Edit property",
"Delete selected property?": "Delete selected property?",
"Are you sure you want to delete the selected property?": "Are you sure you want to delete the selected property?",
"Add property": "Add property",
"The key of the property.": "The key of the property.",
"The value of the property.": "The value of the property.",
"There are currently no propertites defined.": "There are currently no propertites defined.",
"Please enter a key for the property.": "Please enter a key for the property.",
"A property with this key already exists in the current scope.": "A property with this key already exists in the current scope.",
"Select": "Select",
"14 days": "14 days",
"180 days": "180 days",

12
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/zh-Hans.json

@ -5,6 +5,18 @@
"Menu:WorkflowDefinitions": "工作流定义",
"Menu:WorkflowInstances": "工作流实例",
"Menu:Settings": "设置",
"Propertites": "属性",
"Key": "键",
"Create property": "创建属性",
"Edit property": "编辑属性",
"Delete selected property?": "删除所选属性?",
"Are you sure you want to delete the selected property?": "您确定要删除所选属性吗?",
"Add property": "添加属性",
"The key of the property.": "属性的键名。",
"The value of the property.": "属性的值。",
"There are currently no propertites defined.": "目前没有定义任何属性。",
"Please enter a key for the property.": "请输入属性的键名。",
"A property with this key already exists in the current scope.": "当前作用域中已存在具有此键的属性。",
"Select": "选择",
"180 days": "180 天",
"30 days": "30 天",

19
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Widgets/WorkflowDefinitionPropertitesEditorWidget.cs

@ -0,0 +1,19 @@
using Elsa.Studio.Workflows.Widgets;
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Components.WorkflowProperties.Tabs.Properties.Sections.Properties;
using Microsoft.AspNetCore.Components;
namespace LINGYUN.Abp.ElsaNext.Studio.Blazor.Widgets;
public class WorkflowDefinitionPropertitesEditorWidget : WorkflowDefinitionPropertiesWidgetBase
{
public override double Order => 15;
public override Func<IDictionary<string, object?>, RenderFragment> Render => attributes => builder =>
{
builder.OpenComponent<WorkflowDefinitionPropertitesEditor>(0);
builder.AddAttribute(1, nameof(WorkflowDefinitionPropertitesEditor.WorkflowDefinition), attributes["WorkflowDefinition"]);
builder.AddAttribute(2, nameof(WorkflowDefinitionPropertitesEditor.WorkflowDefinitionUpdated), attributes["WorkflowDefinitionUpdated"]);
builder.CloseComponent();
};
}

4
aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/_Imports.razor

@ -1,11 +1,15 @@
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Rendering
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using MudBlazor
@using MudExtensions
@using Blazored.FluentValidation
@using Elsa.Studio.Components
@using Elsa.Studio.Localization
@using Elsa.Studio.Workflows.Components.WorkflowDefinitionEditor
@using Elsa.Studio.Workflows.Components.WorkflowInstanceViewer
@using Elsa.Studio.Workflows.Components.WorkflowDefinitionList

Loading…
Cancel
Save