diff --git a/src/modules/Elsa.Studio.Workflows.Core/UI/Contracts/IDiagramDesigner.cs b/src/modules/Elsa.Studio.Workflows.Core/UI/Contracts/IDiagramDesigner.cs index e77f26fe6..df0d984f2 100644 --- a/src/modules/Elsa.Studio.Workflows.Core/UI/Contracts/IDiagramDesigner.cs +++ b/src/modules/Elsa.Studio.Workflows.Core/UI/Contracts/IDiagramDesigner.cs @@ -1,7 +1,6 @@ using System.Text.Json.Nodes; using Elsa.Studio.Workflows.Domain.Models; using Elsa.Studio.Workflows.UI.Contexts; -using Elsa.Studio.Workflows.UI.Models; using Microsoft.AspNetCore.Components; namespace Elsa.Studio.Workflows.UI.Contracts; diff --git a/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/package.json b/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/package.json index 414289dea..b618ee26e 100644 --- a/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/package.json +++ b/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/package.json @@ -8,6 +8,7 @@ "@antv/layout": "^0.3.25", "@antv/x6": "^2.18.1", "@antv/x6-plugin-clipboard": "^2.1.6", + "@antv/x6-plugin-export": "^2.1.6", "@antv/x6-plugin-history": "^2.2.4", "@antv/x6-plugin-keyboard": "^2.2.3", "@antv/x6-plugin-scroller": "^2.0.10", diff --git a/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/create-graph.ts b/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/create-graph.ts index 09b6d97fe..10816b8e6 100644 --- a/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/create-graph.ts +++ b/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/create-graph.ts @@ -4,7 +4,8 @@ import {Snapline} from "@antv/x6-plugin-snapline"; import {Transform} from "@antv/x6-plugin-transform"; import {Keyboard} from "@antv/x6-plugin-keyboard"; import {Clipboard} from '@antv/x6-plugin-clipboard'; -import {History} from '@antv/x6-plugin-history'; +import { History } from '@antv/x6-plugin-history'; +import { Export } from "@antv/x6-plugin-export"; import {DotNetComponentRef, graphBindings} from "./graph-bindings"; import {DotNetFlowchartDesigner} from "./dotnet-flowchart-designer"; import {Activity} from "../models"; @@ -109,6 +110,8 @@ export async function createGraph(containerId: string, componentRef: DotNetCompo } }); + graph.use(new Export()); + graph.use( new History({ enabled: true, diff --git a/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/export-content.ts b/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/export-content.ts new file mode 100644 index 000000000..e6d70276a --- /dev/null +++ b/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/export-content.ts @@ -0,0 +1,30 @@ +import { graphBindings } from "./graph-bindings"; + +export interface CaptureOptions { + fileName?: string; + padding?: number; + format?: string; +} + +export function exportContentToJPEG(graphId: string, options: CaptureOptions) { + const { graph } = graphBindings[graphId]; + if (!graph) return; + + graph.exportJPEG(options.fileName + ".jpeg", { + padding: options.padding, + }); +} +export function exportContentToPNG(graphId: string, options: CaptureOptions) { + const { graph } = graphBindings[graphId]; + if (!graph) return; + + graph.exportPNG(options.fileName + ".png", { + padding: options.padding, + }); +} +export function exportContentToSVG(graphId: string, options: CaptureOptions) { + const { graph } = graphBindings[graphId]; + if (!graph) return; + + graph.exportSVG(options.fileName + ".svg", {}); +} \ No newline at end of file diff --git a/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/index.ts b/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/index.ts index 6fc148758..a7ba4b364 100644 --- a/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/index.ts +++ b/src/modules/Elsa.Studio.Workflows.Designer/ClientLib/src/designer/api/index.ts @@ -3,6 +3,7 @@ export * from './calculate-activity-size'; export * from './center-content'; export * from './create-graph'; export * from './dispose-graph'; +export * from './export-content'; export * from './graph-bindings'; export * from './load-graph'; export * from './paste-cells'; diff --git a/src/modules/Elsa.Studio.Workflows.Designer/Components/FlowchartDesigner.razor.cs b/src/modules/Elsa.Studio.Workflows.Designer/Components/FlowchartDesigner.razor.cs index 43a45b277..6d855508b 100644 --- a/src/modules/Elsa.Studio.Workflows.Designer/Components/FlowchartDesigner.razor.cs +++ b/src/modules/Elsa.Studio.Workflows.Designer/Components/FlowchartDesigner.razor.cs @@ -327,6 +327,12 @@ public async Task SelectActivityAsync(string id) /// public async Task CenterContentAsync() => await ScheduleGraphActionAsync(() => _graphApi.CenterContentAsync()); + /// + /// Exports the graphs content to a supplied format. + /// + /// The capture options + public async Task ExportContentToFormatAsync(CaptureOptions captureOptions) => await ScheduleGraphActionAsync(() => _graphApi.ExportContentToFormatAsync(captureOptions)); + /// Update the Graph Layout. public async Task AutoLayoutAsync( JsonObject activity, diff --git a/src/modules/Elsa.Studio.Workflows.Designer/Elsa.Studio.Workflows.Designer.csproj b/src/modules/Elsa.Studio.Workflows.Designer/Elsa.Studio.Workflows.Designer.csproj index 721bdb1c8..0412f23eb 100644 --- a/src/modules/Elsa.Studio.Workflows.Designer/Elsa.Studio.Workflows.Designer.csproj +++ b/src/modules/Elsa.Studio.Workflows.Designer/Elsa.Studio.Workflows.Designer.csproj @@ -6,25 +6,16 @@ - + - + - - - - - - - - - - - + + diff --git a/src/modules/Elsa.Studio.Workflows.Designer/Interop/X6GraphApi.cs b/src/modules/Elsa.Studio.Workflows.Designer/Interop/X6GraphApi.cs index c28d41fea..63b12aea0 100644 --- a/src/modules/Elsa.Studio.Workflows.Designer/Interop/X6GraphApi.cs +++ b/src/modules/Elsa.Studio.Workflows.Designer/Interop/X6GraphApi.cs @@ -3,6 +3,7 @@ using System.Text.Json.Serialization; using Elsa.Studio.Workflows.Designer.Contracts; using Elsa.Studio.Workflows.Designer.Models; +using Elsa.Studio.Workflows.Designer.Options; using Microsoft.Extensions.DependencyInjection; using Microsoft.JSInterop; @@ -93,6 +94,9 @@ public async Task LoadGraphAsync(X6Graph graph) /// Center the canvas content. public async Task CenterContentAsync() => await InvokeAsync(module => module.InvokeVoidAsync("centerContent", _containerId)); + /// Exports the graphs content to a supplied + public async Task ExportContentToFormatAsync(CaptureOptions captureOptions) => await InvokeAsync(module => module.InvokeVoidAsync($"exportContentTo{captureOptions.Format}", _containerId, captureOptions)); + /// Adjusts the graph layout. public async Task AutoLayoutAsync(X6Graph graph) { diff --git a/src/modules/Elsa.Studio.Workflows.Designer/Options/CaptureOptions.cs b/src/modules/Elsa.Studio.Workflows.Designer/Options/CaptureOptions.cs new file mode 100644 index 000000000..d6ecfc603 --- /dev/null +++ b/src/modules/Elsa.Studio.Workflows.Designer/Options/CaptureOptions.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; + +namespace Elsa.Studio.Workflows.Designer.Options; + +/// +/// Represents the workflow capture options +/// +public class CaptureOptions +{ + /// + /// Gets or sets the export format. + /// Supported formats are JPEG, SVG and PNG. + /// Default: PNG. + /// + [Required] public string? Format { get; set; } = "PNG"; + + /// + /// Gets or sets the filename. + /// Default: Flowchart + /// + [Required] public string? FileName { get; set; } = "Flowchart"; + + /// + /// Gets or sets the padding around the workflow. + /// Default: 150. + /// + public int Padding { get; set; } = 150; +} \ No newline at end of file diff --git a/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/CaptureFlowChartDialog.razor.cs b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/CaptureFlowChartDialog.razor.cs new file mode 100644 index 000000000..d6b21308d --- /dev/null +++ b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/CaptureFlowChartDialog.razor.cs @@ -0,0 +1,48 @@ +using Blazored.FluentValidation; +using Elsa.Studio.Workflows.Designer.Options; +using Elsa.Studio.Workflows.Validators; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Forms; +using MudBlazor; + +namespace Elsa.Studio.Workflows.DiagramDesigners.Flowcharts +{ + public partial class CaptureFlowchartDialog + { + private readonly CaptureOptions _captureModel = new(); + private EditContext _editContext = null!; + private CaptureOptionsValidator _validator = null!; + private FluentValidationValidator _fluentValidationValidator = null!; + private bool loading = false; + + [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!; + [Parameter] public string FileName { get; set; } = null!; + + protected override void OnParametersSet() + { + _captureModel.FileName = FileName; + _editContext = new(_captureModel); + _validator = new(Localizer); + } + + private Task OnCancelClicked() + { + MudDialog.Cancel(); + return Task.CompletedTask; + } + + private async Task OnSubmitClicked() + { + if (!await _fluentValidationValidator.ValidateAsync()) + return; + + await OnValidSubmit(); + } + + private Task OnValidSubmit() + { + MudDialog.Close(_captureModel); + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/CaptureFlowchartDialog.razor b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/CaptureFlowchartDialog.razor new file mode 100644 index 000000000..10d40e64a --- /dev/null +++ b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/CaptureFlowchartDialog.razor @@ -0,0 +1,28 @@ +@using Variant = MudBlazor.Variant +@inherits StudioComponentBase +@using Elsa.Studio.Workflows.Services +@inject ILocalizer Localizer + + + + + + + + PNG + JPEG + SVG + + + @if (_captureModel.Format != "SVG") + { + + } + + + + + @Localizer["Cancel"] + @Localizer["Ok"] + + \ No newline at end of file diff --git a/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDesignerWrapper.razor.cs b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDesignerWrapper.razor.cs index 86d777038..1b668996c 100644 --- a/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDesignerWrapper.razor.cs +++ b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDesignerWrapper.razor.cs @@ -1,10 +1,9 @@ -using System.Text.Json; -using System.Text.Json.Nodes; using Elsa.Api.Client.Extensions; using Elsa.Api.Client.Resources.ActivityDescriptors.Enums; using Elsa.Api.Client.Resources.ActivityDescriptors.Models; using Elsa.Api.Client.Shared.Models; using Elsa.Studio.Workflows.Designer.Components; +using Elsa.Studio.Workflows.Designer.Options; using Elsa.Studio.Workflows.Domain.Contracts; using Elsa.Studio.Workflows.Domain.Models; using Elsa.Studio.Workflows.Extensions; @@ -14,6 +13,8 @@ using Humanizer; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; +using System.Text.Json; +using System.Text.Json.Nodes; namespace Elsa.Studio.Workflows.DiagramDesigners.Flowcharts; @@ -137,7 +138,14 @@ public async Task UpdateActivityAsync(string id, JsonObject activity) /// Centers the content of the designer. /// public async Task CenterContentAsync() => await Designer.CenterContentAsync(); - + + /// + /// Exports the graphs content to a supplied format. + /// + /// The capture options + /// + public async Task ExportContentToFormatAsync(CaptureOptions captureOptions) => await Designer.ExportContentToFormatAsync(captureOptions); + /// /// Auto layouts the flowchart. /// @@ -207,7 +215,4 @@ private async Task OnCanvasSelected() if (ActivitySelected.HasDelegate) await ActivitySelected.InvokeAsync(Flowchart); } - - private async Task OnZoomToFitClick() => await Designer.ZoomToFitAsync(); - private async Task OnCenterContentClick() => await Designer.CenterContentAsync(); } \ No newline at end of file diff --git a/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDiagramDesigner.cs b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDiagramDesigner.cs index 9965a032b..c2404ce43 100644 --- a/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDiagramDesigner.cs +++ b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDiagramDesigner.cs @@ -1,53 +1,38 @@ -using System.Text.Json.Nodes; +using Elsa.Api.Client.Extensions; using Elsa.Studio.Localization; +using Elsa.Studio.Workflows.Designer.Options; using Elsa.Studio.Workflows.Domain.Models; -using Elsa.Studio.Workflows.Models; using Elsa.Studio.Workflows.UI.Contexts; using Elsa.Studio.Workflows.UI.Contracts; -using Elsa.Studio.Workflows.UI.Models; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using MudBlazor; +using System.Text.Json.Nodes; namespace Elsa.Studio.Workflows.DiagramDesigners.Flowcharts; /// /// A diagram designer that displays a flowchart. /// -public class FlowchartDiagramDesigner(ILocalizer localizer) : IDiagramDesignerToolboxProvider +public class FlowchartDiagramDesigner(ILocalizer localizer, IDialogService dialogService) : IDiagramDesignerToolboxProvider { private FlowchartDesignerWrapper? _designerWrapper; private readonly Guid _id = Guid.NewGuid(); /// - public async Task LoadRootActivityAsync(JsonObject activity, IDictionary? activityStatsMap) - { - await InvokeDesignerActionAsync(x => x.LoadFlowchartAsync(activity, activityStatsMap)); - } + public async Task LoadRootActivityAsync(JsonObject activity, IDictionary? activityStatsMap) => await InvokeDesignerActionAsync(x => x.LoadFlowchartAsync(activity, activityStatsMap)); /// - public async Task UpdateActivityAsync(string id, JsonObject activity) - { - await InvokeDesignerActionAsync(x => x.UpdateActivityAsync(id, activity)); - } - + public async Task UpdateActivityAsync(string id, JsonObject activity) => await InvokeDesignerActionAsync(x => x.UpdateActivityAsync(id, activity)); + /// - public async Task UpdateActivityStatsAsync(string id, ActivityStats stats) - { - await InvokeDesignerActionAsync(x => x.UpdateActivityStatsAsync(id, stats)); - } + public async Task UpdateActivityStatsAsync(string id, ActivityStats stats) => await InvokeDesignerActionAsync(x => x.UpdateActivityStatsAsync(id, stats)); /// - public async Task SelectActivityAsync(string id) - { - await InvokeDesignerActionAsync(x => x.SelectActivityAsync(id)); - } + public async Task SelectActivityAsync(string id) => await InvokeDesignerActionAsync(x => x.SelectActivityAsync(id)); /// - public async Task ReadRootActivityAsync() - { - return await _designerWrapper!.ReadRootActivityAsync(); - } + public async Task ReadRootActivityAsync() => await _designerWrapper!.ReadRootActivityAsync(); /// public RenderFragment DisplayDesigner(DisplayContext context) @@ -83,6 +68,8 @@ public IEnumerable GetToolboxItems(bool isReadonly) { yield return DisplayToolboxItem(localizer["Auto layout"], Icons.Material.Outlined.AutoAwesomeMosaic, localizer["Auto layout"], OnAutoLayoutClicked); } + + yield return DisplayToolboxItem(localizer["Capture"], @Icons.Material.Outlined.Fullscreen, localizer["Capture flowchart"], OnCaptureClicked); } private RenderFragment DisplayToolboxItem(string title, string icon, string description, Func onClick) @@ -113,4 +100,36 @@ private async Task InvokeDesignerActionAsync(Func _designerWrapper != null ? _designerWrapper.ZoomToFitAsync() : Task.CompletedTask; private Task OnCenterClicked() => _designerWrapper != null ? _designerWrapper!.CenterContentAsync() : Task.CompletedTask; private Task OnAutoLayoutClicked() => _designerWrapper != null ? _designerWrapper!.AutoLayoutAsync() : Task.CompletedTask; + private async Task OnCaptureClicked() + { + if (_designerWrapper is null) return; + + var flowchart = _designerWrapper.Flowchart; + var invalidChars = Path.GetInvalidFileNameChars(); + var name = flowchart?.GetName() ?? "Workflow"; + var version = flowchart?.GetVersion(); + var validFileName = string.Concat(name.Select(c => invalidChars.Contains(c) ? "_" : c.ToString())).Trim() + + (version is null ? string.Empty : $"_v{version}"); + + var parameters = new DialogParameters + { + { x => x.FileName, validFileName }, + }; + + var options = new DialogOptions + { + CloseOnEscapeKey = true, + Position = DialogPosition.Center, + CloseButton = true, + FullWidth = true, + MaxWidth = MaxWidth.Small + }; + + var dialogInstance = await dialogService.ShowAsync(localizer["Capture content"], parameters, options); + var dialogResult = await dialogInstance.Result; + if (dialogResult?.Canceled ?? true) return; + + var captureOptions = dialogResult?.Data as CaptureOptions ?? new(); + await _designerWrapper.ExportContentToFormatAsync(captureOptions); + } } \ No newline at end of file diff --git a/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDiagramDesignerProvider.cs b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDiagramDesignerProvider.cs index 4c3c76f71..ccb30aa94 100644 --- a/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDiagramDesignerProvider.cs +++ b/src/modules/Elsa.Studio.Workflows/DiagramDesigners/Flowcharts/FlowchartDiagramDesignerProvider.cs @@ -1,20 +1,19 @@ -using System.Text.Json.Nodes; using Elsa.Api.Client.Extensions; -using Elsa.Api.Client.Resources.WorkflowDefinitions.Models; using Elsa.Studio.Localization; using Elsa.Studio.Workflows.UI.Contracts; using JetBrains.Annotations; +using MudBlazor; +using System.Text.Json.Nodes; namespace Elsa.Studio.Workflows.DiagramDesigners.Flowcharts; -/// -/// A diagram designer provider for the Flowchart designer. -/// -[UsedImplicitly] /// /// Provides flowchart diagram designer services. /// -public class FlowchartDiagramDesignerProvider(ILocalizer localizer) : IDiagramDesignerProvider +/// The localizer used to provide localized strings for the designer interface. +/// The dialog service used to display dialogs within the designer. +[UsedImplicitly] +public class FlowchartDiagramDesignerProvider(ILocalizer localizer, IDialogService dialogService) : IDiagramDesignerProvider { /// public double Priority => 0; @@ -23,5 +22,5 @@ public class FlowchartDiagramDesignerProvider(ILocalizer localizer) : IDiagramDe public bool GetSupportsActivity(JsonObject activity) => activity.GetTypeName() == "Elsa.Flowchart"; /// - public IDiagramDesigner GetEditor() => new FlowchartDiagramDesigner(localizer); + public IDiagramDesigner GetEditor() => new FlowchartDiagramDesigner(localizer, dialogService); } \ No newline at end of file diff --git a/src/modules/Elsa.Studio.Workflows/Shared/Components/DiagramDesignerWrapper.razor.cs b/src/modules/Elsa.Studio.Workflows/Shared/Components/DiagramDesignerWrapper.razor.cs index 2b268ce94..b97030a22 100644 --- a/src/modules/Elsa.Studio.Workflows/Shared/Components/DiagramDesignerWrapper.razor.cs +++ b/src/modules/Elsa.Studio.Workflows/Shared/Components/DiagramDesignerWrapper.razor.cs @@ -6,12 +6,9 @@ using Elsa.Studio.Workflows.Domain.Extensions; using Elsa.Studio.Workflows.Domain.Models; using Elsa.Studio.Workflows.Extensions; -using Elsa.Studio.Workflows.Models; using Elsa.Studio.Workflows.Shared.Args; using Elsa.Studio.Workflows.UI.Args; -using Elsa.Studio.Workflows.UI.Contexts; using Elsa.Studio.Workflows.UI.Contracts; -using Elsa.Studio.Workflows.UI.Models; using Humanizer; using Microsoft.AspNetCore.Components; using MudBlazor; @@ -21,108 +18,76 @@ namespace Elsa.Studio.Workflows.Shared.Components; /// A wrapper around the diagram designer that provides a breadcrumb and a toolbar. public partial class DiagramDesignerWrapper { + private string? _lastSelectedNodeId; private IDiagramDesigner? _diagramDesigner; private Stack _pathSegments = new(); private JsonObject? _currentContainerActivity; private List _breadcrumbItems = new(); - private IDictionary _activityStats = - new Dictionary(); + private IDictionary _activityStats = new Dictionary(); private ActivityGraph _activityGraph = null!; - private IDictionary _indexedActivityNodes = - new Dictionary(); + private IDictionary _indexedActivityNodes = new Dictionary(); + + [Inject] private IDiagramDesignerService DiagramDesignerService { get; set; } = null!; + [Inject] private IActivityDisplaySettingsRegistry ActivityDisplaySettingsRegistry { get; set; } = null!; + [Inject] private IActivityPortService ActivityPortService { get; set; } = null!; + [Inject] private IActivityRegistry ActivityRegistry { get; set; } = null!; + [Inject] private IIdentityGenerator IdentityGenerator { get; set; } = null!; + [Inject] private IActivityExecutionService ActivityExecutionService { get; set; } = null!; + [Inject] private IActivityVisitor ActivityVisitor { get; set; } = null!; + [Inject] private IWorkflowDefinitionService WorkflowDefinitionService { get; set; } = null!; + [Inject] private ISnackbar Snackbar { get; set; } = null!; - /// The workflow definition version ID. - [Parameter] /// /// Gets or sets the workflow definition version id. /// - public string WorkflowDefinitionVersionId { get; set; } = null!; + [Parameter] public string WorkflowDefinitionVersionId { get; set; } = null!; - /// The root activity to display. - [Parameter] /// - /// Gets or sets the activity. + /// Gets or sets the root activity. /// - public JsonObject Activity { get; set; } = null!; + [Parameter] public JsonObject Activity { get; set; } = null!; - /// Whether the designer is read-only. - [Parameter] /// /// Indicates whether is read only. /// - public bool IsReadOnly { get; set; } + [Parameter] public bool IsReadOnly { get; set; } - /// The workflow instance ID, if any. - [Parameter] /// /// Gets or sets the workflow instance id. /// - public string? WorkflowInstanceId { get; set; } + [Parameter] public string? WorkflowInstanceId { get; set; } - /// A custom toolbar to display. - [Parameter] /// /// Gets or sets the custom toolbar items. /// - public RenderFragment? CustomToolbarItems { get; set; } + [Parameter] public RenderFragment? CustomToolbarItems { get; set; } - /// Whether the designer is progressing. - [Parameter] /// /// Indicates whether is progressing. /// - public bool IsProgressing { get; set; } + [Parameter] public bool IsProgressing { get; set; } - /// An event raised when an activity is selected. - [Parameter] /// - /// Gets or sets the activity selected event callback. + /// Gets or sets the callback event when an activity is selected. /// - public EventCallback ActivitySelected { get; set; } + [Parameter] public EventCallback ActivitySelected { get; set; } - /// An event raised when an embedded port is selected. + /// + /// Gets or sets the callback event when an embedded port is selected. + /// [Parameter] public EventCallback GraphUpdated { get; set; } + /// + /// Gets or sets the callback event when the activity is updated. + /// [Parameter] public EventCallback ActivityUpdated { get; set; } - /// An event raised when the path changes. - [Parameter] /// - /// Gets or sets the path changed event callback. + /// Gets or sets the callback event when a path is changed. /// - public EventCallback PathChanged { get; set; } - - [Inject] - private IDiagramDesignerService DiagramDesignerService { get; set; } = null!; - - [Inject] - private IActivityDisplaySettingsRegistry ActivityDisplaySettingsRegistry { get; set; } = null!; - - [Inject] - private IActivityPortService ActivityPortService { get; set; } = null!; + [Parameter] public EventCallback PathChanged { get; set; } - [Inject] - private IActivityRegistry ActivityRegistry { get; set; } = null!; - - [Inject] - private IIdentityGenerator IdentityGenerator { get; set; } = null!; - - [Inject] - private IActivityExecutionService ActivityExecutionService { get; set; } = null!; - - [Inject] - private IActivityVisitor ActivityVisitor { get; set; } = null!; - - [Inject] - private IWorkflowDefinitionService WorkflowDefinitionService { get; set; } = null!; - - [Inject] - private ISnackbar Snackbar { get; set; } = null!; - - private ActivityPathSegment? CurrentPathSegment => - _pathSegments.TryPeek(out var segment) ? segment : null; - - private string? _lastSelectedNodeId; + private ActivityPathSegment? CurrentPathSegment => _pathSegments.TryPeek(out var segment) ? segment : null; /// Selects the activity with the specified ID. /// The ID of the activity ID select. diff --git a/src/modules/Elsa.Studio.Workflows/Validators/CaptureOptionsValidator.cs b/src/modules/Elsa.Studio.Workflows/Validators/CaptureOptionsValidator.cs new file mode 100644 index 000000000..b23ab1bcc --- /dev/null +++ b/src/modules/Elsa.Studio.Workflows/Validators/CaptureOptionsValidator.cs @@ -0,0 +1,17 @@ +using Elsa.Studio.Localization; +using Elsa.Studio.Workflows.Designer.Options; +using FluentValidation; + +namespace Elsa.Studio.Workflows.Validators; + +/// +/// A validator for instances. +/// +public class CaptureOptionsValidator : AbstractValidator +{ + public CaptureOptionsValidator(ILocalizer localizer) + { + RuleFor(x => x.FileName).NotEmpty().WithMessage(localizer["Please enter a filename for the export."]); + RuleFor(x => x.Padding).GreaterThanOrEqualTo(0); + } +} \ No newline at end of file