From 550124a9b1762df9ae9b0746e690f2cb6c9d682d Mon Sep 17 00:00:00 2001 From: cristinamudura <80831066+cristinamudura@users.noreply.github.com> Date: Fri, 18 Mar 2022 20:24:24 +0100 Subject: [PATCH] implemented delete for single workflow definitions and workflow instance (#2855) --- .../Endpoints/WorkflowInstances/Delete.cs | 26 ++++++++++++++++ .../Endpoints/WorkflowInstances/Resource.cs | 2 ++ .../Elsa.Api/Endpoints/Workflows/Delete.cs | 24 +++++++++++++++ .../Elsa.Api/Endpoints/Workflows/Resource.cs | 2 ++ src/api/Elsa.Api/ResourceBase.cs | 6 ++++ .../Elsa.Core/Elsa.Core.csproj.DotSettings | 8 ++++- .../Contracts/IWorkflowInstancePublisher.cs | 6 ++++ .../Extensions/ServiceCollectionExtensions.cs | 1 + .../Services/WorkflowInstancePublisher.cs | 25 ++++++++++++++++ .../workflow-browser/workflow-browser.tsx | 3 ++ .../workflow-instance-browser/filter.tsx | 9 +++++- .../workflow-instance-browser.tsx | 5 ++++ .../src/services/elsa-api-client-provider.ts | 30 +++++++++++++++++++ .../Commands/DeleteWorkflowInstance.cs | 9 ++++++ .../DeleteWorkflowInstancesHandler.cs | 10 ++++++- .../DeleteWorkflowInstancesHandler.cs | 10 +++++++ .../Elsa.Scripting.Liquid.csproj | 1 + 17 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 src/api/Elsa.Api/Endpoints/WorkflowInstances/Delete.cs create mode 100644 src/api/Elsa.Api/Endpoints/Workflows/Delete.cs create mode 100644 src/core/Elsa.Management/Contracts/IWorkflowInstancePublisher.cs create mode 100644 src/core/Elsa.Management/Services/WorkflowInstancePublisher.cs create mode 100644 src/persistence/Elsa.Persistence.Abstractions/Commands/DeleteWorkflowInstance.cs diff --git a/src/api/Elsa.Api/Endpoints/WorkflowInstances/Delete.cs b/src/api/Elsa.Api/Endpoints/WorkflowInstances/Delete.cs new file mode 100644 index 000000000..d307fa12a --- /dev/null +++ b/src/api/Elsa.Api/Endpoints/WorkflowInstances/Delete.cs @@ -0,0 +1,26 @@ +using System.Threading; +using System.Threading.Tasks; +using Elsa.Management.Contracts; +using Elsa.Mediator.Contracts; +using Elsa.Persistence.Requests; +using Microsoft.AspNetCore.Http; + +namespace Elsa.Api.Endpoints.WorkflowInstances; + +public static partial class WorkflowInstances +{ + public static async Task DeleteAsync(string id, IRequestSender requestSender, + IWorkflowInstancePublisher workflowInstancePublisher, CancellationToken cancellationToken) + { + var request = new FindWorkflowInstance(id); + var workflowInstance = await requestSender.RequestAsync(request, cancellationToken); + + if (workflowInstance == null) + { + return Results.NotFound(); + } + + await workflowInstancePublisher.DeleteAsync(id, cancellationToken); + return Results.NoContent(); + } +} \ No newline at end of file diff --git a/src/api/Elsa.Api/Endpoints/WorkflowInstances/Resource.cs b/src/api/Elsa.Api/Endpoints/WorkflowInstances/Resource.cs index 9faa62674..b885829d4 100644 --- a/src/api/Elsa.Api/Endpoints/WorkflowInstances/Resource.cs +++ b/src/api/Elsa.Api/Endpoints/WorkflowInstances/Resource.cs @@ -11,6 +11,7 @@ public class WorkflowInstancesResource : ResourceBase public WorkflowInstancesResource List() => MapGet("api/workflow-instances", WorkflowInstances.ListAsync); public WorkflowInstancesResource Get() => MapGet("api/workflow-instances/{id}", WorkflowInstances.GetAsync); + public void Delete() => MapDelete("api/workflow-instances/{id}", WorkflowInstances.DeleteAsync); } public static class WorkflowsResourceExtensions @@ -24,5 +25,6 @@ public static class WorkflowsResourceExtensions public static IEndpointRouteBuilder MapWorkflowInstances(this IEndpointRouteBuilder endpoints) => endpoints.MapWorkflowInstances(x => x .List() .Get() + .Delete() ); } \ No newline at end of file diff --git a/src/api/Elsa.Api/Endpoints/Workflows/Delete.cs b/src/api/Elsa.Api/Endpoints/Workflows/Delete.cs new file mode 100644 index 000000000..55f966357 --- /dev/null +++ b/src/api/Elsa.Api/Endpoints/Workflows/Delete.cs @@ -0,0 +1,24 @@ +using System.Threading; +using System.Threading.Tasks; +using Elsa.Management.Contracts; +using Elsa.Persistence.Models; +using Elsa.Runtime.Contracts; +using Microsoft.AspNetCore.Http; + +namespace Elsa.Api.Endpoints.Workflows; + +public static partial class Workflows +{ + public static async Task DeleteAsync(string definitionId, IWorkflowRegistry workflowRegistry, + IWorkflowPublisher workflowPublisher, CancellationToken cancellationToken) + { + var workflow = await workflowRegistry.FindByIdAsync(definitionId, VersionOptions.LatestOrPublished, cancellationToken); + if (workflow == null) + { + return Results.NotFound(); + } + + await workflowPublisher.DeleteAsync(workflow, cancellationToken); + return Results.NoContent(); + } +} \ No newline at end of file diff --git a/src/api/Elsa.Api/Endpoints/Workflows/Resource.cs b/src/api/Elsa.Api/Endpoints/Workflows/Resource.cs index 7a69d60f4..6c49e6c2a 100644 --- a/src/api/Elsa.Api/Endpoints/Workflows/Resource.cs +++ b/src/api/Elsa.Api/Endpoints/Workflows/Resource.cs @@ -15,6 +15,7 @@ public class WorkflowsResource : ResourceBase public WorkflowsResource Get() => MapGet("api/workflows/{definitionId}", Workflows.Get); public WorkflowsResource Execute() => MapPost("api/workflows/{definitionId}/execute", Workflows.ExecuteAsync); public WorkflowsResource Dispatch() => MapPost("api/workflows/{definitionId}/dispatch", Workflows.DispatchAsync); + public void Delete() => MapDelete("api/workflows/{definitionId}", Workflows.DeleteAsync); } public static class WorkflowsResourceExtensions @@ -32,5 +33,6 @@ public static class WorkflowsResourceExtensions .List() .GetMany() .Get() + .Delete() ); } \ No newline at end of file diff --git a/src/api/Elsa.Api/ResourceBase.cs b/src/api/Elsa.Api/ResourceBase.cs index ef8a4c221..7ad51c42b 100644 --- a/src/api/Elsa.Api/ResourceBase.cs +++ b/src/api/Elsa.Api/ResourceBase.cs @@ -20,4 +20,10 @@ public abstract class ResourceBase where T:ResourceBase Endpoints.MapPost(pattern, handler); return (T)this; } + + protected T MapDelete(string pattern, Delegate handler) + { + Endpoints.MapDelete(pattern, handler); + return (T)this; + } } \ No newline at end of file diff --git a/src/core/Elsa.Core/Elsa.Core.csproj.DotSettings b/src/core/Elsa.Core/Elsa.Core.csproj.DotSettings index 373203e26..72387db01 100644 --- a/src/core/Elsa.Core/Elsa.Core.csproj.DotSettings +++ b/src/core/Elsa.Core/Elsa.Core.csproj.DotSettings @@ -1,3 +1,9 @@  True - True \ No newline at end of file + True + True + True + True + True + True + True \ No newline at end of file diff --git a/src/core/Elsa.Management/Contracts/IWorkflowInstancePublisher.cs b/src/core/Elsa.Management/Contracts/IWorkflowInstancePublisher.cs new file mode 100644 index 000000000..769ed15af --- /dev/null +++ b/src/core/Elsa.Management/Contracts/IWorkflowInstancePublisher.cs @@ -0,0 +1,6 @@ +namespace Elsa.Management.Contracts; + +public interface IWorkflowInstancePublisher +{ + Task DeleteAsync(string instanceId, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/src/core/Elsa.Management/Extensions/ServiceCollectionExtensions.cs b/src/core/Elsa.Management/Extensions/ServiceCollectionExtensions.cs index af50fef0f..3d86b2617 100644 --- a/src/core/Elsa.Management/Extensions/ServiceCollectionExtensions.cs +++ b/src/core/Elsa.Management/Extensions/ServiceCollectionExtensions.cs @@ -14,6 +14,7 @@ public static class ServiceCollectionExtensions { return services .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/src/core/Elsa.Management/Services/WorkflowInstancePublisher.cs b/src/core/Elsa.Management/Services/WorkflowInstancePublisher.cs new file mode 100644 index 000000000..29c426e09 --- /dev/null +++ b/src/core/Elsa.Management/Services/WorkflowInstancePublisher.cs @@ -0,0 +1,25 @@ +using Elsa.Management.Contracts; +using Elsa.Mediator.Contracts; +using Elsa.Persistence.Commands; + +namespace Elsa.Management.Services; + +public class WorkflowInstancePublisher : IWorkflowInstancePublisher +{ + private readonly IMediator _mediator; + + public WorkflowInstancePublisher(IMediator mediator) + { + _mediator = mediator; + } + public async Task DeleteAsync(string instanceId, CancellationToken cancellationToken = default) + { + await _mediator.ExecuteAsync(new DeleteWorkflowInstance(instanceId), + cancellationToken); + } + + public async Task BulkDeleteAsync(IEnumerable instanceIds, CancellationToken cancellationToken = default) + { + await _mediator.ExecuteAsync(new DeleteWorkflowInstances(instanceIds), cancellationToken); + } +} \ No newline at end of file diff --git a/src/designer/elsa-workflows-designer/src/components/modals/workflow-browser/workflow-browser.tsx b/src/designer/elsa-workflows-designer/src/components/modals/workflow-browser/workflow-browser.tsx index bc08905c3..231a826ab 100644 --- a/src/designer/elsa-workflows-designer/src/components/modals/workflow-browser/workflow-browser.tsx +++ b/src/designer/elsa-workflows-designer/src/components/modals/workflow-browser/workflow-browser.tsx @@ -45,6 +45,9 @@ export class WorkflowBrowser { } private async onDeleteClick(e: MouseEvent, workflowDefinition: WorkflowSummary) { + const elsaClient = this.elsaClient; + await elsaClient.workflows.delete(workflowDefinition); + await this.loadWorkflowDefinitions(); // const result = await this.confirmDialog.show(t('DeleteConfirmationModel.Title'), t('DeleteConfirmationModel.Message')); // diff --git a/src/designer/elsa-workflows-designer/src/components/modals/workflow-instance-browser/filter.tsx b/src/designer/elsa-workflows-designer/src/components/modals/workflow-instance-browser/filter.tsx index a42b08e45..0418851ac 100644 --- a/src/designer/elsa-workflows-designer/src/components/modals/workflow-instance-browser/filter.tsx +++ b/src/designer/elsa-workflows-designer/src/components/modals/workflow-instance-browser/filter.tsx @@ -31,6 +31,7 @@ export interface OrderByFilterProps { onChange: (orderBy: OrderBy) => void; } + export const Filter: FunctionalComponent = ({pageSizeFilter, workflowFilter, statusFilter, orderByFilter}) => { return
@@ -57,7 +58,13 @@ const BulkActions: FunctionalComponent = () => { }]; const onBulkActionSelected = (e: CustomEvent) => { - + const action = e.detail; + switch (action.name){ + case 'Delete' : + break; + default: + action.handler(); + } } return { } }, workflows: { + async delete(request: DeleteWorkflowRequest) : Promise{ + const response = await httpClient.delete(`api/workflows/${request.definitionId}`); + return response.data; + }, async post(request: SaveWorkflowRequest): Promise { const response = await httpClient.post('api/workflows', request); return response.data; @@ -108,6 +112,14 @@ export async function createElsaClient(serverUrl: string): Promise { async get(request: GetWorkflowInstanceRequest): Promise { const response = await httpClient.get(`api/workflow-instances/${request.id}`); return response.data; + }, + async delete(request: DeleteWorkflowInstanceRequest): Promise { + const response = await httpClient.delete(`api/workflow-instances/${request.id}`); + return response.data; + }, + async deleteMany(request: BulkDeleteWorkflowInstancesRequest): Promise> { + const response = await httpClient.delete>(`api/workflow-instances/bulk`); + return response.data; } }, designer: { @@ -147,6 +159,8 @@ export interface WorkflowsApi { list(request: ListWorkflowsRequest): Promise>; getMany(request: GetManyWorkflowsRequest): Promise>; + + delete(request: DeleteWorkflowRequest): Promise; } export interface WorkflowInstancesApi { @@ -154,6 +168,10 @@ export interface WorkflowInstancesApi { list(request: ListWorkflowInstancesRequest): Promise>; get(request: GetWorkflowInstanceRequest): Promise; + + delete(request: DeleteWorkflowInstanceRequest) : Promise + + deleteMany(request: BulkDeleteWorkflowInstancesRequest) : Promise> } export interface DesignerApi { @@ -172,6 +190,10 @@ export interface SaveWorkflowRequest { root?: Activity } +export interface DeleteWorkflowRequest { + definitionId: string; +} + export interface GetWorkflowRequest { definitionId: string; versionOptions?: VersionOptions; @@ -204,6 +226,14 @@ export interface GetWorkflowInstanceRequest { id: string; } +export interface DeleteWorkflowInstanceRequest { + id: string; +} + +export interface BulkDeleteWorkflowInstancesRequest{ + workflowInstanceIds: Array; +} + @Service() export class ElsaApiClientProvider { private elsaClient: ElsaClient; diff --git a/src/persistence/Elsa.Persistence.Abstractions/Commands/DeleteWorkflowInstance.cs b/src/persistence/Elsa.Persistence.Abstractions/Commands/DeleteWorkflowInstance.cs new file mode 100644 index 000000000..4acc906b8 --- /dev/null +++ b/src/persistence/Elsa.Persistence.Abstractions/Commands/DeleteWorkflowInstance.cs @@ -0,0 +1,9 @@ +using Elsa.Mediator.Contracts; + +namespace Elsa.Persistence.Commands; + +public record DeleteWorkflowInstance : ICommand +{ + public DeleteWorkflowInstance(string instanceId) => InstanceId = instanceId; + public string? InstanceId { get; set; } +} \ No newline at end of file diff --git a/src/persistence/Elsa.Persistence.EntityFrameworkCore/Handlers/Commands/DeleteWorkflowInstancesHandler.cs b/src/persistence/Elsa.Persistence.EntityFrameworkCore/Handlers/Commands/DeleteWorkflowInstancesHandler.cs index 33acc011d..3253dff43 100644 --- a/src/persistence/Elsa.Persistence.EntityFrameworkCore/Handlers/Commands/DeleteWorkflowInstancesHandler.cs +++ b/src/persistence/Elsa.Persistence.EntityFrameworkCore/Handlers/Commands/DeleteWorkflowInstancesHandler.cs @@ -5,7 +5,7 @@ using Elsa.Persistence.EntityFrameworkCore.Contracts; namespace Elsa.Persistence.EntityFrameworkCore.Handlers.Commands; -public class DeleteWorkflowInstancesHandler : ICommandHandler +public class DeleteWorkflowInstancesHandler : ICommandHandler, ICommandHandler { private readonly IStore _store; public DeleteWorkflowInstancesHandler(IStore store) => _store = store; @@ -20,4 +20,12 @@ public class DeleteWorkflowInstancesHandler : ICommandHandler HandleAsync(DeleteWorkflowInstance command, CancellationToken cancellationToken) + { + if (command.InstanceId != null) + return await _store.DeleteWhereAsync(x => x.Id == command.InstanceId, cancellationToken); + + return 0; + } } \ No newline at end of file diff --git a/src/persistence/Elsa.Persistence.InMemory/Handlers/Commands/DeleteWorkflowInstancesHandler.cs b/src/persistence/Elsa.Persistence.InMemory/Handlers/Commands/DeleteWorkflowInstancesHandler.cs index 370e48f78..958b50893 100644 --- a/src/persistence/Elsa.Persistence.InMemory/Handlers/Commands/DeleteWorkflowInstancesHandler.cs +++ b/src/persistence/Elsa.Persistence.InMemory/Handlers/Commands/DeleteWorkflowInstancesHandler.cs @@ -29,4 +29,14 @@ public class DeleteWorkflowInstancesHandler : ICommandHandler HandleAsync(DeleteWorkflowInstance command, CancellationToken cancellationToken) + { + if (command.InstanceId != null) + { + _store.Delete(command.InstanceId); + } + + return Task.FromResult(Unit.Instance); + } } \ No newline at end of file diff --git a/src/scripting/Elsa.Scripting.Liquid/Elsa.Scripting.Liquid.csproj b/src/scripting/Elsa.Scripting.Liquid/Elsa.Scripting.Liquid.csproj index 786dfb1b1..2f33e2a54 100644 --- a/src/scripting/Elsa.Scripting.Liquid/Elsa.Scripting.Liquid.csproj +++ b/src/scripting/Elsa.Scripting.Liquid/Elsa.Scripting.Liquid.csproj @@ -9,6 +9,7 @@ +