From 82acecdbd27ca4627b4cafdbcc3feacc6320dd02 Mon Sep 17 00:00:00 2001 From: Jelger Ribbers Date: Mon, 15 Dec 2025 10:57:10 +0100 Subject: [PATCH] add work flow instance --- .../IWorkflowInstanceExportNameProvider.cs | 18 ++++++++++++++++++ .../WorkflowInstances/Export/Endpoint.cs | 17 ++++++++--------- .../Features/WorkflowsApiFeature.cs | 1 + ...efaultWorkflowInstanceExportNameProvider.cs | 15 +++++++++++++++ 4 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 src/modules/Elsa.Workflows.Api/Contracts/IWorkflowInstanceExportNameProvider.cs create mode 100644 src/modules/Elsa.Workflows.Api/Providers/DefaultWorkflowInstanceExportNameProvider.cs diff --git a/src/modules/Elsa.Workflows.Api/Contracts/IWorkflowInstanceExportNameProvider.cs b/src/modules/Elsa.Workflows.Api/Contracts/IWorkflowInstanceExportNameProvider.cs new file mode 100644 index 000000000..12d510470 --- /dev/null +++ b/src/modules/Elsa.Workflows.Api/Contracts/IWorkflowInstanceExportNameProvider.cs @@ -0,0 +1,18 @@ +using Elsa.Workflows.Management.Entities; + +namespace Elsa.Workflows.Api; + +/// +/// Defines a contract for generating a filename suitable for exporting a workflow instance. +/// +public interface IWorkflowInstanceExportNameProvider +{ + /// + /// Generates a filename for a workflow instance export. + /// + /// The workflow instance being exported. + /// The export model representing the instance (optional). + /// Cancellation token. + /// A filename safe for saving to disk. + Task GetFileNameAsync(WorkflowInstance instance, object model, CancellationToken cancellationToken = default); +} diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Export/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Export/Endpoint.cs index 1b0e85a1a..2b695ff11 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Export/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Export/Endpoint.cs @@ -31,6 +31,7 @@ internal class Export : ElsaEndpointWithMapper private readonly IWorkflowStateSerializer _workflowStateSerializer; private readonly IPayloadSerializer _payloadSerializer; private readonly ISafeSerializer _safeSerializer; + private readonly IWorkflowInstanceExportNameProvider _workFlowInstanceExportNameProvider; /// public Export( @@ -40,7 +41,8 @@ internal class Export : ElsaEndpointWithMapper IBookmarkStore bookmarkStore, IWorkflowStateSerializer workflowStateSerializer, IPayloadSerializer payloadSerializer, - ISafeSerializer safeSerializer) + ISafeSerializer safeSerializer, + IWorkflowInstanceExportNameProvider workFlowInstanceExportNameProvider) { _workflowInstanceStore = workflowInstanceStore; _activityExecutionStore = activityExecutionStore; @@ -49,6 +51,7 @@ internal class Export : ElsaEndpointWithMapper _workflowStateSerializer = workflowStateSerializer; _payloadSerializer = payloadSerializer; _safeSerializer = safeSerializer; + _workFlowInstanceExportNameProvider = workFlowInstanceExportNameProvider; } /// @@ -85,7 +88,9 @@ internal class Export : ElsaEndpointWithMapper { var model = await CreateExportModelAsync(request, instance, cancellationToken); var binaryJson = SerializeWorkflowInstance(model); - var fileName = GetFileName(instance.WorkflowState); + + var fileName = await _workFlowInstanceExportNameProvider.GetFileNameAsync(instance, model, cancellationToken); + var entry = zipArchive.CreateEntry(fileName, CompressionLevel.Optimal); await using var entryStream = entry.Open(); await entryStream.WriteAsync(binaryJson, cancellationToken); @@ -109,7 +114,7 @@ internal class Export : ElsaEndpointWithMapper var model = await CreateExportModelAsync(request, instance, cancellationToken); var binaryJson = SerializeWorkflowInstance(model); - var fileName = GetFileName(instance.WorkflowState); + var fileName = await _workFlowInstanceExportNameProvider.GetFileNameAsync(instance, model, cancellationToken); await Send.BytesAsync(binaryJson, fileName, cancellation: cancellationToken); } @@ -168,12 +173,6 @@ internal class Export : ElsaEndpointWithMapper return page.Items; } - private static string GetFileName(WorkflowState instance) - { - var fileName = $"workflow-instance-{instance.Id.ToLowerInvariant()}.json"; - return fileName; - } - private static byte[] SerializeWorkflowInstance(ExportedWorkflowState model) { var binaryJson = JsonSerializer.SerializeToUtf8Bytes(model); diff --git a/src/modules/Elsa.Workflows.Api/Features/WorkflowsApiFeature.cs b/src/modules/Elsa.Workflows.Api/Features/WorkflowsApiFeature.cs index 721a36827..fd625fc05 100644 --- a/src/modules/Elsa.Workflows.Api/Features/WorkflowsApiFeature.cs +++ b/src/modules/Elsa.Workflows.Api/Features/WorkflowsApiFeature.cs @@ -41,5 +41,6 @@ public class WorkflowsApiFeature(IModule module) : FeatureBase(module) { options.AddPolicy(AuthorizationPolicies.NotReadOnlyPolicy, policy => policy.AddRequirements(new NotReadOnlyRequirement())); }); + Services.AddScoped(); } } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Api/Providers/DefaultWorkflowInstanceExportNameProvider.cs b/src/modules/Elsa.Workflows.Api/Providers/DefaultWorkflowInstanceExportNameProvider.cs new file mode 100644 index 000000000..76728e26e --- /dev/null +++ b/src/modules/Elsa.Workflows.Api/Providers/DefaultWorkflowInstanceExportNameProvider.cs @@ -0,0 +1,15 @@ +using Elsa.Workflows.Management.Entities; + +namespace Elsa.Workflows.Api; + +/// +/// Provides a default implementation for generating export file names for workflow instances. +/// +public class DefaultWorkflowInstanceExportNameProvider : IWorkflowInstanceExportNameProvider +{ + public Task GetFileNameAsync(WorkflowInstance instance, object model, CancellationToken cancellationToken = default) + { + var fileName = $"workflow-instance-{instance.Id.ToLowerInvariant()}.json"; + return Task.FromResult(fileName); + } +}