Merge pull request #6370 from yinzara/feature/alterations-client-api

Added Alterations API to Client API library and updated server API co…
This commit is contained in:
Sipke Schoorstra 2025-02-06 16:45:25 +01:00
parent 92626d4443
commit 861fe40f66
No known key found for this signature in database
GPG key ID: 5C10502B28A4268F
30 changed files with 579 additions and 5 deletions

View file

@ -0,0 +1,6 @@
namespace Elsa.Api.Client.Resources.Alterations.Contracts;
/// <summary>
/// Marker interface for all alteration classes
/// </summary>
public interface IAlteration;

View file

@ -0,0 +1,52 @@
using Elsa.Api.Client.Resources.Alterations.Models;
using Elsa.Api.Client.Resources.Alterations.Requests;
using Elsa.Api.Client.Resources.Alterations.Responses;
using Refit;
namespace Elsa.Api.Client.Resources.Alterations.Contracts;
/// <summary>
/// Represents a client for the alterations API. Requires the Elsa.Alterations feature.
/// </summary>
public interface IAlterationsApi
{
/// <summary>
/// Returns an alteration plan and its associated jobs.
/// </summary>
/// <param name="id">The ID of the alteration plan to return.</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Get("/alterations/{id}")]
Task<GetAlterationPlanResponse> GetAsync(string id, CancellationToken cancellationToken = default);
/// <summary>
/// Determines which workflow instances a "Submit" request would target without actually running an alteration
/// </summary>
/// <param name="request">The requested workflow filter to dry run</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Post("/alterations/dry-run")]
Task<DryRunResponse> DryRun(AlterationWorkflowInstanceFilter request, CancellationToken cancellationToken = default);
/// <summary>
/// Submits an alteration plan and a filter for workflows instances to be executed against
/// </summary>
/// <param name="request">The alterations and filter to submit</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Post("/alterations/submit")]
Task<SubmitResponse> Submit(AlterationPlanParams request, CancellationToken cancellationToken = default);
/// <summary>
/// Runs an alteration plan and a list of workflow Instance Ids to be executed against
/// </summary>
/// <param name="request">The alterations and workflowInstanceIds to execute</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Post("/alterations/run")]
Task<RunResponse> Run(RunRequest request, CancellationToken cancellationToken = default);
/// <summary>
/// Retries the specified workflow instances.
/// </summary>
/// <param name="request">The request containing the selection of workflow instances to retry.</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Post("/alterations/workflows/retry")]
Task<BulkRetryResponse> BulkRetryAsync(BulkRetryRequest request, CancellationToken cancellationToken);
}

View file

@ -0,0 +1,32 @@
namespace Elsa.Api.Client.Resources.Alterations.Enums;
/// <summary>
/// Represents the status of an activity.
/// </summary>
public enum ActivityStatus
{
/// <summary>
/// The activity is in the Pending state.
/// </summary>
Pending,
/// <summary>
/// The activity is in the Running state. Note that event if an activity is running, it may not be executing.
/// </summary>
Running,
/// <summary>
/// The activity is in the Completed state.
/// </summary>
Completed,
/// <summary>
/// The activity is in the Canceled state.
/// </summary>
Canceled,
/// <summary>
/// The activity is in the Faulted state.
/// </summary>
Faulted
}

View file

@ -0,0 +1,27 @@
namespace Elsa.Api.Client.Resources.Alterations.Enums;
/// <summary>
/// The status of an alteration plan for a workflow instance.
/// </summary>
public enum AlterationJobStatus
{
/// <summary>
/// The plan is pending execution.
/// </summary>
Pending,
/// <summary>
/// The plan is currently being executed.
/// </summary>
Running,
/// <summary>
/// The plan has been completed.
/// </summary>
Completed,
/// <summary>
/// The job has failed.
/// </summary>
Failed
}

View file

@ -0,0 +1,37 @@
namespace Elsa.Api.Client.Resources.Alterations.Enums;
/// <summary>
/// The status of an alteration plan.
/// </summary>
public enum AlterationPlanStatus
{
/// <summary>
/// The plan is pending execution.
/// </summary>
Pending,
/// <summary>
/// The plan is currently generating jobs.
/// </summary>
Generating,
/// <summary>
/// The plan is currently dispatching jobs.
/// </summary>
Dispatching,
/// <summary>
/// The plan is currently being executed.
/// </summary>
Running,
/// <summary>
/// The plan has been completed.
/// </summary>
Completed,
/// <summary>
/// The plan has failed.
/// </summary>
Failed
}

View file

@ -0,0 +1,34 @@
using Elsa.Api.Client.Resources.Alterations.Enums;
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// A filter for activities within a workflow instance
/// </summary>
public class ActivityFilter
{
/// <summary>
/// The ID of the activity.
/// </summary>
public string? ActivityId { get; set; }
/// <summary>
/// The ID of the activity instance.
/// </summary>
public string? ActivityInstanceId { get; set; }
/// <summary>
/// The node ID of the activity.
/// </summary>
public string? NodeId { get; set; }
/// <summary>
/// The name of the activity.
/// </summary>
public string? Name { get; set; }
/// <summary>
/// The status of the activity.
/// </summary>
public ActivityStatus? Status { get; set; }
}

View file

@ -0,0 +1,8 @@
using Elsa.Api.Client.Resources.Alterations.Contracts;
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// A base class for all IAlterations.
/// </summary>
public abstract class AlterationBase : IAlteration;

View file

@ -0,0 +1,45 @@
using Elsa.Api.Client.Resources.Alterations.Enums;
using Elsa.Api.Client.Shared.Models;
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// Represents the execution of the plan for an individual workflow instance.
/// </summary>
public class AlterationJob : Entity
{
/// <summary>
/// The ID of the plan that this job belongs to.
/// </summary>
public string PlanId { get; set; } = default!;
/// <summary>
/// The ID of the workflow instance that this job applies to.
/// </summary>
public string WorkflowInstanceId { get; set; } = default!;
/// <summary>
/// The status of the job.
/// </summary>
public AlterationJobStatus Status { get; set; }
/// <summary>
/// The serialized log of the job.
/// </summary>
public ICollection<AlterationLogEntry>? Log { get; set; } = new List<AlterationLogEntry>();
/// <summary>
/// The date and time at which the job was created.
/// </summary>
public DateTimeOffset CreatedAt { get; set; }
/// <summary>
/// The date and time at which the job was started.
/// </summary>
public DateTimeOffset? StartedAt { get; set; }
/// <summary>
/// The date and time at which the job was completed.
/// </summary>
public DateTimeOffset? CompletedAt { get; set; }
}

View file

@ -0,0 +1,13 @@
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// Represents a log of alterations.
/// </summary>
public class AlterationLog
{
/// <summary>
/// The log entries.
/// </summary>
public ICollection<AlterationLogEntry> LogEntries { get; set; } = new List<AlterationLogEntry>();
}

View file

@ -0,0 +1,12 @@
using Microsoft.Extensions.Logging;
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// An individual log entry about an alteration
/// </summary>
/// <param name="Message"></param>
/// <param name="LogLevel"></param>
/// <param name="Timestamp"></param>
/// <param name="EventName"></param>
public record AlterationLogEntry(string Message, LogLevel LogLevel, DateTimeOffset Timestamp, string? EventName = null);

View file

@ -0,0 +1,41 @@
using Elsa.Api.Client.Resources.Alterations.Contracts;
using Elsa.Api.Client.Resources.Alterations.Enums;
using Elsa.Api.Client.Shared.Models;
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// A plan that contains a list of alterations to be applied to a set of workflow instances.
/// </summary>
public class AlterationPlan : Entity
{
/// <summary>
/// The alterations to be applied.
/// </summary>
public ICollection<IAlteration> Alterations { get; set; } = new List<IAlteration>();
/// <summary>
/// The IDs of the workflow instances that this plan applies to.
/// </summary>
public AlterationWorkflowInstanceFilter WorkflowInstanceFilter { get; set; } = new();
/// <summary>
/// The status of the plan.
/// </summary>
public AlterationPlanStatus Status { get; set; }
/// <summary>
/// The date and time at which the plan was created.
/// </summary>
public DateTimeOffset CreatedAt { get; set; }
/// <summary>
/// The date and time at which the plan was started.
/// </summary>
public DateTimeOffset? StartedAt { get; set; }
/// <summary>
/// The date and time at which the plan was completed.
/// </summary>
public DateTimeOffset? CompletedAt { get; set; }
}

View file

@ -0,0 +1,24 @@
using Elsa.Api.Client.Resources.Alterations.Contracts;
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// Represents the execution of an alteration plan against a set of workflow instances defined by the given filter
/// </summary>
public class AlterationPlanParams
{
/// <summary>
/// The unique identifier for the alteration plan. If not specified, a new ID will be generated.
/// </summary>
public string? Id { get; set; }
/// <summary>
/// The alterations to be applied.
/// </summary>
public ICollection<IAlteration> Alterations { get; set; } = new List<IAlteration>();
/// <summary>
/// The IDs of the workflow instances that this plan applies to.
/// </summary>
public AlterationWorkflowInstanceFilter Filter { get; set; } = new();
}

View file

@ -0,0 +1,45 @@
using Elsa.Api.Client.Shared.Models;
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// Represents a filter for workflow instances.
/// </summary>
public class AlterationWorkflowInstanceFilter
{
/// <summary>
/// The IDs of the workflow instances that this plan applies to.
/// </summary>
public IEnumerable<string>? WorkflowInstanceIds { get; set; }
/// <summary>
/// The correlation IDs of the workflow instances that this plan applies to.
/// </summary>
public IEnumerable<string>? CorrelationIds { get; set; }
/// <summary>
/// A collection of timestamp filters used for filtering data based on specified timestamp columns and operators.
/// </summary>
public IEnumerable<TimestampFilter>? TimestampFilters { get; set; }
/// <summary>
/// The IDs of the workflow definitions that this plan applies to.
/// </summary>
public IEnumerable<string>? DefinitionVersionIds { get; set; }
/// <summary>
/// Whether the workflow instances to match have incidents.
/// </summary>
public bool? HasIncidents { get; set; }
/// <summary>
/// Whether the workflow instances to match are system workflows. Defaults to <c>false</c>.
/// </summary>
public bool? IsSystem { get; set; } = false;
/// <summary>
/// Represents a collection of filters for activities.
/// </summary>
public IEnumerable<ActivityFilter>? ActivityFilters { get; set; }
}

View file

@ -0,0 +1,17 @@
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// Cancels a workflow instance activity during an alteration
/// </summary>
public class CancelActivity : AlterationBase
{
/// <summary>
/// The ID of the activity to be cancelled. If not specified, the activity instance ID will be used.
/// </summary>
public string? ActivityId { get; set; }
/// <summary>
/// The ID of the activity instance to be cancelled. If specified, overrides <see cref="ActivityId"/>.
/// </summary>
public string? ActivityInstanceId { get; set; }
}

View file

@ -0,0 +1,12 @@
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// Migrates a workflow instance to a newer version in an alteration.
/// </summary>
public class Migrate : AlterationBase
{
/// <summary>
/// The target version to upgrade to.
/// </summary>
public int TargetVersion { get; set; }
}

View file

@ -0,0 +1,18 @@
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// Modifies a variable in a workflow instance alteration
/// </summary>
public class ModifyVariable : AlterationBase
{
/// <summary>
/// The ID of the variable to modify.
/// </summary>
public string VariableId { get; set; } = default!;
/// <summary>
/// The new value of the variable.
/// </summary>
public object? Value { get; set; }
}

View file

@ -0,0 +1,27 @@
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// The result of running a series of alterations.
/// </summary>
public class RunAlterationsResult
{
/// <summary>
/// The ID of the workflow instance that was altered.
/// </summary>
public string WorkflowInstanceId { get; set; } = string.Empty;
/// <summary>
/// A log of the alterations that were run.
/// </summary>
public AlterationLog Log { get; set; } = new();
/// <summary>
/// A flag indicating whether the workflow has scheduled work.
/// </summary>
public bool WorkflowHasScheduledWork { get; set; }
/// <summary>
/// A flag indicating whether the alterations have succeeded.
/// </summary>
public bool IsSuccessful { get; set; }
}

View file

@ -0,0 +1,17 @@
namespace Elsa.Api.Client.Resources.Alterations.Models;
/// <summary>
/// Schedules an activity for execution in an alteration.
/// </summary>
public class ScheduleActivity : AlterationBase
{
/// <summary>
/// The ID of the next activity to be scheduled. If not specified, the ActivityInstanceId will be used.
/// </summary>
public string? ActivityId { get; set; }
/// <summary>
/// The ID of the activity instance to be scheduled. If not specified, the ActivityId will be used.
/// </summary>
public string? ActivityInstanceId { get; set; }
}

View file

@ -0,0 +1,17 @@
namespace Elsa.Api.Client.Resources.Alterations.Requests;
/// <summary>
/// Represents a request to bulk retry workflow instances.
/// </summary>
public class BulkRetryRequest
{
/// <summary>
/// The IDs of the workflow instances that have incidents to be retried.
/// </summary>
public ICollection<string> WorkflowInstanceIds { get; set; } = new List<string>();
/// <summary>
/// An optional list of explicitly specified activity IDs to retry. If omitted, all faulted activities will be retried.
/// </summary>
public ICollection<string>? ActivityIds { get; set; }
}

View file

@ -0,0 +1,14 @@
using Elsa.Api.Client.Resources.Alterations.Models;
namespace Elsa.Api.Client.Resources.Alterations.Responses;
/// <summary>
/// Represents a response to bulk retry workflow instances.
/// </summary>
public class BulkRetryResponse
{
/// <summary>
/// The alterations that resulted from the bulk retry request
/// </summary>
public ICollection<RunAlterationsResult> Results { get;set; } = new List<RunAlterationsResult>();
}

View file

@ -0,0 +1,12 @@
namespace Elsa.Api.Client.Resources.Alterations.Responses;
/// <summary>
/// The response to the DryRun request
/// </summary>
public class DryRunResponse
{
/// <summary>
/// The list of workflow instance IDs that would be affected by a "Submit" request
/// </summary>
public ICollection<string> WorkflowInstanceIds { get; set; } = new List<string>();
}

View file

@ -0,0 +1,19 @@
using Elsa.Api.Client.Resources.Alterations.Models;
namespace Elsa.Api.Client.Resources.Alterations.Responses;
/// <summary>
/// The response from the "Get" alteration plan endpoint
/// </summary>
public class GetAlterationPlanResponse
{
/// <summary>
/// The alteration plan mathching the provided ID
/// </summary>
public AlterationPlan Plan { get; set; } = new();
/// <summary>
/// The list of jobs that exist for that AlterationPlan
/// </summary>
public ICollection<AlterationJob> Jobs { get; set; } = new List<AlterationJob>();
}

View file

@ -0,0 +1,19 @@
using Elsa.Api.Client.Resources.Alterations.Contracts;
namespace Elsa.Api.Client.Resources.Alterations.Responses;
/// <summary>
/// A plan that contains a list of alterations to be applied to a set of workflow instances.
/// </summary>
public class RunRequest
{
/// <summary>
/// The alterations to be applied.
/// </summary>
public ICollection<IAlteration> Alterations { get; set; } = new List<IAlteration>();
/// <summary>
/// The IDs of the workflow instances that this plan applies to.
/// </summary>
public ICollection<string> WorkflowInstanceIds { get; set; } = new List<string>();
}

View file

@ -0,0 +1,14 @@
using Elsa.Api.Client.Resources.Alterations.Models;
namespace Elsa.Api.Client.Resources.Alterations.Responses;
/// <summary>
/// The response to the Run endpoint
/// </summary>
public class RunResponse
{
/// <summary>
/// The alteration results of a Run request
/// </summary>
private ICollection<RunAlterationsResult> Results { get; set; } = new List<RunAlterationsResult>();
}

View file

@ -0,0 +1,12 @@
namespace Elsa.Api.Client.Resources.Alterations.Responses;
/// <summary>
/// The response to the "Submit" endpoint
/// </summary>
public class SubmitResponse
{
/// <summary>
/// The ID of the alteration plan created as part of the Submit request
/// </summary>
public string PlanId { get; set; } = string.Empty;
}

View file

@ -18,7 +18,7 @@ public class AlterationPlanParams
public ICollection<IAlteration> Alterations { get; set; } = new List<IAlteration>();
/// <summary>
/// The IDs of the workflow instances that this plan applies to.
/// The filter used to determine which workflow instances that this plan applies to.
/// </summary>
public AlterationWorkflowInstanceFilter Filter { get; set; } = new();
}

View file

@ -6,7 +6,7 @@ using JetBrains.Annotations;
namespace Elsa.Alterations.Endpoints.Alterations.DryRun;
/// <summary>
/// Executes an alteration plan.
/// Determines which workflow instances a "Submit" request would target without actually running an alteration.
/// </summary>
[PublicAPI]
public class DryRun(IWorkflowInstanceFinder workflowInstanceFinder) : ElsaEndpoint<AlterationWorkflowInstanceFilter, Response>

View file

@ -6,7 +6,7 @@ using JetBrains.Annotations;
namespace Elsa.Alterations.Endpoints.Alterations.Get;
/// <summary>
/// Executes an alteration plan.
/// Gets an alteration plan and its associated jobs.
/// </summary>
[PublicAPI]
public class Get : ElsaEndpointWithoutRequest<Response>

View file

@ -5,7 +5,7 @@ using JetBrains.Annotations;
namespace Elsa.Alterations.Endpoints.Alterations.Run;
/// <summary>
/// Executes an alteration plan.
/// Executes an alteration plan by targeting workflow instances by ID.
/// </summary>
[PublicAPI]
public class Run : ElsaEndpoint<Request, Response>

View file

@ -8,7 +8,7 @@ using JetBrains.Annotations;
namespace Elsa.Alterations.Endpoints.Alterations.Submit;
/// <summary>
/// Executes an alteration plan.
/// Submits an alteration plan to be executed targeting workflow instances by a filter.
/// </summary>
[PublicAPI]
public class Submit : ElsaEndpoint<AlterationPlanParams, Response>