This commit is contained in:
Sipke Schoorstra 2022-03-20 20:39:04 +01:00
commit aa40a7e966
17 changed files with 174 additions and 3 deletions

View file

@ -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<IResult> 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();
}
}

View file

@ -11,6 +11,7 @@ public class WorkflowInstancesResource : ResourceBase<WorkflowInstancesResource>
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()
);
}

View file

@ -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<IResult> 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();
}
}

View file

@ -15,6 +15,7 @@ public class WorkflowsResource : ResourceBase<WorkflowsResource>
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()
);
}

View file

@ -20,4 +20,10 @@ public abstract class ResourceBase<T> where T:ResourceBase<T>
Endpoints.MapPost(pattern, handler);
return (T)this;
}
protected T MapDelete(string pattern, Delegate handler)
{
Endpoints.MapDelete(pattern, handler);
return (T)this;
}
}

View file

@ -1,3 +1,9 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Ccontainers_005Cfreeflowchart/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Cworkflows_005Cfreeflowchart/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Ccontrolflow_005Cfinish/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Ccontrolflow_005Cfor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Ccontrolflow_005Cswitch/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Cprimitives_005Csetname/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Csignaling_005Cactivities_005Csignalreceived/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Cworkflows_005Cfreeflowchart/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extensions/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -0,0 +1,6 @@
namespace Elsa.Management.Contracts;
public interface IWorkflowInstancePublisher
{
Task DeleteAsync(string instanceId, CancellationToken cancellationToken = default);
}

View file

@ -14,6 +14,7 @@ public static class ServiceCollectionExtensions
{
return services
.AddSingleton<IWorkflowPublisher, WorkflowPublisher>()
.AddSingleton<IWorkflowInstancePublisher, WorkflowInstancePublisher>()
.AddSingleton<IActivityDescriber, ActivityDescriber>()
.AddSingleton<IActivityRegistry, ActivityRegistry>()
.AddSingleton<IActivityRegistryPopulator, ActivityRegistryPopulator>()

View file

@ -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<string> instanceIds, CancellationToken cancellationToken = default)
{
await _mediator.ExecuteAsync(new DeleteWorkflowInstances(instanceIds), cancellationToken);
}
}

View file

@ -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'));
//

View file

@ -31,6 +31,7 @@ export interface OrderByFilterProps {
onChange: (orderBy: OrderBy) => void;
}
export const Filter: FunctionalComponent<FilterProps> = ({pageSizeFilter, workflowFilter, statusFilter, orderByFilter}) => {
return <div class="p-8 flex content-end justify-right bg-white space-x-4">
@ -57,7 +58,13 @@ const BulkActions: FunctionalComponent = () => {
}];
const onBulkActionSelected = (e: CustomEvent<DropdownButtonItem>) => {
const action = e.detail;
switch (action.name){
case 'Delete' :
break;
default:
action.handler();
}
}
return <elsa-dropdown-button

View file

@ -243,6 +243,11 @@ export class WorkflowInstanceBrowser {
private async onDeleteClick(e: MouseEvent, workflowInstance: WorkflowInstanceSummary) {
const elsaClient = this.elsaClient;
await elsaClient.workflowInstances.delete(workflowInstance);
await this.loadWorkflowInstances();
// const result = await this.confirmDialog.show(t('DeleteConfirmationModel.Title'), t('DeleteConfirmationModel.Message'));
//
// if (!result)

View file

@ -56,6 +56,10 @@ export async function createElsaClient(serverUrl: string): Promise<ElsaClient> {
}
},
workflows: {
async delete(request: DeleteWorkflowRequest) : Promise<Workflow>{
const response = await httpClient.delete<Workflow>(`api/workflows/${request.definitionId}`);
return response.data;
},
async post(request: SaveWorkflowRequest): Promise<Workflow> {
const response = await httpClient.post<Workflow>('api/workflows', request);
return response.data;
@ -108,6 +112,14 @@ export async function createElsaClient(serverUrl: string): Promise<ElsaClient> {
async get(request: GetWorkflowInstanceRequest): Promise<WorkflowInstance> {
const response = await httpClient.get<WorkflowInstance>(`api/workflow-instances/${request.id}`);
return response.data;
},
async delete(request: DeleteWorkflowInstanceRequest): Promise<WorkflowInstanceSummary> {
const response = await httpClient.delete<WorkflowInstanceSummary>(`api/workflow-instances/${request.id}`);
return response.data;
},
async deleteMany(request: BulkDeleteWorkflowInstancesRequest): Promise<PagedList<WorkflowInstanceSummary>> {
const response = await httpClient.delete<PagedList<WorkflowInstanceSummary>>(`api/workflow-instances/bulk`);
return response.data;
}
},
designer: {
@ -147,6 +159,8 @@ export interface WorkflowsApi {
list(request: ListWorkflowsRequest): Promise<PagedList<WorkflowSummary>>;
getMany(request: GetManyWorkflowsRequest): Promise<Array<WorkflowSummary>>;
delete(request: DeleteWorkflowRequest): Promise<Workflow>;
}
export interface WorkflowInstancesApi {
@ -154,6 +168,10 @@ export interface WorkflowInstancesApi {
list(request: ListWorkflowInstancesRequest): Promise<PagedList<WorkflowInstanceSummary>>;
get(request: GetWorkflowInstanceRequest): Promise<WorkflowInstance>;
delete(request: DeleteWorkflowInstanceRequest) : Promise<WorkflowInstanceSummary>
deleteMany(request: BulkDeleteWorkflowInstancesRequest) : Promise<PagedList<WorkflowInstanceSummary>>
}
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<string>;
}
@Service()
export class ElsaApiClientProvider {
private elsaClient: ElsaClient;

View file

@ -0,0 +1,9 @@
using Elsa.Mediator.Contracts;
namespace Elsa.Persistence.Commands;
public record DeleteWorkflowInstance : ICommand<int>
{
public DeleteWorkflowInstance(string instanceId) => InstanceId = instanceId;
public string? InstanceId { get; set; }
}

View file

@ -5,7 +5,7 @@ using Elsa.Persistence.EntityFrameworkCore.Contracts;
namespace Elsa.Persistence.EntityFrameworkCore.Handlers.Commands;
public class DeleteWorkflowInstancesHandler : ICommandHandler<DeleteWorkflowInstances, int>
public class DeleteWorkflowInstancesHandler : ICommandHandler<DeleteWorkflowInstances, int>, ICommandHandler<DeleteWorkflowInstance, int>
{
private readonly IStore<WorkflowInstance> _store;
public DeleteWorkflowInstancesHandler(IStore<WorkflowInstance> store) => _store = store;
@ -20,4 +20,12 @@ public class DeleteWorkflowInstancesHandler : ICommandHandler<DeleteWorkflowInst
return 0;
}
public async Task<int> HandleAsync(DeleteWorkflowInstance command, CancellationToken cancellationToken)
{
if (command.InstanceId != null)
return await _store.DeleteWhereAsync(x => x.Id == command.InstanceId, cancellationToken);
return 0;
}
}

View file

@ -29,4 +29,14 @@ public class DeleteWorkflowInstancesHandler : ICommandHandler<DeleteWorkflowInst
return Task.FromResult(Unit.Instance);
}
public Task<Unit> HandleAsync(DeleteWorkflowInstance command, CancellationToken cancellationToken)
{
if (command.InstanceId != null)
{
_store.Delete(command.InstanceId);
}
return Task.FromResult(Unit.Instance);
}
}

View file

@ -9,6 +9,7 @@
<ItemGroup>
<PackageReference Include="Fluid.Core" Version="2.2.14" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
</ItemGroup>
<ItemGroup>