Enhanced Workflow Instance Filters (#4957)
* Add timestamp filtering for workflow instances Implemented a new feature in the workflow instances' querying API, enabling filtering based on timestamps. The changes include adding a new TimestampFilter class and modifying existing classes accordingly. This new filter supports various operators such as greater than and less than, providing flexibility in filtering workflow instances. * Improve timestamp filtering efficiency and update UI in WorkflowInstanceList Timestamp filtering within WorkflowInstanceList is refactored using System.Linq.Dynamic.Core for more compact expression. This change results in simpler and more efficient code, reducing repetitive code lines. The UI updates include changing the MudGrid structure to table for timestamp filters display, offering a more organized view. Also, protection against null or minimum date values during parsing and comparisons is added, increasing stability and safety of operations. * Refactor HTTP verbs and routes configuration in Endpoint.cs The previous Get and Post method calls for handling '/workflow-instances' have been replaced with a Verbs method for HTTP verbs and a Routes method for setting the route. * Update WorkflowInstanceFilter to use nullable HasIncidents The HasIncidents property in WorkflowInstanceFilter has been updated from a bool to a nullable bool so that it can represent three states (true, false, or null) instead of only two. This allows not only to filter workflow instances that have incidents, but also those that don't have any, enhancing the flexibility of the filter in the process. * Improve search functionality and UI in WorkflowInstanceList Updated search term comparison in WorkflowInstanceFilter to use "Contains" instead of "Equals" to improve search flexibility. Also, enhanced the user interface in WorkflowInstanceList by adding debounce interval for the search input for performance reasons and by adding a Close button for convenience. * Add input validation to WorkflowInstances endpoint The code modifies the API endpoint for WorkflowInstances. It now checks that the input provided in the request is valid before proceeding. Furthermore, a new file called 'RequiredMembers.cs' has been added, which introduces two new attributes 'RequiredMemberAttribute' and 'CompilerFeatureRequiredAttribute'. * Update src/modules/Elsa.Workflows.Management/Models/TimestampFilter.cs Co-authored-by: Béchir BEN AMEUR <32399944+bbenameur@users.noreply.github.com> * Update src/modules/Elsa.Workflows.Management/Models/TimestampFilter.cs Co-authored-by: Béchir BEN AMEUR <32399944+bbenameur@users.noreply.github.com> * Update src/modules/Elsa.Workflows.Management/Models/TimestampFilter.cs Co-authored-by: Béchir BEN AMEUR <32399944+bbenameur@users.noreply.github.com> --------- Co-authored-by: Béchir BEN AMEUR <32399944+bbenameur@users.noreply.github.com>
This commit is contained in:
parent
01c34e6b13
commit
c80f80fd81
|
|
@ -87,6 +87,7 @@
|
|||
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
<PackageVersion Include="System.Data.SqlClient" Version="4.8.6" />
|
||||
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageVersion Include="System.Linq.Dynamic.Core" Version="1.3.8" />
|
||||
<PackageVersion Include="Testcontainers" Version="3.6.0" />
|
||||
<PackageVersion Include="Testcontainers.Redis" Version="3.6.0" />
|
||||
<PackageVersion Include="ThrottleDebounce" Version="2.0.0" />
|
||||
|
|
|
|||
10
NuGet.Config
10
NuGet.Config
|
|
@ -3,8 +3,14 @@
|
|||
<packageSources>
|
||||
<clear />
|
||||
<add key="NuGet official package source" value="https://api.nuget.org/v3/index.json" />
|
||||
<!--
|
||||
<add key="Elsa 3 Preview" value="https://f.feedz.io/elsa-workflows/elsa-3/nuget/index.json" />
|
||||
-->
|
||||
</packageSources>
|
||||
<packageSourceMapping>
|
||||
<packageSource key="NuGet official package source">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
<packageSource key="Elsa 3 Preview">
|
||||
<package pattern="Elsa.*" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
|
|
@ -14,7 +14,7 @@ public interface IWorkflowInstancesApi
|
|||
/// <summary>
|
||||
/// Returns a list of workflow instances.
|
||||
/// </summary>
|
||||
[Get("/workflow-instances")]
|
||||
[Post("/workflow-instances")]
|
||||
Task<PagedListResponse<WorkflowInstanceSummary>> ListAsync(ListWorkflowInstancesRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -13,64 +13,74 @@ public class ListWorkflowInstancesRequest
|
|||
/// Gets or sets the page number.
|
||||
/// </summary>
|
||||
public int? Page { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the page size.
|
||||
/// </summary>
|
||||
public int? PageSize { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the search term.
|
||||
/// </summary>
|
||||
public string? SearchTerm { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the workflow definition id.
|
||||
/// </summary>
|
||||
public string? DefinitionId { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the workflow definition ids.
|
||||
/// </summary>
|
||||
[Query(CollectionFormat.Multi)] public ICollection<string>? DefinitionIds { get; set; }
|
||||
|
||||
public ICollection<string>? DefinitionIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the correlation id.
|
||||
/// </summary>
|
||||
public string? CorrelationId { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the version.
|
||||
/// </summary>
|
||||
public int? Version { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the workflow instances have incidents or not.
|
||||
/// </summary>
|
||||
public bool? HasIncidents { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status.
|
||||
/// </summary>
|
||||
public WorkflowStatus? Status { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the statuses.
|
||||
/// </summary>
|
||||
[Query(CollectionFormat.Multi)] public ICollection<WorkflowStatus>? Statuses { get; set; }
|
||||
|
||||
public ICollection<WorkflowStatus>? Statuses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sub status.
|
||||
/// </summary>
|
||||
public WorkflowSubStatus? SubStatus { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sub statuses.
|
||||
/// </summary>
|
||||
[Query(CollectionFormat.Multi)] public ICollection<WorkflowSubStatus>? SubStatuses { get; set; }
|
||||
public ICollection<WorkflowSubStatus>? SubStatuses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the key to order by.
|
||||
/// </summary>
|
||||
public OrderByWorkflowInstance? OrderBy { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the order direction.
|
||||
/// </summary>
|
||||
public OrderDirection? OrderDirection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp filters.
|
||||
/// </summary>
|
||||
public ICollection<TimestampFilter>? TimestampFilters { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
namespace Elsa.Api.Client.Shared.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the operators for filtering timestamps in a TimestampFilter object.
|
||||
/// </summary>
|
||||
public enum TimestampFilterOperator
|
||||
{
|
||||
/// <summary>
|
||||
/// The timestamp is equal to the specified value.
|
||||
/// </summary>
|
||||
Is,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is not equal to the specified value.
|
||||
/// </summary>
|
||||
IsNot,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is before the specified value.
|
||||
/// </summary>
|
||||
LessThan,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is greater than the specified value.
|
||||
/// </summary>
|
||||
GreaterThan,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is less than or equal to the specified value.
|
||||
/// </summary>
|
||||
LessThanOrEqual,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is greater than or equal to the specified value.
|
||||
/// </summary>
|
||||
GreaterThanOrEqual
|
||||
}
|
||||
26
src/clients/Elsa.Api.Client/Shared/Models/TimestampFilter.cs
Normal file
26
src/clients/Elsa.Api.Client/Shared/Models/TimestampFilter.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using Elsa.Api.Client.Shared.Enums;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Api.Client.Shared.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a timestamp filter used for filtering data based on a specified timestamp column and operator.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class TimestampFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the column to filter by.
|
||||
/// </summary>
|
||||
public string Column { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the operator to use for filtering.
|
||||
/// </summary>
|
||||
public TimestampFilterOperator Operator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp to filter by.
|
||||
/// </summary>
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
}
|
||||
|
|
@ -6,57 +6,98 @@ using Elsa.Workflows.Management.Contracts;
|
|||
using Elsa.Workflows.Management.Filters;
|
||||
using Elsa.Workflows.Management.Models;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Workflows.Api.Endpoints.WorkflowInstances.List;
|
||||
|
||||
[PublicAPI]
|
||||
internal class List : ElsaEndpoint<Request, Response>
|
||||
[UsedImplicitly]
|
||||
internal class List(IWorkflowInstanceStore store) : ElsaEndpoint<Request, Response>
|
||||
{
|
||||
private readonly IWorkflowInstanceStore _store;
|
||||
|
||||
public List(IWorkflowInstanceStore store)
|
||||
{
|
||||
_store = store;
|
||||
}
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/workflow-instances");
|
||||
Verbs(FastEndpoints.Http.GET, FastEndpoints.Http.POST);
|
||||
Routes("/workflow-instances");
|
||||
ConfigurePermissions("read:workflow-instances");
|
||||
}
|
||||
|
||||
public override async Task<Response> ExecuteAsync(Request request, CancellationToken cancellationToken)
|
||||
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var pageArgs = PageArgs.FromPage(request.Page, request.PageSize);
|
||||
|
||||
if (!await ValidateInputAsync(request, cancellationToken))
|
||||
{
|
||||
await SendErrorsAsync(StatusCodes.Status400BadRequest, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var filter = new WorkflowInstanceFilter
|
||||
{
|
||||
SearchTerm = request.SearchTerm,
|
||||
DefinitionId = request.DefinitionId,
|
||||
DefinitionIds = request.DefinitionIds,
|
||||
DefinitionIds = request.DefinitionIds?.Any() == true ? request.DefinitionIds : null,
|
||||
Version = request.Version,
|
||||
CorrelationId = request.CorrelationId,
|
||||
WorkflowStatus = request.Status,
|
||||
WorkflowSubStatus = request.SubStatus,
|
||||
WorkflowStatuses = request.Statuses?.Select(Enum.Parse<WorkflowStatus>).ToList(),
|
||||
WorkflowSubStatuses = request.SubStatuses?.Select(Enum.Parse<WorkflowSubStatus>).ToList(),
|
||||
ToCreatedAt = request.ToCreatedAt,
|
||||
FromCreatedAt = request.FromCreatedAt,
|
||||
WorkflowStatuses = request.Statuses?.Any() == true ? request.Statuses : null,
|
||||
WorkflowSubStatuses = request.SubStatuses?.Any() == true ? request.SubStatuses : null,
|
||||
HasIncidents = request.HasIncidents,
|
||||
TimestampFilters = request.TimestampFilters?.Any() == true ? request.TimestampFilters : null,
|
||||
};
|
||||
|
||||
var summaries = await FindAsync(request, filter, pageArgs, cancellationToken);
|
||||
return new Response(summaries.Items, summaries.TotalCount);
|
||||
var response = new Response(summaries.Items, summaries.TotalCount);
|
||||
await SendOkAsync(response, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<bool> ValidateInputAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (request.Page is < 0)
|
||||
{
|
||||
AddError("Page must be greater than or equal to 1.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (request.PageSize is < 1)
|
||||
{
|
||||
AddError("Page size must be greater than or equal to 1.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var columnWhitelist = new[]
|
||||
{
|
||||
"CreatedAt", "UpdatedAt", "FinishedAt"
|
||||
};
|
||||
|
||||
if (request.TimestampFilters?.Any() == true)
|
||||
{
|
||||
foreach (var timestampFilter in request.TimestampFilters)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(timestampFilter.Column))
|
||||
{
|
||||
AddError("Column must be specified.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!columnWhitelist.Contains(timestampFilter.Column))
|
||||
{
|
||||
AddError($"Invalid column '{timestampFilter.Column}'.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<Page<WorkflowInstanceSummary>> FindAsync(Request request, WorkflowInstanceFilter filter, PageArgs pageArgs, CancellationToken cancellationToken)
|
||||
{
|
||||
request.OrderBy = request.OrderBy ?? OrderByWorkflowInstance.Created;
|
||||
var direction = request.OrderBy == OrderByWorkflowInstance.Name ? (request.OrderDirection ?? OrderDirection.Ascending) : (request.OrderDirection ?? OrderDirection.Descending);
|
||||
request.OrderBy ??= OrderByWorkflowInstance.Created;
|
||||
var direction = request.OrderBy == OrderByWorkflowInstance.Name ? request.OrderDirection ?? OrderDirection.Ascending : request.OrderDirection ?? OrderDirection.Descending;
|
||||
|
||||
switch (request.OrderBy)
|
||||
{
|
||||
default:
|
||||
case OrderByWorkflowInstance.Created:
|
||||
{
|
||||
var o = new WorkflowInstanceOrder<DateTimeOffset>
|
||||
{
|
||||
|
|
@ -64,7 +105,7 @@ internal class List : ElsaEndpoint<Request, Response>
|
|||
Direction = direction
|
||||
};
|
||||
|
||||
return await _store.SummarizeManyAsync(filter, pageArgs, o, cancellationToken);
|
||||
return await store.SummarizeManyAsync(filter, pageArgs, o, cancellationToken);
|
||||
}
|
||||
case OrderByWorkflowInstance.UpdatedAt:
|
||||
{
|
||||
|
|
@ -74,7 +115,7 @@ internal class List : ElsaEndpoint<Request, Response>
|
|||
Direction = direction
|
||||
};
|
||||
|
||||
return await _store.SummarizeManyAsync(filter, pageArgs, o, cancellationToken);
|
||||
return await store.SummarizeManyAsync(filter, pageArgs, o, cancellationToken);
|
||||
}
|
||||
case OrderByWorkflowInstance.Finished:
|
||||
{
|
||||
|
|
@ -84,7 +125,7 @@ internal class List : ElsaEndpoint<Request, Response>
|
|||
Direction = direction
|
||||
};
|
||||
|
||||
return await _store.SummarizeManyAsync(filter, pageArgs, o, cancellationToken);
|
||||
return await store.SummarizeManyAsync(filter, pageArgs, o, cancellationToken);
|
||||
}
|
||||
case OrderByWorkflowInstance.Name:
|
||||
{
|
||||
|
|
@ -94,7 +135,7 @@ internal class List : ElsaEndpoint<Request, Response>
|
|||
Direction = direction
|
||||
};
|
||||
|
||||
return await _store.SummarizeManyAsync(filter, pageArgs, o, cancellationToken);
|
||||
return await store.SummarizeManyAsync(filter, pageArgs, o, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,25 +12,21 @@ public class Request
|
|||
public string? DefinitionId { get; set; }
|
||||
public ICollection<string>? DefinitionIds { get; set; }
|
||||
public string? CorrelationId { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public int? Version { get; set; }
|
||||
public bool? HasIncidents { get; set; }
|
||||
public WorkflowStatus? Status { get; set; }
|
||||
public ICollection<string>? Statuses { get; set; }
|
||||
public ICollection<WorkflowStatus>? Statuses { get; set; }
|
||||
public WorkflowSubStatus? SubStatus { get; set; }
|
||||
public ICollection<string>? SubStatuses { get; set; }
|
||||
public ICollection<WorkflowSubStatus>? SubStatuses { get; set; }
|
||||
public OrderByWorkflowInstance? OrderBy { get; set; }
|
||||
public OrderDirection? OrderDirection { get; set; }
|
||||
public DateTimeOffset? FromCreatedAt { get; set; }
|
||||
public DateTimeOffset? ToCreatedAt { get; set; }
|
||||
public ICollection<TimestampFilter>? TimestampFilters { get; set; }
|
||||
}
|
||||
|
||||
public class Response
|
||||
internal class Response(ICollection<WorkflowInstanceSummary> items, long totalCount)
|
||||
{
|
||||
public Response(ICollection<WorkflowInstanceSummary> items, long totalCount)
|
||||
{
|
||||
Items = items;
|
||||
TotalCount = totalCount;
|
||||
}
|
||||
public ICollection<WorkflowInstanceSummary> Items { get; set; } = items;
|
||||
public long TotalCount { get; set; } = totalCount;
|
||||
}
|
||||
|
||||
public ICollection<WorkflowInstanceSummary> Items { get; set; }
|
||||
public long TotalCount { get; set; }
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" />
|
||||
<PackageReference Include="IronCompress" />
|
||||
<PackageReference Include="System.Linq.Async" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
namespace Elsa.Workflows.Management.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the operators for filtering timestamps in a TimestampFilter object.
|
||||
/// </summary>
|
||||
public enum TimestampFilterOperator
|
||||
{
|
||||
/// <summary>
|
||||
/// The timestamp is equal to the specified value.
|
||||
/// </summary>
|
||||
Is,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is not equal to the specified value.
|
||||
/// </summary>
|
||||
IsNot,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is before the specified value.
|
||||
/// </summary>
|
||||
LessThan,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is greater than the specified value.
|
||||
/// </summary>
|
||||
GreaterThan,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is less than or equal to the specified value.
|
||||
/// </summary>
|
||||
LessThanOrEqual,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp is greater than or equal to the specified value.
|
||||
/// </summary>
|
||||
GreaterThanOrEqual
|
||||
}
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Elsa.Workflows.Management.Entities;
|
||||
using Elsa.Workflows.Management.Enums;
|
||||
using Elsa.Workflows.Management.Models;
|
||||
using System.Linq.Dynamic.Core;
|
||||
|
||||
namespace Elsa.Workflows.Management.Filters;
|
||||
|
||||
|
|
@ -61,7 +65,7 @@ public class WorkflowInstanceFilter
|
|||
/// Filter workflow instances by status.
|
||||
/// </summary>
|
||||
public WorkflowStatus? WorkflowStatus { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Filter workflow instances by a set of statuses.
|
||||
/// </summary>
|
||||
|
|
@ -71,25 +75,26 @@ public class WorkflowInstanceFilter
|
|||
/// Filter workflow instances by sub-status.
|
||||
/// </summary>
|
||||
public WorkflowSubStatus? WorkflowSubStatus { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Filter workflow instances by a set of sub-status.
|
||||
/// </summary>
|
||||
public ICollection<WorkflowSubStatus>? WorkflowSubStatuses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter workflow instances by created date time, start from this date time.
|
||||
/// Filter workflow instances by whether they have incidents.
|
||||
/// </summary>
|
||||
public DateTimeOffset? FromCreatedAt { get; set; }
|
||||
public bool? HasIncidents { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter workflow instances by created date time, to this date time.
|
||||
/// Filter workflow instances by timestamp.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ToCreatedAt { get; set; }
|
||||
public ICollection<TimestampFilter>? TimestampFilters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Applies the filter to the specified query.
|
||||
/// </summary>
|
||||
[RequiresUnreferencedCode("The method uses reflection to create an expression tree.")]
|
||||
public IQueryable<WorkflowInstance> Apply(IQueryable<WorkflowInstance> query)
|
||||
{
|
||||
var filter = this;
|
||||
|
|
@ -106,8 +111,36 @@ public class WorkflowInstanceFilter
|
|||
if (filter.WorkflowSubStatus != null) query = query.Where(x => x.SubStatus == filter.WorkflowSubStatus);
|
||||
if (filter.WorkflowStatuses != null) query = query.Where(x => filter.WorkflowStatuses.Contains(x.Status));
|
||||
if (filter.WorkflowSubStatuses != null) query = query.Where(x => filter.WorkflowSubStatuses.Contains(x.SubStatus));
|
||||
if (filter.ToCreatedAt is not null) query = query.Where(x => filter.ToCreatedAt >= x.CreatedAt);
|
||||
if (filter.FromCreatedAt is not null) query = query.Where(x => filter.FromCreatedAt <= x.CreatedAt);
|
||||
if (filter.HasIncidents != null) query = filter.HasIncidents == true ? query.Where(x => x.IncidentCount > 0) : query.Where(x => x.IncidentCount == 0);
|
||||
|
||||
if (TimestampFilters != null)
|
||||
{
|
||||
foreach (TimestampFilter timestampFilter in TimestampFilters)
|
||||
{
|
||||
var column = timestampFilter.Column;
|
||||
var timestamp = timestampFilter.Timestamp;
|
||||
var isZeroTime = timestamp.TimeOfDay == TimeSpan.Zero;
|
||||
var startDay = new DateTimeOffset(timestamp.Date);
|
||||
var endDay = startDay.AddDays(1);
|
||||
|
||||
query = timestampFilter.Operator switch
|
||||
{
|
||||
TimestampFilterOperator.Is when isZeroTime => query.Where($"{column} >= @0 && {column} < @1", startDay, endDay),
|
||||
TimestampFilterOperator.Is => query.Where($"{column} == @0", timestamp),
|
||||
TimestampFilterOperator.IsNot when isZeroTime => query.Where($"{column} < @0 || {column} >= @1", startDay, endDay),
|
||||
TimestampFilterOperator.IsNot => query.Where($"{column} != @0", timestamp),
|
||||
TimestampFilterOperator.GreaterThan when isZeroTime => query.Where($"{column} > @0", endDay),
|
||||
TimestampFilterOperator.GreaterThan => query.Where($"{column} > @0", timestamp),
|
||||
TimestampFilterOperator.GreaterThanOrEqual when isZeroTime => query.Where($"{column} >= @0", startDay),
|
||||
TimestampFilterOperator.GreaterThanOrEqual => query.Where($"{column} >= @0", timestamp),
|
||||
TimestampFilterOperator.LessThan when isZeroTime => query.Where($"{column} < @0", startDay),
|
||||
TimestampFilterOperator.LessThan => query.Where($"{column} < @0", timestamp),
|
||||
TimestampFilterOperator.LessThanOrEqual when isZeroTime => query.Where($"{column} <= @0", endDay),
|
||||
TimestampFilterOperator.LessThanOrEqual => query.Where($"{column} <= @0", timestamp),
|
||||
_ => query
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var searchTerm = filter.SearchTerm;
|
||||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||||
|
|
@ -115,10 +148,10 @@ public class WorkflowInstanceFilter
|
|||
query =
|
||||
from instance in query
|
||||
where instance.Name!.Contains(searchTerm)
|
||||
|| instance.DefinitionVersionId.Equals(searchTerm)
|
||||
|| instance.Id.Equals(searchTerm)
|
||||
|| instance.DefinitionId.Equals(searchTerm)
|
||||
|| instance.CorrelationId!.Equals(searchTerm)
|
||||
|| instance.DefinitionVersionId.Contains(searchTerm)
|
||||
|| instance.DefinitionId.Contains(searchTerm)
|
||||
|| instance.Id.Contains(searchTerm)
|
||||
|| instance.CorrelationId!.Contains(searchTerm)
|
||||
select instance;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
using Elsa.Workflows.Management.Enums;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Workflows.Management.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a timestamp filter used for filtering data based on a specified timestamp column and operator.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class TimestampFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the column to filter by.
|
||||
/// </summary>
|
||||
public required string Column { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the operator to use for filtering.
|
||||
/// </summary>
|
||||
public required TimestampFilterOperator Operator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp to filter by.
|
||||
/// </summary>
|
||||
public required DateTimeOffset Timestamp { get; set; }
|
||||
}
|
||||
8
src/modules/Elsa.Workflows.Management/RequiredMembers.cs
Normal file
8
src/modules/Elsa.Workflows.Management/RequiredMembers.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// See: https://github.com/dotnet/core/issues/8016
|
||||
namespace System.Runtime.CompilerServices;
|
||||
|
||||
public class RequiredMemberAttribute : Attribute { }
|
||||
public class CompilerFeatureRequiredAttribute : Attribute
|
||||
{
|
||||
public CompilerFeatureRequiredAttribute(string name) { }
|
||||
}
|
||||
Loading…
Reference in a new issue