From 98b9957fae39d8f594ba15270cc1199ac72b47fc Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 16 Dec 2020 23:03:08 +0100 Subject: [PATCH] Implement workflow filter --- src/clients/Elsa.Client/Models/OrderBy.cs | 8 ++++ .../Elsa.Client/Models/WorkflowInstance.cs | 38 +++++++++---------- .../Services/IWorkflowInstancesApi.cs | 12 ++++-- .../Builders/IActivityBuilder.cs | 1 - .../Pages/WorkflowInstances/List.razor | 14 +++---- .../Pages/WorkflowInstances/List.razor.cs | 34 ++++++----------- .../Rpc/WorkflowInstanceService.cs | 5 ++- .../WorkflowInstanceServiceExtensions.cs | 10 ++++- .../Models/ListWorkflowInstancesRequest.cs | 11 +++++- .../Endpoints/WorkflowInstances/List.cs | 12 +++++- src/server/Elsa.Server.Api/Models/OrderBy.cs | 8 ++++ .../Elsa.Server.Host/Workflows/HelloWorld.cs | 1 + .../Workflows/HelloWorld.v2.cs | 3 +- 13 files changed, 98 insertions(+), 59 deletions(-) create mode 100644 src/clients/Elsa.Client/Models/OrderBy.cs create mode 100644 src/server/Elsa.Server.Api/Models/OrderBy.cs diff --git a/src/clients/Elsa.Client/Models/OrderBy.cs b/src/clients/Elsa.Client/Models/OrderBy.cs new file mode 100644 index 000000000..e176b5f57 --- /dev/null +++ b/src/clients/Elsa.Client/Models/OrderBy.cs @@ -0,0 +1,8 @@ +namespace Elsa.Client.Models +{ + public enum OrderBy + { + Started, + Finished + } +} \ No newline at end of file diff --git a/src/clients/Elsa.Client/Models/WorkflowInstance.cs b/src/clients/Elsa.Client/Models/WorkflowInstance.cs index 5b5201edf..798aa188d 100644 --- a/src/clients/Elsa.Client/Models/WorkflowInstance.cs +++ b/src/clients/Elsa.Client/Models/WorkflowInstance.cs @@ -19,30 +19,30 @@ namespace Elsa.Client.Models PostScheduledActivities = new Stack(); } - [DataMember(Order = 1)] public int Id { get; set; } - [DataMember(Order = 2)] public string WorkflowInstanceId { get; set; } = default!; - [DataMember(Order = 3)] public string WorkflowDefinitionId { get; set; } = default!; - [DataMember(Order = 4)] public int Version { get; set; } - [DataMember(Order = 5)] public WorkflowStatus Status { get; set; } - [DataMember(Order = 6)] public string? CorrelationId { get; set; } - [DataMember(Order = 7)] public string? ContextId { get; set; } - [DataMember(Order = 8)] public Instant CreatedAt { get; set; } - [DataMember(Order = 9)] public Instant? LastExecutedAt { get; set; } - [DataMember(Order = 10)] public Instant? LastBurstAt { get; set; } - [DataMember(Order = 11)] public Instant? CompletedAt { get; set; } - [DataMember(Order = 12)] public Variables Variables { get; set; } - [DataMember(Order = 13)] public object? Output { get; set; } - [DataMember(Order = 14)] public ICollection Activities { get; set; } + [DataMember(Order = 1)] public string EntityId { get; set; } = default!; + [DataMember(Order = 2)] public string DefinitionId { get; set; } = default!; + [DataMember(Order = 3)] public int Version { get; set; } + [DataMember(Order = 4)] public WorkflowStatus WorkflowStatus { get; set; } + [DataMember(Order = 5)] public string? CorrelationId { get; set; } + [DataMember(Order = 6)] public string? ContextId { get; set; } + [DataMember(Order = 7)] public Instant CreatedAt { get; set; } + [DataMember(Order = 8)] public Instant? LastExecutedAt { get; set; } + [DataMember(Order = 9)] public Instant? LastBurstAt { get; set; } + [DataMember(Order = 10)] public Instant? CompletedAt { get; set; } + [DataMember(Order = 11)] public Variables Variables { get; set; } + [DataMember(Order = 12)] public object? Output { get; set; } + [DataMember(Order = 13)] public ICollection Activities { get; set; } - [DataMember(Order = 15)] public HashSet BlockingActivities + [DataMember(Order = 14)] + public HashSet BlockingActivities { get => _blockingActivities; set => _blockingActivities = new HashSet(value, BlockingActivityEqualityComparer.Instance); } - [DataMember(Order = 16)] public ICollection ExecutionLog { get; set; } - [DataMember(Order = 17)] public WorkflowFault? Fault { get; set; } - [DataMember(Order = 18)] public Stack ScheduledActivities { get; set; } - [DataMember(Order = 19)] public Stack PostScheduledActivities { get; set; } + [DataMember(Order = 15)] public ICollection ExecutionLog { get; set; } + [DataMember(Order = 16)] public WorkflowFault? Fault { get; set; } + [DataMember(Order = 17)] public Stack ScheduledActivities { get; set; } + [DataMember(Order = 18)] public Stack PostScheduledActivities { get; set; } } } \ No newline at end of file diff --git a/src/clients/Elsa.Client/Services/IWorkflowInstancesApi.cs b/src/clients/Elsa.Client/Services/IWorkflowInstancesApi.cs index 109891d24..21d8a5aee 100644 --- a/src/clients/Elsa.Client/Services/IWorkflowInstancesApi.cs +++ b/src/clients/Elsa.Client/Services/IWorkflowInstancesApi.cs @@ -9,10 +9,16 @@ namespace Elsa.Client.Services { [Get("/v1/workflow-instances/{id}")] Task GetByIdAsync(string id, CancellationToken cancellationToken = default); - + [Get("/v1/workflow-instances")] - Task> ListAsync(int? page = default, int? pageSize = default, CancellationToken cancellationToken = default); - + Task> ListAsync( + int? page = default, + int? pageSize = default, + [AliasAs("workflow")] string? workflowDefinitionId = default, + [AliasAs("status")] WorkflowStatus? workflowStatus = default, + OrderBy? orderBy = default, + CancellationToken cancellationToken = default); + [Delete("/v1/workflow-instances/{id}")] Task DeleteAsync(string id, CancellationToken cancellationToken = default); } diff --git a/src/core/Elsa.Abstractions/Builders/IActivityBuilder.cs b/src/core/Elsa.Abstractions/Builders/IActivityBuilder.cs index 6d5f8093e..84a89a2d2 100644 --- a/src/core/Elsa.Abstractions/Builders/IActivityBuilder.cs +++ b/src/core/Elsa.Abstractions/Builders/IActivityBuilder.cs @@ -24,6 +24,5 @@ namespace Elsa.Builders IActivityBuilder WithName(string? name); IActivityBuilder LoadWorkflowContext(bool value = true); IActivityBuilder SaveWorkflowContext(bool value = true); - //Func> BuildActivityAsync(); } } \ No newline at end of file diff --git a/src/dashboards/blazor/ElsaDashboard.Application/Pages/WorkflowInstances/List.razor b/src/dashboards/blazor/ElsaDashboard.Application/Pages/WorkflowInstances/List.razor index 314e4e779..be8816cb2 100644 --- a/src/dashboards/blazor/ElsaDashboard.Application/Pages/WorkflowInstances/List.razor +++ b/src/dashboards/blazor/ElsaDashboard.Application/Pages/WorkflowInstances/List.razor @@ -88,18 +88,18 @@ @foreach (var workflowInstance in WorkflowInstances.Items) { - var workflowBlueprint = WorkflowBlueprints[(workflowInstance.WorkflowDefinitionId, workflowInstance.Version)]; + var workflowBlueprint = WorkflowBlueprints[(workflowInstance.DefinitionId, workflowInstance.Version)]; var displayName = workflowBlueprint.DisplayName; - var statusColor = GetStatusColor(workflowInstance.Status); - var viewUrl = $"workflow-instances/{workflowInstance.WorkflowInstanceId}/viewer"; + var statusColor = GetStatusColor(workflowInstance.WorkflowStatus); + var viewUrl = $"workflow-instances/{workflowInstance.EntityId}/viewer"; - - @workflowInstance.WorkflowInstanceId + + @workflowInstance.EntityId - + @displayName @@ -109,7 +109,7 @@
- @workflowInstance.Status + @workflowInstance.WorkflowStatus
diff --git a/src/dashboards/blazor/ElsaDashboard.Application/Pages/WorkflowInstances/List.razor.cs b/src/dashboards/blazor/ElsaDashboard.Application/Pages/WorkflowInstances/List.razor.cs index 0eee0f8e6..3e3539f20 100644 --- a/src/dashboards/blazor/ElsaDashboard.Application/Pages/WorkflowInstances/List.razor.cs +++ b/src/dashboards/blazor/ElsaDashboard.Application/Pages/WorkflowInstances/List.razor.cs @@ -24,23 +24,9 @@ namespace ElsaDashboard.Application.Pages.WorkflowInstances [Inject] private IConfirmDialogService ConfirmDialogService { get; set; } = default!; private PagedList WorkflowInstances { get; set; } = new(); private IDictionary<(string, int), WorkflowBlueprint> WorkflowBlueprints { get; set; } = new Dictionary<(string, int), WorkflowBlueprint>(); - - private IEnumerable WorkflowFilterItems => WorkflowBlueprints.Values - .OrderByDescending(x => x.Version) - .GroupBy(x => x.Id) - .Select(x => x.First()) - .Select(x => (x.Id, x.DisplayName)) - .Select(x => new ButtonDropdownItem(x.DisplayName!, x.Id, $"workflow-instances?workflow={x.Id}", x.Id == SelectedWorkflowId)); - - private string SelectedWorkflowText => - SelectedWorkflowId == null - ? "Workflow" - : WorkflowBlueprints - .GroupBy(x => x.Value.Id, x => x.Value) - .FirstOrDefault(x => x.Key == SelectedWorkflowId) - ?.OrderByDescending(x => x.Version) - ?.FirstOrDefault() - ?.DisplayName ?? "Workflow"; + private IEnumerable LatestWorkflowBlueprints => GetLatestVersions(WorkflowBlueprints.Values); + private IEnumerable WorkflowFilterItems => LatestWorkflowBlueprints.Select(x => new ButtonDropdownItem(x.DisplayName!, x.Id, $"workflow-instances?workflow={x.Id}", x.Id == SelectedWorkflowId)); + private string SelectedWorkflowText => SelectedWorkflowId == null ? "Workflow" : LatestWorkflowBlueprints.FirstOrDefault(x => x.Id == SelectedWorkflowId)?.DisplayName ?? "Workflow"; public void Dispose() { @@ -66,6 +52,11 @@ namespace ElsaDashboard.Application.Pages.WorkflowInstances await LoadWorkflowInstancesAsync(); } + private async Task LoadWorkflowInstancesAsync() + { + WorkflowInstances = await WorkflowInstanceService.ListAsync(Page, PageSize, SelectedWorkflowId); + } + private async Task OnDeleteWorkflowInstanceClick(WorkflowInstance workflowInstance) { var result = await ConfirmDialogService.Show("Delete Workflow Instance", "Are you sure you want to delete this workflow instance?", "Delete"); @@ -73,15 +64,10 @@ namespace ElsaDashboard.Application.Pages.WorkflowInstances if (result.Cancelled) return; - await WorkflowInstanceService.DeleteAsync(workflowInstance.WorkflowInstanceId); + await WorkflowInstanceService.DeleteAsync(workflowInstance.EntityId); await LoadWorkflowInstancesAsync(); } - private async Task LoadWorkflowInstancesAsync() - { - WorkflowInstances = await WorkflowInstanceService.ListAsync(Page, PageSize); - } - private void OnLocationChanged(object? sender, LocationChangedEventArgs e) { this.SetParametersFromQueryString(NavigationManager); @@ -99,5 +85,7 @@ namespace ElsaDashboard.Application.Pages.WorkflowInstances WorkflowStatus.Cancelled => "yellow", _ => throw new ArgumentOutOfRangeException(nameof(status), status, null) }; + + private static IEnumerable GetLatestVersions(IEnumerable workflowBlueprints) => workflowBlueprints.GroupBy(x => x.Id).Select(x => x.OrderByDescending(y => y.Version).First()); } } \ No newline at end of file diff --git a/src/dashboards/blazor/ElsaDashboard.Backend/Rpc/WorkflowInstanceService.cs b/src/dashboards/blazor/ElsaDashboard.Backend/Rpc/WorkflowInstanceService.cs index b859b2ebf..72dee60f5 100644 --- a/src/dashboards/blazor/ElsaDashboard.Backend/Rpc/WorkflowInstanceService.cs +++ b/src/dashboards/blazor/ElsaDashboard.Backend/Rpc/WorkflowInstanceService.cs @@ -10,7 +10,10 @@ namespace ElsaDashboard.Backend.Rpc { private readonly IElsaClient _elsaClient; public WorkflowInstanceService(IElsaClient elsaClient) => _elsaClient = elsaClient; - public Task> ListAsync(ListWorkflowInstancesRequest request, CallContext context = default) => _elsaClient.WorkflowInstances.ListAsync(request.Page, request.PageSize, context.CancellationToken); + + public Task> ListAsync(ListWorkflowInstancesRequest request, CallContext context = default) => + _elsaClient.WorkflowInstances.ListAsync(request.Page, request.PageSize, request.WorkflowDefinitionId, request.WorkflowStatus, request.OrderBy, context.CancellationToken); + public Task GetByIdAsync(GetWorkflowInstanceByIdRequest request, CallContext context = default) => _elsaClient.WorkflowInstances.GetByIdAsync(request.WorkflowInstanceId, context.CancellationToken); public Task DeleteAsync(DeleteWorkflowInstanceRequest request, CallContext context = default) => _elsaClient.WorkflowInstances.DeleteAsync(request.WorkflowInstanceId, context.CancellationToken); } diff --git a/src/dashboards/blazor/ElsaDashboard.Shared/Rpc/WorkflowInstance/Extensions/WorkflowInstanceServiceExtensions.cs b/src/dashboards/blazor/ElsaDashboard.Shared/Rpc/WorkflowInstance/Extensions/WorkflowInstanceServiceExtensions.cs index 9b1a7719f..21d66e40d 100644 --- a/src/dashboards/blazor/ElsaDashboard.Shared/Rpc/WorkflowInstance/Extensions/WorkflowInstanceServiceExtensions.cs +++ b/src/dashboards/blazor/ElsaDashboard.Shared/Rpc/WorkflowInstance/Extensions/WorkflowInstanceServiceExtensions.cs @@ -6,7 +6,15 @@ namespace ElsaDashboard.Shared.Rpc { public static class WorkflowInstanceServiceExtensions { - public static Task> ListAsync(this IWorkflowInstanceService service, int page = 0, int pageSize = 50) => service.ListAsync(new ListWorkflowInstancesRequest(page, pageSize)); + public static Task> ListAsync( + this IWorkflowInstanceService service, + int page = 0, + int pageSize = 50, + string? workflowDefinitionId = default, + WorkflowStatus? workflowStatus = default, + OrderBy? orderBy = default) => + service.ListAsync(new ListWorkflowInstancesRequest(page, pageSize, workflowDefinitionId, workflowStatus, orderBy)); + public static Task GetByIdAsync(this IWorkflowInstanceService service, string workflowInstanceId) => service.GetByIdAsync(new GetWorkflowInstanceByIdRequest(workflowInstanceId)); public static Task DeleteAsync(this IWorkflowInstanceService service, string workflowInstanceId) => service.DeleteAsync(new DeleteWorkflowInstanceRequest(workflowInstanceId)); } diff --git a/src/dashboards/blazor/ElsaDashboard.Shared/Rpc/WorkflowInstance/Models/ListWorkflowInstancesRequest.cs b/src/dashboards/blazor/ElsaDashboard.Shared/Rpc/WorkflowInstance/Models/ListWorkflowInstancesRequest.cs index f1d27e0d1..0e29d8da0 100644 --- a/src/dashboards/blazor/ElsaDashboard.Shared/Rpc/WorkflowInstance/Models/ListWorkflowInstancesRequest.cs +++ b/src/dashboards/blazor/ElsaDashboard.Shared/Rpc/WorkflowInstance/Models/ListWorkflowInstancesRequest.cs @@ -1,4 +1,5 @@ -using ProtoBuf; +using Elsa.Client.Models; +using ProtoBuf; // ReSharper disable once CheckNamespace namespace ElsaDashboard.Shared.Rpc @@ -10,13 +11,19 @@ namespace ElsaDashboard.Shared.Rpc { } - public ListWorkflowInstancesRequest(int page, int pageSize = 50) + public ListWorkflowInstancesRequest(int page, int pageSize = 50, string? workflowDefinitionId = default, WorkflowStatus? workflowStatus = default, OrderBy? orderBy = default) { Page = page; PageSize = pageSize; + WorkflowDefinitionId = workflowDefinitionId; + WorkflowStatus = workflowStatus; + OrderBy = orderBy; } [ProtoMember(1)] public int Page { get; set; } [ProtoMember(2)] public int PageSize { get; set; } = 50; + [ProtoMember(3)] public string? WorkflowDefinitionId { get; set; } + [ProtoMember(4)] public WorkflowStatus? WorkflowStatus { get; set; } + [ProtoMember(5)] public OrderBy? OrderBy { get; set; } } } \ No newline at end of file diff --git a/src/server/Elsa.Server.Api/Endpoints/WorkflowInstances/List.cs b/src/server/Elsa.Server.Api/Endpoints/WorkflowInstances/List.cs index fde746b18..9bd18556a 100644 --- a/src/server/Elsa.Server.Api/Endpoints/WorkflowInstances/List.cs +++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowInstances/List.cs @@ -32,9 +32,19 @@ namespace Elsa.Server.Api.Endpoints.WorkflowInstances OperationId = "WorkflowInstances.List", Tags = new[] { "WorkflowInstances" }) ] - public async Task>> Handle(int page = 0, int pageSize = 50, CancellationToken cancellationToken = default) + public async Task>> Handle( + [FromQuery(Name = "workflow")] string? workflowDefinitionId = default, + [FromQuery(Name = "status")] WorkflowStatus? workflowStatus = default, + [FromQuery] OrderBy? orderBy = default, + int page = 0, + int pageSize = 50, + CancellationToken cancellationToken = default) { var specification = Specification.All; + + if (!string.IsNullOrWhiteSpace(workflowDefinitionId)) + specification = specification.WithWorkflowDefinition(workflowDefinitionId); + var totalCount = await _workflowInstanceStore.CountAsync(specification, cancellationToken: cancellationToken); var paging = Paging.Page(page, pageSize); var workflowInstances = await _workflowInstanceStore.FindManyAsync(specification, paging: paging, cancellationToken: cancellationToken).ToList(); diff --git a/src/server/Elsa.Server.Api/Models/OrderBy.cs b/src/server/Elsa.Server.Api/Models/OrderBy.cs new file mode 100644 index 000000000..b7781729f --- /dev/null +++ b/src/server/Elsa.Server.Api/Models/OrderBy.cs @@ -0,0 +1,8 @@ +namespace Elsa.Server.Api.Models +{ + public enum OrderBy + { + Started, + Finished + } +} \ No newline at end of file diff --git a/src/server/Elsa.Server.Host/Workflows/HelloWorld.cs b/src/server/Elsa.Server.Host/Workflows/HelloWorld.cs index b851b0ae9..db704d485 100644 --- a/src/server/Elsa.Server.Host/Workflows/HelloWorld.cs +++ b/src/server/Elsa.Server.Host/Workflows/HelloWorld.cs @@ -9,6 +9,7 @@ namespace Elsa.Server.Host.Workflows public void Build(IWorkflowBuilder workflow) { workflow + .WithWorkflowDefinitionId("HelloWorld") .WithVersion(1) .WithDisplayName("Hello World!") .HttpRequestReceived("/hello-world") diff --git a/src/server/Elsa.Server.Host/Workflows/HelloWorld.v2.cs b/src/server/Elsa.Server.Host/Workflows/HelloWorld.v2.cs index fe222d023..3fc20adee 100644 --- a/src/server/Elsa.Server.Host/Workflows/HelloWorld.v2.cs +++ b/src/server/Elsa.Server.Host/Workflows/HelloWorld.v2.cs @@ -9,9 +9,10 @@ namespace Elsa.Server.Host.Workflows public void Build(IWorkflowBuilder workflow) { workflow + .WithWorkflowDefinitionId("HelloWorld") .WithVersion(2) .WithDisplayName("Hello World!") - .HttpRequestReceived("/hello-world") + .HttpRequestReceived("/hello-world/v2") .WriteHttpResponse(HttpStatusCode.OK, "Hello World V2!", "text/plain"); } }