12 changed files with 347 additions and 0 deletions
@ -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> |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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."]); |
||||
|
} |
||||
|
} |
||||
@ -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 /> |
||||
@ -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(); |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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(); |
||||
|
|
||||
|
}; |
||||
|
} |
||||
Loading…
Reference in new issue