diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/AbpElsaNextStudioBlazorModule.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/AbpElsaNextStudioBlazorModule.cs index 6e6d7d97a..abc027ec9 100644 --- a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/AbpElsaNextStudioBlazorModule.cs +++ b/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(configuration.GetSection("DesignerOptions")); diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/EditPropertyDialog.razor b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/EditPropertyDialog.razor new file mode 100644 index 000000000..236963fb1 --- /dev/null +++ b/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 + + + + + + + + + + + + + @Localizer["Cancel"] + @Localizer["Ok"] + + \ No newline at end of file diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/EditPropertyDialog.razor.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/EditPropertyDialog.razor.cs new file mode 100644 index 000000000..47585d0c1 --- /dev/null +++ b/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 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; + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/PropertyModel.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/PropertyModel.cs new file mode 100644 index 000000000..5f69cccb3 --- /dev/null +++ b/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; + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/PropertyModelValidator.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/PropertyModelValidator.cs new file mode 100644 index 000000000..5303e6b5c --- /dev/null +++ b/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 +{ + 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."]); + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/WorkflowDefinitionPropertitesEditor.razor b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/WorkflowDefinitionPropertitesEditor.razor new file mode 100644 index 000000000..2052f80e1 --- /dev/null +++ b/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 + + + @Localizer["Propertites"] + + + @Localizer["Add property"] + + + @if (!Properties.Any()) + { + @Localizer["There are currently no propertites defined."] + } + else + { + + + + + @Localizer["Key"] + @Localizer["Value"] + + + + + + @foreach (var property in Properties) + { + + @property.Key + @property.Value + + + @Localizer["Edit"] + @Localizer["Delete"] + + + + } + + + + } + + + diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/WorkflowDefinitionPropertitesEditor.razor.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Components/WorkflowProperties/Tabs/Properties/Sections/Properties/WorkflowDefinitionPropertitesEditor.razor.cs new file mode 100644 index 000000000..17d177cc0 --- /dev/null +++ b/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 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 + { + [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(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(); + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Extensions/ServiceCollectionExtensions.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..77ea56e7e --- /dev/null +++ b/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(); + + return services; + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/en.json b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/en.json index 48535886a..f0470dbbd 100644 --- a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/en.json +++ b/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", diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/zh-Hans.json b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/zh-Hans.json index 7ae90f140..668522aea 100644 --- a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Localization/Resources/ElsaStudioBlazor/zh-Hans.json +++ b/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 天", diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Widgets/WorkflowDefinitionPropertitesEditorWidget.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/Widgets/WorkflowDefinitionPropertitesEditorWidget.cs new file mode 100644 index 000000000..f6fe129fb --- /dev/null +++ b/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, RenderFragment> Render => attributes => builder => + { + builder.OpenComponent(0); + builder.AddAttribute(1, nameof(WorkflowDefinitionPropertitesEditor.WorkflowDefinition), attributes["WorkflowDefinition"]); + builder.AddAttribute(2, nameof(WorkflowDefinitionPropertitesEditor.WorkflowDefinitionUpdated), attributes["WorkflowDefinitionUpdated"]); + builder.CloseComponent(); + + }; +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/_Imports.razor b/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/_Imports.razor index 81f24c47f..148ae623d 100644 --- a/aspnet-core/modules/elsa/LINGYUN.Abp.ElsaNext.Studio.Blazor/_Imports.razor +++ b/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