Implement workflow filter
This commit is contained in:
parent
8419424c98
commit
98b9957fae
8
src/clients/Elsa.Client/Models/OrderBy.cs
Normal file
8
src/clients/Elsa.Client/Models/OrderBy.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
namespace Elsa.Client.Models
|
||||
{
|
||||
public enum OrderBy
|
||||
{
|
||||
Started,
|
||||
Finished
|
||||
}
|
||||
}
|
||||
|
|
@ -19,30 +19,30 @@ namespace Elsa.Client.Models
|
|||
PostScheduledActivities = new Stack<ScheduledActivity>();
|
||||
}
|
||||
|
||||
[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<ActivityInstance> 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<ActivityInstance> Activities { get; set; }
|
||||
|
||||
[DataMember(Order = 15)] public HashSet<BlockingActivity> BlockingActivities
|
||||
[DataMember(Order = 14)]
|
||||
public HashSet<BlockingActivity> BlockingActivities
|
||||
{
|
||||
get => _blockingActivities;
|
||||
set => _blockingActivities = new HashSet<BlockingActivity>(value, BlockingActivityEqualityComparer.Instance);
|
||||
}
|
||||
|
||||
[DataMember(Order = 16)] public ICollection<ExecutionLogEntry> ExecutionLog { get; set; }
|
||||
[DataMember(Order = 17)] public WorkflowFault? Fault { get; set; }
|
||||
[DataMember(Order = 18)] public Stack<ScheduledActivity> ScheduledActivities { get; set; }
|
||||
[DataMember(Order = 19)] public Stack<ScheduledActivity> PostScheduledActivities { get; set; }
|
||||
[DataMember(Order = 15)] public ICollection<ExecutionLogEntry> ExecutionLog { get; set; }
|
||||
[DataMember(Order = 16)] public WorkflowFault? Fault { get; set; }
|
||||
[DataMember(Order = 17)] public Stack<ScheduledActivity> ScheduledActivities { get; set; }
|
||||
[DataMember(Order = 18)] public Stack<ScheduledActivity> PostScheduledActivities { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -9,10 +9,16 @@ namespace Elsa.Client.Services
|
|||
{
|
||||
[Get("/v1/workflow-instances/{id}")]
|
||||
Task<WorkflowInstance?> GetByIdAsync(string id, CancellationToken cancellationToken = default);
|
||||
|
||||
|
||||
[Get("/v1/workflow-instances")]
|
||||
Task<PagedList<WorkflowInstance>> ListAsync(int? page = default, int? pageSize = default, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<PagedList<WorkflowInstance>> 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,5 @@ namespace Elsa.Builders
|
|||
IActivityBuilder WithName(string? name);
|
||||
IActivityBuilder LoadWorkflowContext(bool value = true);
|
||||
IActivityBuilder SaveWorkflowContext(bool value = true);
|
||||
//Func<ActivityExecutionContext, CancellationToken, ValueTask<IActivity>> BuildActivityAsync();
|
||||
}
|
||||
}
|
||||
|
|
@ -88,18 +88,18 @@
|
|||
<tbody class="bg-white divide-y divide-gray-100">
|
||||
@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";
|
||||
<tr>
|
||||
<td class="px-6 py-3 whitespace-no-wrap text-sm leading-5 font-medium text-gray-900">
|
||||
<a href="@($"workflow-instances/{workflowInstance.WorkflowInstanceId}/viewer")" class="truncate hover:text-gray-600">
|
||||
@workflowInstance.WorkflowInstanceId
|
||||
<a href="@($"workflow-instances/{workflowInstance.EntityId}/viewer")" class="truncate hover:text-gray-600">
|
||||
@workflowInstance.EntityId
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-6 py-3 whitespace-no-wrap text-sm leading-5 font-medium text-gray-900 text-left">
|
||||
<a href="@($"workflow-registry/{workflowInstance.WorkflowDefinitionId}/viewer")" class="truncate hover:text-gray-600">
|
||||
<a href="@($"workflow-registry/{workflowInstance.DefinitionId}/viewer")" class="truncate hover:text-gray-600">
|
||||
@displayName
|
||||
</a>
|
||||
</td>
|
||||
|
|
@ -109,7 +109,7 @@
|
|||
<td class="hidden md:table-cell px-6 py-3 whitespace-no-wrap text-sm leading-5 text-gray-500 text-right">
|
||||
<div class="flex items-center space-x-3 lg:pl-2">
|
||||
<div class="flex-shrink-0 w-2.5 h-2.5 rounded-full bg-@statusColor-600"></div>
|
||||
<span>@workflowInstance.Status</span>
|
||||
<span>@workflowInstance.WorkflowStatus</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="hidden md:table-cell px-6 py-3 whitespace-no-wrap text-sm leading-5 text-gray-500 text-left">
|
||||
|
|
|
|||
|
|
@ -24,23 +24,9 @@ namespace ElsaDashboard.Application.Pages.WorkflowInstances
|
|||
[Inject] private IConfirmDialogService ConfirmDialogService { get; set; } = default!;
|
||||
private PagedList<WorkflowInstance> WorkflowInstances { get; set; } = new();
|
||||
private IDictionary<(string, int), WorkflowBlueprint> WorkflowBlueprints { get; set; } = new Dictionary<(string, int), WorkflowBlueprint>();
|
||||
|
||||
private IEnumerable<ButtonDropdownItem> 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<WorkflowBlueprint> LatestWorkflowBlueprints => GetLatestVersions(WorkflowBlueprints.Values);
|
||||
private IEnumerable<ButtonDropdownItem> 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<WorkflowBlueprint> GetLatestVersions(IEnumerable<WorkflowBlueprint> workflowBlueprints) => workflowBlueprints.GroupBy(x => x.Id).Select(x => x.OrderByDescending(y => y.Version).First());
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,10 @@ namespace ElsaDashboard.Backend.Rpc
|
|||
{
|
||||
private readonly IElsaClient _elsaClient;
|
||||
public WorkflowInstanceService(IElsaClient elsaClient) => _elsaClient = elsaClient;
|
||||
public Task<PagedList<WorkflowInstance>> ListAsync(ListWorkflowInstancesRequest request, CallContext context = default) => _elsaClient.WorkflowInstances.ListAsync(request.Page, request.PageSize, context.CancellationToken);
|
||||
|
||||
public Task<PagedList<WorkflowInstance>> ListAsync(ListWorkflowInstancesRequest request, CallContext context = default) =>
|
||||
_elsaClient.WorkflowInstances.ListAsync(request.Page, request.PageSize, request.WorkflowDefinitionId, request.WorkflowStatus, request.OrderBy, context.CancellationToken);
|
||||
|
||||
public Task<WorkflowInstance?> 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,15 @@ namespace ElsaDashboard.Shared.Rpc
|
|||
{
|
||||
public static class WorkflowInstanceServiceExtensions
|
||||
{
|
||||
public static Task<PagedList<WorkflowInstance>> ListAsync(this IWorkflowInstanceService service, int page = 0, int pageSize = 50) => service.ListAsync(new ListWorkflowInstancesRequest(page, pageSize));
|
||||
public static Task<PagedList<WorkflowInstance>> 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<WorkflowInstance?> 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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -32,9 +32,19 @@ namespace Elsa.Server.Api.Endpoints.WorkflowInstances
|
|||
OperationId = "WorkflowInstances.List",
|
||||
Tags = new[] { "WorkflowInstances" })
|
||||
]
|
||||
public async Task<ActionResult<PagedList<WorkflowInstance>>> Handle(int page = 0, int pageSize = 50, CancellationToken cancellationToken = default)
|
||||
public async Task<ActionResult<PagedList<WorkflowInstance>>> 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<WorkflowInstance>.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();
|
||||
|
|
|
|||
8
src/server/Elsa.Server.Api/Models/OrderBy.cs
Normal file
8
src/server/Elsa.Server.Api/Models/OrderBy.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
namespace Elsa.Server.Api.Models
|
||||
{
|
||||
public enum OrderBy
|
||||
{
|
||||
Started,
|
||||
Finished
|
||||
}
|
||||
}
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue