Add project files.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Elsa.Api.Client.Extensions;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Api.Client.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Converts <see cref="Type"/> objects to and from their assembly-qualified name.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class TypeJsonConverter : JsonConverter<Type>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert)
|
||||
{
|
||||
return typeToConvert == typeof(Type) || typeToConvert.FullName == "System.RuntimeType";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Type? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var typeName = reader.GetString()!;
|
||||
|
||||
// Handle collection types.
|
||||
if (typeName.EndsWith("[]"))
|
||||
{
|
||||
var elementTypeName = typeName[..^"[]".Length];
|
||||
var elementType = Type.GetType(elementTypeName)!;
|
||||
return typeof(List<>).MakeGenericType(elementType);
|
||||
}
|
||||
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, Type value, JsonSerializerOptions options)
|
||||
{
|
||||
// Handle collection types.
|
||||
if (value is { IsGenericType: true, GenericTypeArguments.Length: 1 })
|
||||
{
|
||||
var elementType = value.GenericTypeArguments.First();
|
||||
var typedEnumerable = typeof(IEnumerable<>).MakeGenericType(elementType);
|
||||
|
||||
if (typedEnumerable.IsAssignableFrom(value))
|
||||
{
|
||||
var elementTypeName = value.GetSimpleAssemblyQualifiedName();
|
||||
JsonSerializer.Serialize(writer, $"{elementTypeName}[]", options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var typeName = value.GetSimpleAssemblyQualifiedName();
|
||||
JsonSerializer.Serialize(writer, typeName, options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// A JSON converter that serializes <see cref="VersionOptions"/>.
|
||||
/// </summary>
|
||||
public class VersionOptionsJsonConverter : JsonConverter<VersionOptions>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override VersionOptions Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var textValue = reader.GetString();
|
||||
return string.IsNullOrWhiteSpace(textValue) ? VersionOptions.Published : VersionOptions.FromString(textValue);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, VersionOptions value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// A type converter that converts <see cref="VersionOptions"/> to and from strings.
|
||||
/// </summary>
|
||||
public class VersionOptionsTypeConverter : TypeConverter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) => sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) => value is string text ? VersionOptions.FromString(text) : base.ConvertFrom(context, culture, value)!;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>
|
||||
Provides HTTP clients for the Elsa Workflows REST API.
|
||||
</Description>
|
||||
<PackageTags>elsa api client</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Polly" />
|
||||
<PackageReference Include="Polly" />
|
||||
<PackageReference Include="Polly.Extensions.Http" />
|
||||
<PackageReference Include="Refit" />
|
||||
<PackageReference Include="Refit.HttpClientFactory" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<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/=helpers/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=resources_005Clogpersistencestrategies_005Ccontracts/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=resources_005Clogpersistencestrategies_005Cmodels/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -0,0 +1,216 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using Elsa.Api.Client.Resources.Resilience.Models;
|
||||
using Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="JsonObject"/>.
|
||||
/// </summary>
|
||||
public static class ActivityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type name of the specified activity.
|
||||
/// </summary>
|
||||
public static string GetTypeName(this JsonObject activity) => activity.GetProperty<string>("type")!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type name of the specified activity.
|
||||
/// </summary>
|
||||
public static void SetTypeName(this JsonObject activity, string value) => activity.SetProperty(JsonValue.Create(value), "type");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version of the specified activity.
|
||||
/// </summary>
|
||||
public static int GetVersion(this JsonObject activity) => activity.GetProperty<int>("version");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version of the specified activity.
|
||||
/// </summary>
|
||||
public static void SetVersion(this JsonObject activity, int value) => activity.SetProperty(JsonValue.Create(value), "version");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ID of the specified activity.
|
||||
/// </summary>
|
||||
public static string GetId(this JsonObject activity) => activity.GetProperty<string>("id")!;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ID of the specified activity.
|
||||
/// </summary>
|
||||
public static void SetId(this JsonObject activity, string value) => activity.SetProperty(JsonValue.Create(value), "id");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the node ID of the specified activity.
|
||||
/// </summary>
|
||||
public static string GetNodeId(this JsonObject activity) => activity.GetProperty<string>("nodeId")!;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the node ID of the specified activity.
|
||||
/// </summary>
|
||||
public static void SetNodeId(this JsonObject activity, string value) => activity.SetProperty(JsonValue.Create(value), "nodeId");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the specified activity.
|
||||
/// </summary>
|
||||
public static string? GetName(this JsonObject activity) => activity.GetProperty<string>("name");
|
||||
|
||||
/// <summary>
|
||||
/// Sets the name of the specified activity.
|
||||
/// </summary>
|
||||
public static void SetName(this JsonObject activity, string? value) => activity.SetProperty(JsonValue.Create(value), "name");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the designer metadata for the specified activity.
|
||||
/// </summary>
|
||||
public static JsonObject? GetMetadata(this JsonObject activity) => activity.GetProperty("metadata")?.AsObject();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the designer metadata for the specified activity.
|
||||
/// </summary>
|
||||
public static void SetDesignerMetadata(this JsonObject activity, ActivityDesignerMetadata designerMetadata) => activity.SetProperty(designerMetadata.SerializeToNode(), "metadata", "designer");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the designer metadata for the specified activity.
|
||||
/// </summary>
|
||||
public static ActivityDesignerMetadata GetDesignerMetadata(this JsonObject activity) => activity.GetProperty<ActivityDesignerMetadata>("metadata", "designer") ?? new ActivityDesignerMetadata();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display text for the specified activity.
|
||||
/// </summary>
|
||||
public static string? GetDisplayText(this JsonObject activity) => activity.GetProperty("metadata", "displayText")?.GetValue<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the display text for the specified activity.
|
||||
/// </summary>
|
||||
public static void SetDisplayText(this JsonObject activity, string? value)
|
||||
{
|
||||
activity.SetProperty(JsonValue.Create(value), "metadata", "displayText");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description for the specified activity.
|
||||
/// </summary>
|
||||
public static string? GetDescription(this JsonObject activity) => activity.GetProperty("metadata", "description")?.GetValue<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the description for the specified activity.
|
||||
/// </summary>
|
||||
public static void SetDescription(this JsonObject activity, string value) => activity.SetProperty(JsonValue.Create(value), "metadata", "description");
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the description for the specified activity should be shown.
|
||||
/// </summary>
|
||||
public static bool? GetShowDescription(this JsonObject activity) => activity.GetProperty<bool>("metadata", "showDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value indicating whether the description for the specified activity should be shown.
|
||||
/// </summary>
|
||||
public static void SetShowDescription(this JsonObject activity, bool value) => activity.SetProperty(JsonValue.Create(value), "metadata", "showDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the specified activity can trigger the workflow.
|
||||
/// </summary>
|
||||
public static bool? GetCanStartWorkflow(this JsonObject activity) => activity.GetProperty<bool>("customProperties", "canStartWorkflow");
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value indicating whether the specified activity can trigger the workflow.
|
||||
/// </summary>
|
||||
public static void SetCanStartWorkflow(this JsonObject activity, bool value) => activity.SetProperty(JsonValue.Create(value), "customProperties", "canStartWorkflow");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the activities in the specified flowchart.
|
||||
/// </summary>
|
||||
public static IEnumerable<JsonObject> GetActivities(this JsonObject flowchart) => flowchart.GetProperty("activities")?.AsArray().AsEnumerable().Cast<JsonObject>() ?? Array.Empty<JsonObject>();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the activities in the specified flowchart.
|
||||
/// </summary>
|
||||
public static void SetActivities(this JsonObject flowchart, JsonArray activities) => flowchart.SetProperty(activities, "activities");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the connections in the specified flowchart.
|
||||
/// </summary>
|
||||
public static IEnumerable<Connection> GetConnections(this JsonObject flowchart) => flowchart.GetProperty<ICollection<Connection>>("connections") ?? new List<Connection>();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the connections in the specified flowchart.
|
||||
/// </summary>
|
||||
public static void SetConnections(this JsonObject flowchart, IEnumerable<Connection> connections) => flowchart.SetProperty(JsonValue.Create(connections), "connections");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the root activity in the specified activity.
|
||||
/// </summary>
|
||||
public static JsonObject? GetRoot(this JsonObject activity) => activity.GetProperty("root") as JsonObject;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the root activity in the specified activity.
|
||||
/// </summary>
|
||||
public static void SetRoot(this JsonObject container, JsonObject root) => container.SetProperty(root, "root");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the root activity in the specified activity.
|
||||
/// </summary>
|
||||
public static string? GetWorkflowDefinitionId(this JsonObject activity)
|
||||
{
|
||||
// Determine if this activity represents a workflow definition activity based on the presence of the following properties.
|
||||
var workflowDefinitionIdNode = activity.GetProperty("workflowDefinitionId");
|
||||
var workflowDefinitionVersionId = activity.GetProperty("workflowDefinitionVersionId");
|
||||
var latestAvailablePublishedVersion = activity.GetProperty("latestAvailablePublishedVersion");
|
||||
var latestAvailablePublishedVersionId = activity.GetProperty("latestAvailablePublishedVersionId");
|
||||
|
||||
if (workflowDefinitionIdNode == null || workflowDefinitionVersionId == null || latestAvailablePublishedVersion == null || latestAvailablePublishedVersionId == null)
|
||||
return null; // Not a workflow definition activity.
|
||||
|
||||
if (workflowDefinitionIdNode is JsonValue value)
|
||||
return value.ToString();
|
||||
|
||||
return null; // Not a workflow definition activity.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the given activity is a workflow definition activity.
|
||||
/// </summary>
|
||||
/// <param name="activity">The JsonObject representing the activity.</param>
|
||||
/// <returns>Returns true if the activity is a workflow definition activity; otherwise, false.</returns>
|
||||
public static bool GetIsWorkflowDefinitionActivity(this JsonObject activity) => activity.ContainsKey("workflowDefinitionId") && activity.ContainsKey("workflowDefinitionVersionId");
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the specified activity can trigger the workflow.
|
||||
/// </summary>
|
||||
public static bool? GetRunAsynchronously(this JsonObject activity) => activity.GetProperty<bool>("customProperties", "runAsynchronously");
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value indicating whether the specified activity can trigger the workflow.
|
||||
/// </summary>
|
||||
public static void SetRunAsynchronously(this JsonObject activity, bool value) => activity.SetProperty(JsonValue.Create(value), "customProperties", "runAsynchronously");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the commit state behavior for the specified activity.
|
||||
/// </summary>
|
||||
public static string? GetCommitStrategy(this JsonObject activity) => activity.TryGetProperty<string?>("customProperties", "commitStrategyName");
|
||||
|
||||
/// <summary>
|
||||
/// Sets the commit state behavior for the specified activity.
|
||||
/// </summary>
|
||||
public static void SetCommitStrategy(this JsonObject activity, string? name) => activity.SetProperty(JsonValue.Create(name), "customProperties", "commitStrategyName");
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the resilience strategy for the specified activity.
|
||||
/// </summary>
|
||||
public static ResilienceStrategyConfig? GetResilienceStrategy(this JsonObject activity)
|
||||
{
|
||||
var node = activity.GetProperty("customProperties", "resilienceStrategy");
|
||||
return ResilienceStrategyConfig.Deserialize(node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the resilience strategy for the specified activity.
|
||||
/// </summary>
|
||||
public static void SetResilienceStrategy(this JsonObject activity, ResilienceStrategyConfig? config)
|
||||
{
|
||||
var node = config?.SerializeToNode();
|
||||
activity.SetProperty(node, "customProperties", "resilienceStrategy");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="IApiResponse"/>.
|
||||
/// </summary>
|
||||
public static class ApiResponseExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the downloaded file name or the specified default file name.
|
||||
/// </summary>
|
||||
public static string GetDownloadedFileNameOrDefault(this IApiResponse response, string defaultFileName = "download.bin")
|
||||
{
|
||||
var fileName = defaultFileName;
|
||||
|
||||
if (response.Headers.TryGetValues("content-disposition", out var contentDispositionHeader)) // Only available if the Elsa Server exposes the "Content-Disposition" header.
|
||||
{
|
||||
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
|
||||
var values = contentDispositionHeader.ToList() ?? [];
|
||||
|
||||
if (values.Count >= 2)
|
||||
fileName = values[1].Split('=')[1];
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
using Elsa.Api.Client.Options;
|
||||
using Elsa.Api.Client.Resources.ActivityDescriptorOptions.Contracts;
|
||||
using Elsa.Api.Client.Resources.ActivityDescriptors.Contracts;
|
||||
using Elsa.Api.Client.Resources.ActivityExecutions.Contracts;
|
||||
using Elsa.Api.Client.Resources.Alterations.Contracts;
|
||||
using Elsa.Api.Client.Resources.CommitStrategies.Contracts;
|
||||
using Elsa.Api.Client.Resources.Features.Contracts;
|
||||
using Elsa.Api.Client.Resources.Identity.Contracts;
|
||||
using Elsa.Api.Client.Resources.IncidentStrategies.Contracts;
|
||||
using Elsa.Api.Client.Resources.LogPersistenceStrategies;
|
||||
using Elsa.Api.Client.Resources.Resilience.Contracts;
|
||||
using Elsa.Api.Client.Resources.Scripting.Contracts;
|
||||
using Elsa.Api.Client.Resources.StorageDrivers.Contracts;
|
||||
using Elsa.Api.Client.Resources.Tasks.Contracts;
|
||||
using Elsa.Api.Client.Resources.VariableTypes.Contracts;
|
||||
using Elsa.Api.Client.Resources.WorkflowActivationStrategies.Contracts;
|
||||
using Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts;
|
||||
using Elsa.Api.Client.Resources.WorkflowExecutionContexts.Contracts;
|
||||
using Elsa.Api.Client.Resources.WorkflowInstances.Contracts;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Refit;
|
||||
using static Elsa.Api.Client.RefitSettingsHelper;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for dependency injection.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static class DependencyInjectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds default Elsa API clients configured to use an API key.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddDefaultApiClientsUsingApiKey(this IServiceCollection services, Action<ElsaClientOptions> configureOptions)
|
||||
{
|
||||
var options = new ElsaClientOptions();
|
||||
configureOptions(options);
|
||||
|
||||
return services.AddDefaultApiClients(client =>
|
||||
{
|
||||
client.BaseAddress = options.BaseAddress;
|
||||
client.ApiKey = options.ApiKey;
|
||||
client.ConfigureHttpClient = options.ConfigureHttpClient;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds default Elsa API clients.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddDefaultApiClients(this IServiceCollection services, Action<ElsaClientBuilderOptions>? configureClient = null)
|
||||
{
|
||||
return services.AddApiClients(configureClient, builderOptions =>
|
||||
{
|
||||
var builderOptionsWithoutRetryPolicy = new ElsaClientBuilderOptions
|
||||
{
|
||||
ApiKey = builderOptions.ApiKey,
|
||||
AuthenticationHandler = builderOptions.AuthenticationHandler,
|
||||
BaseAddress = builderOptions.BaseAddress,
|
||||
ConfigureHttpClient = builderOptions.ConfigureHttpClient,
|
||||
ConfigureHttpClientBuilder = builderOptions.ConfigureHttpClientBuilder,
|
||||
ConfigureRetryPolicy = null
|
||||
};
|
||||
|
||||
services.AddApi<IWorkflowDefinitionsApi>(builderOptions);
|
||||
services.AddApi<IExecuteWorkflowApi>(builderOptionsWithoutRetryPolicy);
|
||||
services.AddApi<IWorkflowInstancesApi>(builderOptions);
|
||||
services.AddApi<IActivityDescriptorsApi>(builderOptions);
|
||||
services.AddApi<IActivityDescriptorOptionsApi>(builderOptions);
|
||||
services.AddApi<IActivityExecutionsApi>(builderOptions);
|
||||
services.AddApi<IStorageDriversApi>(builderOptions);
|
||||
services.AddApi<IVariableTypesApi>(builderOptions);
|
||||
services.AddApi<IWorkflowActivationStrategiesApi>(builderOptions);
|
||||
services.AddApi<IIncidentStrategiesApi>(builderOptions);
|
||||
services.AddApi<ILogPersistenceStrategiesApi>(builderOptions);
|
||||
services.AddApi<ICommitStrategiesApi>(builderOptions);
|
||||
services.AddApi<IResilienceStrategiesApi>(builderOptions);
|
||||
services.AddApi<IRetryAttemptsApi>(builderOptions);
|
||||
services.AddApi<ILoginApi>(builderOptions);
|
||||
services.AddApi<IFeaturesApi>(builderOptions);
|
||||
services.AddApi<IJavaScriptApi>(builderOptions);
|
||||
services.AddApi<IExpressionDescriptorsApi>(builderOptions);
|
||||
services.AddApi<IWorkflowContextProviderDescriptorsApi>(builderOptions);
|
||||
services.AddApi<IAlterationsApi>(builderOptions);
|
||||
services.AddApi<ITasksApi>(builderOptions);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an API client to the service collection. Requires AddElsaClient to be called exactly once.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddApiClient<T>(this IServiceCollection services, Action<ElsaClientBuilderOptions>? configureClient = null) where T : class
|
||||
{
|
||||
return services.AddApiClients(configureClient, builderOptions => services.AddApi<T>(builderOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the Elsa client to the service collection.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddApiClients(this IServiceCollection services, Action<ElsaClientBuilderOptions>? configureClient = null, Action<ElsaClientBuilderOptions>? configureServices = null)
|
||||
{
|
||||
var builderOptions = new ElsaClientBuilderOptions();
|
||||
configureClient?.Invoke(builderOptions);
|
||||
builderOptions.ConfigureHttpClientBuilder += builder => builder.AddHttpMessageHandler(sp => (DelegatingHandler)sp.GetRequiredService(builderOptions.AuthenticationHandler));
|
||||
|
||||
services.TryAddScoped(builderOptions.AuthenticationHandler);
|
||||
|
||||
services.Configure<ElsaClientOptions>(options =>
|
||||
{
|
||||
options.BaseAddress = builderOptions.BaseAddress;
|
||||
options.ConfigureHttpClient = builderOptions.ConfigureHttpClient;
|
||||
options.ApiKey = builderOptions.ApiKey;
|
||||
});
|
||||
|
||||
configureServices?.Invoke(builderOptions);
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a refit client for the specified API type.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection.</param>
|
||||
/// <param name="httpClientBuilderOptions">An options object that can be used to configure the HTTP client builder.</param>
|
||||
/// <typeparam name="T">The type representing the API.</typeparam>
|
||||
public static IServiceCollection AddApi<T>(this IServiceCollection services, ElsaClientBuilderOptions? httpClientBuilderOptions = default) where T : class
|
||||
{
|
||||
return services.AddApi(typeof(T), httpClientBuilderOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a refit client for the specified API type.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection.</param>
|
||||
/// <param name="apiType">The type representing the API</param>
|
||||
/// <param name="httpClientBuilderOptions">An options object that can be used to configure the HTTP client builder.</param>
|
||||
public static IServiceCollection AddApi(this IServiceCollection services, Type apiType, ElsaClientBuilderOptions? httpClientBuilderOptions = default)
|
||||
{
|
||||
var builder = services.AddRefitClient(apiType, sp => CreateRefitSettings(sp, httpClientBuilderOptions?.ConfigureJsonSerializerOptions), apiType.Name).ConfigureHttpClient(ConfigureElsaApiHttpClient);
|
||||
httpClientBuilderOptions?.ConfigureHttpClientBuilder(builder);
|
||||
httpClientBuilderOptions?.ConfigureRetryPolicy?.Invoke(builder);
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a refit client for the specified API type.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection.</param>
|
||||
/// <param name="httpClientBuilderOptions">An options object that can be used to configure the HTTP client builder.</param>
|
||||
/// <typeparam name="T">The type representing the API.</typeparam>
|
||||
public static void AddApiWithoutRetryPolicy<T>(this IServiceCollection services, ElsaClientBuilderOptions? httpClientBuilderOptions = default) where T : class
|
||||
{
|
||||
var builder = services
|
||||
.AddRefitClient<T>(sp => CreateRefitSettings(sp), typeof(T).Name)
|
||||
.ConfigureHttpClient(ConfigureElsaApiHttpClient);
|
||||
httpClientBuilderOptions?.ConfigureHttpClientBuilder(builder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an API client for the specified API type.
|
||||
/// </summary>
|
||||
public static T CreateApi<T>(this IServiceProvider serviceProvider, Uri baseAddress) where T : class
|
||||
{
|
||||
var httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
|
||||
var httpClient = httpClientFactory.CreateClient(typeof(T).Name);
|
||||
httpClient.BaseAddress = baseAddress;
|
||||
return CreateApi<T>(serviceProvider, httpClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an API client for the specified API type.
|
||||
/// </summary>
|
||||
public static T CreateApi<T>(this IServiceProvider serviceProvider, HttpClient httpClient) where T : class
|
||||
{
|
||||
return RestService.For<T>(httpClient, CreateRefitSettings(serviceProvider));
|
||||
}
|
||||
|
||||
private static void ConfigureElsaApiHttpClient(IServiceProvider serviceProvider, HttpClient httpClient)
|
||||
{
|
||||
var options = serviceProvider.GetRequiredService<IOptions<ElsaClientOptions>>().Value;
|
||||
httpClient.BaseAddress = options.BaseAddress;
|
||||
options.ConfigureHttpClient?.Invoke(serviceProvider, httpClient);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="JsonElement"/>.
|
||||
/// </summary>
|
||||
public static class DictionaryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the value of the specified property if it exists, otherwise the default value.
|
||||
/// </summary>
|
||||
public static T TryGetValue<T>(this IDictionary<string, object> dictionary, string key, Func<T>? defaultValue = default, JsonSerializerOptions? serializerOptions = default)
|
||||
{
|
||||
var caseInsensitiveDictionary = ToCaseInsensitiveDictionary(dictionary);
|
||||
|
||||
if (caseInsensitiveDictionary.TryGetValue(key, out var value) && value is not JsonElement { ValueKind: JsonValueKind.Undefined })
|
||||
{
|
||||
var convertedValue = value.ConvertTo<T>(new ObjectConverterOptions(serializerOptions));
|
||||
|
||||
if (convertedValue != null)
|
||||
return convertedValue;
|
||||
}
|
||||
|
||||
if (defaultValue == null)
|
||||
return default!;
|
||||
|
||||
var defaultVal = defaultValue()!;
|
||||
dictionary[key] = defaultVal;
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the specified property if it exists, otherwise the default value.
|
||||
/// </summary>
|
||||
public static object? TryGetValue(this IDictionary<string, object> dictionary, string key, Func<object>? defaultValue = default)
|
||||
{
|
||||
var caseInsensitiveDictionary = ToCaseInsensitiveDictionary(dictionary);
|
||||
|
||||
if (caseInsensitiveDictionary.TryGetValue(key, out var value) && value is not JsonElement { ValueKind: JsonValueKind.Undefined })
|
||||
return value;
|
||||
|
||||
if (defaultValue == null)
|
||||
return default;
|
||||
|
||||
var defaultVal = defaultValue()!;
|
||||
dictionary[key] = defaultVal;
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
// A method that de-duplicates the keys in the dictionary, taking into account that there may already be multiple keys that would be considered the same if the case was ignored.
|
||||
private static Dictionary<string, object> ToCaseInsensitiveDictionary(this IDictionary<string, object> dictionary)
|
||||
{
|
||||
var caseInsensitiveDictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var key in dictionary.Keys)
|
||||
{
|
||||
if (caseInsensitiveDictionary.ContainsKey(key))
|
||||
continue;
|
||||
|
||||
caseInsensitiveDictionary[key] = dictionary[key]!;
|
||||
}
|
||||
|
||||
return caseInsensitiveDictionary;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Elsa.Api.Client.Shared;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Contains extension methods for the <see cref="HttpResponseMessage"/> class.
|
||||
/// </summary>
|
||||
public static class HttpResponseMessageExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the workflow instance ID from the response.
|
||||
/// </summary>
|
||||
public static string? GetWorkflowInstanceId(this HttpResponseMessage response) => response.Headers.TryGetValues(HeaderNames.WorkflowInstanceId, out var values) ? values.FirstOrDefault() : default;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="JsonElement"/>.
|
||||
/// </summary>
|
||||
public static class JsonElementExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the value of the specified property if it exists, otherwise the default value.
|
||||
/// </summary>
|
||||
public static bool TryGetPropertySafe(this JsonElement element, string propertyName, out JsonElement value)
|
||||
{
|
||||
value = default;
|
||||
|
||||
if(element.ValueKind != JsonValueKind.Object)
|
||||
return false;
|
||||
|
||||
if (!element.TryGetProperty(propertyName, out var property))
|
||||
return false;
|
||||
|
||||
value = property;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="JsonObject"/>.
|
||||
/// </summary>
|
||||
public static class JsonObjectExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if the specified <see cref="JsonObject"/> represents an activity.
|
||||
/// </summary>
|
||||
public static bool IsActivity(this JsonObject obj)
|
||||
{
|
||||
return obj.ContainsKey("type") && obj.ContainsKey("id") && obj.ContainsKey("version");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified value to a <see cref="JsonObject"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to serialize.</param>
|
||||
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
|
||||
/// <returns>A <see cref="JsonObject"/> representing the specified value.</returns>
|
||||
public static JsonNode SerializeToNode(this object value, JsonSerializerOptions? options = null)
|
||||
{
|
||||
options ??= new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
|
||||
|
||||
return JsonSerializer.SerializeToNode(value, options)!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified value to a <see cref="JsonArray"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to serialize.</param>
|
||||
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
|
||||
/// <returns>A <see cref="JsonObject"/> representing the specified value.</returns>
|
||||
public static JsonArray SerializeToArray(this object value, JsonSerializerOptions? options = null)
|
||||
{
|
||||
options ??= new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
|
||||
|
||||
return JsonSerializer.SerializeToNode(value, options)!.AsArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified value to a <see cref="JsonArray"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to serialize.</param>
|
||||
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
|
||||
/// <returns>A <see cref="JsonObject"/> representing the specified value.</returns>
|
||||
public static JsonArray SerializeToArray<T>(this IEnumerable<T> value, JsonSerializerOptions? options = null)
|
||||
{
|
||||
options ??= new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
|
||||
|
||||
return JsonSerializer.SerializeToNode(value, options)!.AsArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified <see cref="JsonNode"/> to the specified type.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="JsonNode"/> to deserialize.</param>
|
||||
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
|
||||
/// <typeparam name="T">The type to deserialize to.</typeparam>
|
||||
/// <returns>The deserialized value.</returns>
|
||||
public static T Deserialize<T>(this JsonNode value, JsonSerializerOptions? options = null)
|
||||
{
|
||||
options ??= new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
|
||||
|
||||
if (value is JsonObject jsonObject)
|
||||
return JsonSerializer.Deserialize<T>(jsonObject, options)!;
|
||||
|
||||
if (value is JsonArray jsonArray)
|
||||
return JsonSerializer.Deserialize<T>(jsonArray, options)!;
|
||||
|
||||
if (typeof(T).IsEnum || (Nullable.GetUnderlyingType(typeof(T))?.IsEnum ?? false))
|
||||
{
|
||||
if (value.GetValueKind() == JsonValueKind.Null)
|
||||
return default!;
|
||||
return (T)Enum.Parse(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T), value.ToString());
|
||||
}
|
||||
|
||||
if (value is JsonValue jsonValue)
|
||||
return jsonValue.GetValue<T>();
|
||||
|
||||
throw new NotSupportedException($"Cannot deserialize {value.GetType()} to {typeof(T)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the property value of the specified model.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to set the property value on.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
/// <param name="path">The path to the property.</param>
|
||||
public static void SetProperty(this JsonObject model, JsonNode? value, params string[] path)
|
||||
{
|
||||
model = GetPropertyContainer(model, path);
|
||||
model[path.Last()] = value?.SerializeToNode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the property value of the specified model.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to set the property value on.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
/// <param name="path">The path to the property.</param>
|
||||
public static void SetProperty(this JsonObject model, JsonArray? value, params string[] path)
|
||||
{
|
||||
model = GetPropertyContainer(model, path);
|
||||
model[path.Last()] = value?.SerializeToNode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the property value of the specified model.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to set the property value on.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
/// <param name="path">The path to the property.</param>
|
||||
public static void SetProperty(this JsonObject model, IEnumerable<JsonNode> value, params string[] path)
|
||||
{
|
||||
model = GetPropertyContainer(model, path);
|
||||
model[path.Last()] = new JsonArray(value.Select(x => x.SerializeToNode()).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property value of the specified model.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to get the property value from.</param>
|
||||
/// <param name="path">The path to the property.</param>
|
||||
/// <returns>The property value.</returns>
|
||||
public static JsonNode? GetProperty(this JsonObject model, params string[] path)
|
||||
{
|
||||
var currentModel = model;
|
||||
|
||||
foreach (var prop in path.SkipLast(1))
|
||||
{
|
||||
if (currentModel[prop] is not JsonObject value)
|
||||
return null;
|
||||
|
||||
currentModel = value;
|
||||
}
|
||||
|
||||
return currentModel[path.Last()];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property value of the specified model.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to get the property value from.</param>
|
||||
/// <param name="path">The path to the property.</param>
|
||||
/// <typeparam name="T">The type to deserialize to.</typeparam>
|
||||
/// <returns>The property value.</returns>
|
||||
public static T? TryGetProperty<T>(this JsonObject model, params string[] path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return model.GetProperty<T>(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property value of the specified model.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to get the property value from.</param>
|
||||
/// <param name="path">The path to the property.</param>
|
||||
/// <typeparam name="T">The type to deserialize to.</typeparam>
|
||||
/// <returns>The property value.</returns>
|
||||
public static T? GetProperty<T>(this JsonObject model, params string[] path)
|
||||
{
|
||||
var property = GetProperty(model, path);
|
||||
return property != null ? property.Deserialize<T>() : default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property value of the specified model.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to get the property value from.</param>
|
||||
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use when deserializing.</param>
|
||||
/// <param name="path">The path to the property.</param>
|
||||
/// <typeparam name="T">The type to deserialize to.</typeparam>
|
||||
/// <returns>The property value.</returns>
|
||||
public static T? GetProperty<T>(this JsonObject model, JsonSerializerOptions options, params string[] path)
|
||||
{
|
||||
var property = GetProperty(model, path);
|
||||
return property != null ? property.Deserialize<T>(options) : default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the property container of the specified model.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to set the property value on.</param>
|
||||
/// <param name="path">The path to the property.</param>
|
||||
private static JsonObject GetPropertyContainer(this JsonObject model, params string[] path)
|
||||
{
|
||||
foreach (var prop in path.SkipLast(1))
|
||||
{
|
||||
var property = model[prop] as JsonObject ?? new JsonObject();
|
||||
model[prop] = property;
|
||||
model = property;
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Dynamic;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides options to the conversion method.
|
||||
/// </summary>
|
||||
public record ObjectConverterOptions(JsonSerializerOptions? SerializerOptions = default)
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ObjectConverterOptions(Action<JsonSerializerOptions> configureSerializerOptions) : this()
|
||||
{
|
||||
SerializerOptions = new JsonSerializerOptions();
|
||||
configureSerializerOptions(SerializerOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A helper that attempts many strategies to try and convert the source value into the destination type.
|
||||
/// </summary>
|
||||
public static class ObjectConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to convert the source value into the destination type.
|
||||
/// </summary>
|
||||
public static T? ConvertTo<T>(this object? value, ObjectConverterOptions? serializerOptions = null) => value != null ? (T?)value.ConvertTo(typeof(T), serializerOptions) : default;
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to convert the source value into the destination type.
|
||||
/// </summary>
|
||||
public static object? ConvertTo(this object? value, Type targetType, ObjectConverterOptions? converterOptions = null)
|
||||
{
|
||||
if (value == null)
|
||||
return default!;
|
||||
|
||||
var sourceType = value.GetType();
|
||||
|
||||
if (sourceType == targetType)
|
||||
return value;
|
||||
|
||||
var options = converterOptions?.SerializerOptions != null ? new JsonSerializerOptions(converterOptions.SerializerOptions) : new JsonSerializerOptions();
|
||||
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
options.ReferenceHandler = ReferenceHandler.Preserve;
|
||||
options.PropertyNameCaseInsensitive = true;
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
|
||||
var underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType;
|
||||
var underlyingSourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;
|
||||
|
||||
if (value is JsonElement { ValueKind: JsonValueKind.Number } jsonNumber && underlyingTargetType == typeof(string))
|
||||
return jsonNumber.ToString().ConvertTo(underlyingTargetType);
|
||||
|
||||
if (value is JsonElement jsonElement)
|
||||
{
|
||||
if (jsonElement.ValueKind == JsonValueKind.String && underlyingTargetType != typeof(string))
|
||||
return jsonElement.GetString().ConvertTo(underlyingTargetType);
|
||||
|
||||
return jsonElement.Deserialize(targetType, options);
|
||||
}
|
||||
|
||||
if (value is JsonNode jsonNode)
|
||||
return jsonNode.Deserialize(targetType, options);
|
||||
|
||||
if (underlyingSourceType == typeof(string) && !underlyingTargetType.IsPrimitive && underlyingTargetType != typeof(object))
|
||||
{
|
||||
var stringValue = (string)value;
|
||||
|
||||
try
|
||||
{
|
||||
var firstChar = stringValue.TrimStart().FirstOrDefault();
|
||||
|
||||
if (firstChar is '{' or '[')
|
||||
return JsonSerializer.Deserialize(stringValue, underlyingTargetType, options);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new Exception($"Failed to deserialize {stringValue} to {underlyingTargetType}");
|
||||
}
|
||||
}
|
||||
|
||||
if (targetType == typeof(object))
|
||||
return value;
|
||||
|
||||
if (underlyingTargetType.IsInstanceOfType(value))
|
||||
return value;
|
||||
|
||||
if (underlyingSourceType == underlyingTargetType)
|
||||
return value;
|
||||
|
||||
if (IsDateType(underlyingSourceType) && IsDateType(underlyingTargetType))
|
||||
return ConvertAnyDateType(value, underlyingTargetType);
|
||||
|
||||
if (typeof(IDictionary<string, object>).IsAssignableFrom(underlyingSourceType) && underlyingTargetType.IsClass)
|
||||
{
|
||||
if (typeof(ExpandoObject) == underlyingTargetType)
|
||||
{
|
||||
var expandoJson = JsonSerializer.Serialize(value);
|
||||
return ConvertTo(expandoJson, underlyingTargetType, converterOptions);
|
||||
}
|
||||
|
||||
if (typeof(IDictionary<string, object>).IsAssignableFrom(underlyingTargetType))
|
||||
return new Dictionary<string, object>((IDictionary<string, object>)value);
|
||||
|
||||
if (typeof(ExpandoObject) == underlyingSourceType)
|
||||
{
|
||||
// Parse ExpandoObject into target type.
|
||||
var expandoObject = (IDictionary<string, object>)value;
|
||||
var json = JsonSerializer.Serialize(expandoObject);
|
||||
return ConvertTo(json, underlyingTargetType, converterOptions);
|
||||
}
|
||||
}
|
||||
|
||||
var targetTypeConverter = TypeDescriptor.GetConverter(underlyingTargetType);
|
||||
|
||||
if (targetTypeConverter.CanConvertFrom(underlyingSourceType))
|
||||
return targetTypeConverter.IsValid(value)
|
||||
? targetTypeConverter.ConvertFrom(null!, CultureInfo.InvariantCulture, value)
|
||||
: targetType.GetDefaultValue();
|
||||
|
||||
var sourceTypeConverter = TypeDescriptor.GetConverter(underlyingSourceType);
|
||||
|
||||
if (sourceTypeConverter.CanConvertTo(underlyingTargetType))
|
||||
return sourceTypeConverter.ConvertTo(value, underlyingTargetType);
|
||||
|
||||
if (underlyingTargetType.IsEnum)
|
||||
{
|
||||
if (underlyingSourceType == typeof(string))
|
||||
return Enum.Parse(underlyingTargetType, (string)value);
|
||||
|
||||
if (underlyingSourceType == typeof(int))
|
||||
return Enum.ToObject(underlyingTargetType, value);
|
||||
|
||||
if (underlyingSourceType == typeof(double))
|
||||
return Enum.ToObject(underlyingTargetType, Convert.ChangeType(value, typeof(int), CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
if (value is string s)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(s))
|
||||
return null;
|
||||
|
||||
if (underlyingTargetType == typeof(Type))
|
||||
return Type.GetType(s);
|
||||
|
||||
// Perhaps it's a bit of a leap, but if the input is a string and the target type is IEnumerable<string>, then let's assume the string is a comma-separated list of strings.
|
||||
if (typeof(IEnumerable<string>).IsAssignableFrom(underlyingTargetType))
|
||||
return new[] { s };
|
||||
}
|
||||
|
||||
if (value is IEnumerable enumerable)
|
||||
{
|
||||
if (underlyingTargetType is { IsGenericType: true })
|
||||
{
|
||||
var desiredCollectionItemType = targetType.GenericTypeArguments[0];
|
||||
var desiredCollectionType = typeof(ICollection<>).MakeGenericType(desiredCollectionItemType);
|
||||
|
||||
if (underlyingTargetType.IsAssignableFrom(desiredCollectionType) || desiredCollectionType.IsAssignableFrom(underlyingTargetType))
|
||||
{
|
||||
var collectionType = typeof(List<>).MakeGenericType(desiredCollectionItemType);
|
||||
var collection = (IList)Activator.CreateInstance(collectionType)!;
|
||||
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
var convertedItem = ConvertTo(item, desiredCollectionItemType);
|
||||
collection.Add(convertedItem);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Convert.ChangeType(value, underlyingTargetType, CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
throw new Exception($"Failed to convert an object of type {sourceType} to {underlyingTargetType}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the specified type is date-like type, false otherwise.
|
||||
/// </summary>
|
||||
private static bool IsDateType(Type type)
|
||||
{
|
||||
var dateTypes = new[]
|
||||
{
|
||||
typeof(DateTime),
|
||||
typeof(DateTimeOffset)
|
||||
};
|
||||
|
||||
return dateTypes.Contains(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts any date type to the specified target type.
|
||||
/// </summary>
|
||||
/// <param name="value">Any of <see cref="DateTime"/> or <see cref="DateTimeOffset"/>.</param>
|
||||
/// <param name="targetType">Any of <see cref="DateTime"/> or <see cref="DateTimeOffset"/>.</param>
|
||||
/// <returns>The converted value.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is not of type <see cref="DateTime"/> or <see cref="DateTimeOffset"/>.</exception>
|
||||
private static object ConvertAnyDateType(object value, Type targetType)
|
||||
{
|
||||
return targetType switch
|
||||
{
|
||||
{ } t when t == typeof(DateTime) => value switch
|
||||
{
|
||||
DateTime dateTime => dateTime,
|
||||
DateTimeOffset dateTimeOffset => dateTimeOffset.DateTime,
|
||||
_ => throw new ArgumentException("Invalid value type.")
|
||||
},
|
||||
{ } t when t == typeof(DateTimeOffset) => value switch
|
||||
{
|
||||
DateTime dateTime => new DateTimeOffset(dateTime),
|
||||
DateTimeOffset dateTimeOffset => dateTimeOffset,
|
||||
_ => throw new ArgumentException("Invalid value type.")
|
||||
},
|
||||
_ => throw new ArgumentException("Invalid target type.")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Text.Json;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the PropertyBag class.
|
||||
/// </summary>
|
||||
public static class PropertyBagExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to retrieve a value from the PropertyBag based on the provided key.
|
||||
/// If the specified key does not exist in the PropertyBag, the method will return the default value obtained from the defaultValue function.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value to retrieve.</typeparam>
|
||||
/// <param name="propertyBag">The PropertyBag to retrieve the value from.</param>
|
||||
/// <param name="key">The key of the value to retrieve.</param>
|
||||
/// <param name="defaultValue">A function that returns the default value to be returned if the key does not exist in the PropertyBag.</param>
|
||||
/// <returns>The value associated with the key, or the default value if the key does not exist.</returns>
|
||||
public static T? TryGetValueOrDefault<T>(this PropertyBag propertyBag, string key, Func<T> defaultValue)
|
||||
{
|
||||
if (!propertyBag.TryGetValue(key, out var value))
|
||||
return defaultValue();
|
||||
|
||||
var json = value.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
return defaultValue();
|
||||
|
||||
return JsonSerializer.Deserialize<T>(json);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value in the PropertyBag based on the provided key.
|
||||
/// The value is serialized using JSON.
|
||||
/// </summary>
|
||||
/// <param name="propertyBag">The PropertyBag to set the value in.</param>
|
||||
/// <param name="key">The key to associate with the value.</param>
|
||||
/// <param name="value">The value to store in the PropertyBag.</param>
|
||||
public static void SetValue(this PropertyBag propertyBag, string key, object value)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(value);
|
||||
propertyBag[key] = json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
public static class ResilienceStrategyExtensions
|
||||
{
|
||||
public static string GetResilienceStrategyId(this JsonObject strategyJsonObject)
|
||||
{
|
||||
return strategyJsonObject.GetProperty<string>("id")!;
|
||||
}
|
||||
|
||||
public static string GetResilienceStrategyDisplayName(this JsonObject strategyJsonObject)
|
||||
{
|
||||
return strategyJsonObject.GetProperty<string>("displayName")!;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Elsa.Api.Client.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Adds extension methods to <see cref="Type"/>.
|
||||
/// </summary>
|
||||
public static class TypeExtensions
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, string> SimpleAssemblyQualifiedTypeNameCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assembly-qualified name of the type, without any version info etc.
|
||||
/// E.g. "System.String, System.Private.CoreLib"
|
||||
/// </summary>
|
||||
public static string GetSimpleAssemblyQualifiedName(this Type type)
|
||||
{
|
||||
if (type is null) throw new ArgumentNullException(nameof(type));
|
||||
return SimpleAssemblyQualifiedTypeNameCache.GetOrAdd(type, BuildSimplifiedName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the specified type.
|
||||
/// </summary>
|
||||
public static object? GetDefaultValue(this Type type) => type.IsClass ? null : Activator.CreateInstance(type);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the element type of the specified type representing an array or generic enumerable.
|
||||
/// </summary>
|
||||
public static Type GetEnumerableElementType(this Type type)
|
||||
{
|
||||
if (type.IsArray)
|
||||
return type.GetElementType()!;
|
||||
|
||||
var elementType = FindIEnumerable(type);
|
||||
return elementType == null ? type : elementType.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for the first implemented IEnumerable interface in the given type hierarchy, and returns the generic type argument of the interface.
|
||||
/// </summary>
|
||||
/// <param name="sequenceType">The type to search for the IEnumerable interface.</param>
|
||||
/// <returns>The generic type argument of the first implemented IEnumerable interface found in the type hierarchy, or null if none is found.</returns>
|
||||
private static Type? FindIEnumerable(Type? sequenceType)
|
||||
{
|
||||
if (sequenceType == null || sequenceType == typeof(string))
|
||||
return null;
|
||||
|
||||
if (sequenceType.IsArray)
|
||||
return typeof(IEnumerable<>).MakeGenericType(sequenceType.GetElementType()!);
|
||||
|
||||
if (sequenceType.IsGenericType)
|
||||
{
|
||||
foreach (var arg in sequenceType.GetGenericArguments())
|
||||
{
|
||||
var enumerable = typeof(IEnumerable<>).MakeGenericType(arg);
|
||||
if (enumerable.IsAssignableFrom(sequenceType))
|
||||
return enumerable;
|
||||
}
|
||||
}
|
||||
|
||||
var interfaces = sequenceType.GetInterfaces();
|
||||
|
||||
if (interfaces is { Length: > 0 })
|
||||
{
|
||||
foreach (var interfaceType in interfaces)
|
||||
{
|
||||
var enumerable = FindIEnumerable(interfaceType);
|
||||
if (enumerable != null) return enumerable;
|
||||
}
|
||||
}
|
||||
if (sequenceType.BaseType != null && sequenceType.BaseType != typeof(object))
|
||||
return FindIEnumerable(sequenceType.BaseType);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string BuildSimplifiedName(Type type)
|
||||
{
|
||||
var assemblyName = type.Assembly.GetName().Name;
|
||||
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
var genericTypeName = type.GetGenericTypeDefinition().FullName!;
|
||||
var backtickIndex = genericTypeName.IndexOf('`');
|
||||
var typeNameWithoutArity = genericTypeName[..backtickIndex];
|
||||
var arity = genericTypeName[backtickIndex..];
|
||||
|
||||
var genericArguments = type.GetGenericArguments();
|
||||
var simplifiedGenericArguments = genericArguments.Select(BuildSimplifiedName);
|
||||
|
||||
return $"{typeNameWithoutArity}{arity}[[{string.Join("],[", simplifiedGenericArguments)}]], {assemblyName}";
|
||||
}
|
||||
|
||||
var typeName = type.FullName;
|
||||
return $"{typeName}, {assemblyName}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<ConfigureAwait />
|
||||
</Weavers>
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Elsa.Api.Client.Converters;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client;
|
||||
|
||||
/// <summary>
|
||||
/// Contains helper methods for configuring Refit settings.
|
||||
/// </summary>
|
||||
public static class RefitSettingsHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RefitSettings"/> instance configured for Elsa.
|
||||
/// </summary>
|
||||
public static RefitSettings CreateRefitSettings(IServiceProvider serviceProvider, Action<IServiceProvider, JsonSerializerOptions>? configureJsonSerializerOptions = null)
|
||||
{
|
||||
var settings = new RefitSettings
|
||||
{
|
||||
ContentSerializer = new SystemTextJsonContentSerializer(CreateJsonSerializerOptions(serviceProvider, configureJsonSerializerOptions))
|
||||
};
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="JsonSerializerOptions"/> instance configured for Elsa.
|
||||
/// </summary>
|
||||
public static JsonSerializerOptions CreateJsonSerializerOptions(IServiceProvider serviceProvider, Action<IServiceProvider, JsonSerializerOptions>? configureJsonSerializerOptions = null)
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
};
|
||||
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
options.Converters.Add(new VersionOptionsJsonConverter());
|
||||
options.Converters.Add(new TypeJsonConverter());
|
||||
|
||||
configureJsonSerializerOptions?.Invoke(serviceProvider, options);
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Net.Http.Headers;
|
||||
using Elsa.Api.Client.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.Api.Client.HttpMessageHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// An <see cref="HttpMessageHandler"/> that configures the outgoing HTTP request to use an API key as the authorization header.
|
||||
/// </summary>
|
||||
public class ApiKeyHttpMessageHandler : DelegatingHandler
|
||||
{
|
||||
private readonly ElsaClientOptions _options;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiKeyHttpMessageHandler"/> class.
|
||||
/// </summary>
|
||||
public ApiKeyHttpMessageHandler(IOptions<ElsaClientOptions> options)
|
||||
{
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
var apiKey = _options.ApiKey;
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("ApiKey", apiKey);
|
||||
|
||||
return await base.SendAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace System.Runtime.CompilerServices;
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal sealed class IsExternalInit;
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Text.Json;
|
||||
using Elsa.Api.Client.HttpMessageHandlers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Polly;
|
||||
|
||||
namespace Elsa.Api.Client.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents options for building an Elsa API client.
|
||||
/// </summary>
|
||||
public class ElsaClientBuilderOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the base address of the Elsa server.
|
||||
/// </summary>
|
||||
public Uri BaseAddress { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the API key function to use when authenticating with the Elsa server.
|
||||
/// </summary>
|
||||
public string? ApiKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="DelegatingHandler"/> type that can be used to authenticate with the Elsa server.
|
||||
/// Defaults to <see cref="ApiKeyHttpMessageHandler"/>.
|
||||
/// </summary>
|
||||
public Type AuthenticationHandler { get; set; } = typeof(ApiKeyHttpMessageHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that can be used to configure the HTTP client.
|
||||
/// </summary>
|
||||
public Action<IServiceProvider, HttpClient>? ConfigureHttpClient { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that can be used to configure the HTTP client builder.
|
||||
/// </summary>
|
||||
public Action<IHttpClientBuilder> ConfigureHttpClientBuilder { get; set; } = _ => { };
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that can be used to configure the retry policy.
|
||||
/// </summary>
|
||||
public Action<IHttpClientBuilder>? ConfigureRetryPolicy { get; set; } = builder => builder.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt))));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that can be used to configure the JSON serializer options.
|
||||
/// </summary>
|
||||
public Action<IServiceProvider, JsonSerializerOptions>? ConfigureJsonSerializerOptions { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Elsa.Api.Client.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents options for the Elsa client.
|
||||
/// </summary>
|
||||
public class ElsaClientOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the base address of the Elsa server.
|
||||
/// </summary>
|
||||
public Uri BaseAddress { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the API key function to use when authenticating with the Elsa server.
|
||||
/// </summary>
|
||||
public string? ApiKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that can be used to configure the HTTP client.
|
||||
/// </summary>
|
||||
public Action<IServiceProvider, HttpClient>? ConfigureHttpClient { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Elsa.Api.Client.Resources.ActivityExecutions.Models;
|
||||
|
||||
namespace Elsa.Api.Client.RealTime.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Contains information about the activity executed event.
|
||||
/// </summary>
|
||||
/// <param name="ActivityId">The ID of the activity.</param>
|
||||
/// <param name="Stats">Execution stats about the activity.</param>
|
||||
public record ActivityExecutedMessage(string ActivityId, ActivityExecutionStats Stats);
|
||||
@@ -0,0 +1,10 @@
|
||||
using Elsa.Api.Client.Resources.ActivityExecutions.Models;
|
||||
|
||||
namespace Elsa.Api.Client.RealTime.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Contains information about the activity executing event.
|
||||
/// </summary>
|
||||
/// <param name="ActivityId">The ID of the activity.</param>
|
||||
/// <param name="Stats">Execution stats about the activity.</param>
|
||||
public record ActivityExecutingMessage(string ActivityId, ActivityExecutionStats Stats);
|
||||
@@ -0,0 +1,9 @@
|
||||
using Elsa.Api.Client.Resources.ActivityExecutions.Models;
|
||||
|
||||
namespace Elsa.Api.Client.RealTime.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Contains information about the activity execution logs updated event.
|
||||
/// </summary>
|
||||
/// <param name="Stats">Execution stats about a set of activities.</param>
|
||||
public record ActivityExecutionLogUpdatedMessage(ICollection<ActivityExecutionStats> Stats);
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Elsa.Api.Client.RealTime.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a message that is sent when the workflow execution log is updated.
|
||||
/// </summary>
|
||||
public record WorkflowExecutionLogUpdatedMessage();
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Elsa.Api.Client.RealTime.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a message that is sent when the workflow instance is updated.
|
||||
/// </summary>
|
||||
/// <param name="WorkflowInstanceId">The ID of the workflow instance that was updated.</param>
|
||||
public record WorkflowInstanceUpdatedMessage(string WorkflowInstanceId);
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
using Elsa.Api.Client.Resources.ActivityDescriptorOptions.Requests;
|
||||
using Elsa.Api.Client.Resources.ActivityDescriptorOptions.Responses;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptorOptions.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the workflow definitions API.
|
||||
/// </summary>
|
||||
public interface IActivityDescriptorOptionsApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists activity descriptors options.
|
||||
/// </summary>
|
||||
/// <param name="activityTypeName">The TypeName of the activity </param>
|
||||
/// <param name="propertyName">The name of the property</param>
|
||||
/// <param name="request">The context request.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The response containing the activity descriptors.</returns>
|
||||
[Post("/descriptors/activities/{activityTypeName}/options/{propertyName}")]
|
||||
Task<GetActivityDescriptorOptionsResponse> GetAsync(string activityTypeName, string propertyName, [Body]GetActivityDescriptorOptionsRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptorOptions.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request to Get Activity Descriptor Options.
|
||||
/// </summary>
|
||||
public class GetActivityDescriptorOptionsRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Object context use to pass custom information
|
||||
/// </summary>
|
||||
public object? Context { get; set; }
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptorOptions.Responses;
|
||||
/// <summary>
|
||||
/// Represents a response from get activity descriptors Options.
|
||||
/// </summary>
|
||||
/// <param name="Items">The options elements.</param>
|
||||
public record GetActivityDescriptorOptionsResponse(IDictionary<string,object> Items);
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using Elsa.Api.Client.Resources.ActivityDescriptors.Requests;
|
||||
using Elsa.Api.Client.Resources.ActivityDescriptors.Responses;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the workflow definitions API.
|
||||
/// </summary>
|
||||
public interface IActivityDescriptorsApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists activity descriptors.
|
||||
/// </summary>
|
||||
/// <param name="request">The request containing options for listing activity descriptors.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The response containing the activity descriptors.</returns>
|
||||
[Get("/descriptors/activities")]
|
||||
Task<ListActivityDescriptorsResponse> ListAsync([Query]ListActivityDescriptorsRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the kind of an activity, which affects how it is executed.
|
||||
/// </summary>
|
||||
public enum ActivityKind
|
||||
{
|
||||
/// <summary>
|
||||
/// Always run synchronously.
|
||||
/// </summary>
|
||||
Action,
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to trigger new workflows.
|
||||
/// </summary>
|
||||
Trigger,
|
||||
|
||||
/// <summary>
|
||||
/// Always run asynchronously.
|
||||
/// </summary>
|
||||
Job,
|
||||
|
||||
/// <summary>
|
||||
/// Run synchronously by default (like <see cref="Action"/>, but can be configured to run asynchronously (like <see cref="Job"/>).
|
||||
/// </summary>
|
||||
Task
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// The type of a port.
|
||||
/// </summary>
|
||||
public enum PortType
|
||||
{
|
||||
/// <summary>
|
||||
/// A port that is embedded in the activity.
|
||||
/// </summary>
|
||||
Embedded,
|
||||
|
||||
/// <summary>
|
||||
/// A flow port.
|
||||
/// </summary>
|
||||
Flow
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
using Elsa.Api.Client.Resources.ActivityDescriptors.Enums;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A descriptor of an activity type.
|
||||
/// </summary>
|
||||
public record ActivityDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// The fully qualified name of the activity type.
|
||||
/// </summary>
|
||||
public string TypeName { get; init; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The namespace of the activity type.
|
||||
/// </summary>
|
||||
public string Namespace { get; init; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the activity type.
|
||||
/// </summary>
|
||||
public string Name { get; init; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The version of the activity type.
|
||||
/// </summary>
|
||||
public int Version { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The category of the activity type.
|
||||
/// </summary>
|
||||
public string Category { get; init; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The display name of the activity type.
|
||||
/// </summary>
|
||||
public string? DisplayName { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The description of the activity type.
|
||||
/// </summary>
|
||||
public string? Description { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The input properties of the activity type.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<InputDescriptor> Inputs { get; init; } = new List<InputDescriptor>();
|
||||
|
||||
/// <summary>
|
||||
/// The output properties of the activity type.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<OutputDescriptor> Outputs { get; init; } = new List<OutputDescriptor>();
|
||||
|
||||
/// <summary>
|
||||
/// The kind of activity.
|
||||
/// </summary>
|
||||
public ActivityKind Kind { get; set; } = ActivityKind.Action;
|
||||
|
||||
/// <summary>
|
||||
/// The ports of the activity type.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<Port> Ports { get; init; } = new List<Port>();
|
||||
|
||||
/// <summary>
|
||||
/// The custom properties of the activity type.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, object> CustomProperties { get; set; } = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// The properties to set when constructing an activity in the designer.
|
||||
/// </summary>
|
||||
public IDictionary<string, object> ConstructionProperties { get; set; } = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating whether this activity is a container of child activities.
|
||||
/// </summary>
|
||||
public bool IsContainer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this activity type is selectable from activity pickers.
|
||||
/// </summary>
|
||||
public bool IsBrowsable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this activity type is a start activity.
|
||||
/// </summary>
|
||||
public bool IsStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this activity type is a terminal activity.
|
||||
/// </summary>
|
||||
public bool IsTerminal { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A descriptor of an activity's input property.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public class InputDescriptor : PropertyDescriptor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public InputDescriptor()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the property is wrapped with an <c>"Input{T}"</c> type, false otherwise.
|
||||
/// </summary>
|
||||
public bool IsWrapped { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A string value that hints at what UI control might be used to render in a UI tool.
|
||||
/// </summary>
|
||||
public string UIHint { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The category to which this input belongs. Can be used by UI to e.g. render different inputs in different tabs.
|
||||
/// </summary>
|
||||
public string? Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The default value.
|
||||
/// </summary>
|
||||
public object? DefaultValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The default syntax.
|
||||
/// </summary>
|
||||
public string? DefaultSyntax { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the input is readonly, false otherwise.
|
||||
/// </summary>
|
||||
public bool? IsReadOnly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The storage driver type to use for persistence.
|
||||
/// If no driver is specified, the referenced memory block will remain in memory for as long as the expression execution context exists.
|
||||
/// </summary>
|
||||
public string? StorageDriverType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary of UI specifications to be used by the UI.
|
||||
/// </summary>
|
||||
public IDictionary<string, object>? UISpecifications { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A descriptor of an activity's output property.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public class OutputDescriptor : PropertyDescriptor
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Elsa.Api.Client.Resources.ActivityDescriptors.Enums;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a port on an activity.
|
||||
/// </summary>
|
||||
public class Port
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the port.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display name of the port.
|
||||
/// </summary>
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the port.
|
||||
/// </summary>
|
||||
public PortType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visibility of the port.
|
||||
/// </summary>
|
||||
public bool? IsBrowsable { get; set; } = true;
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A base type for <see cref="InputDescriptor"/> and <see cref="OutputDescriptor"/>.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public abstract class PropertyDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// The name.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The .NET type.
|
||||
/// </summary>
|
||||
[JsonPropertyName("typeName")]
|
||||
public string TypeName { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The user friendly name of the input. Used by UI tools.
|
||||
/// </summary>
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user friendly description of the input. Used by UI tools.
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The order in which this input should be displayed by UI tools.
|
||||
/// </summary>
|
||||
public float Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if this input should be displayed by UI tools, false otherwise.
|
||||
/// </summary>
|
||||
public bool? IsBrowsable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if this input property is synthetic, which means it does not exist physically on the activity's .NET type.
|
||||
/// </summary>
|
||||
public bool IsSynthetic { get; set; }
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request to list activity descriptors.
|
||||
/// </summary>
|
||||
public class ListActivityDescriptorsRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether to refresh the activity descriptors or not.
|
||||
/// </summary>
|
||||
[Query] public bool Refresh { get; set; }
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using Elsa.Api.Client.Resources.ActivityDescriptors.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityDescriptors.Responses;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a response from listing activity descriptors.
|
||||
/// </summary>
|
||||
/// <param name="Items">The activity descriptors.</param>
|
||||
/// <param name="Count">The total number of activity descriptors.</param>
|
||||
public record ListActivityDescriptorsResponse(ICollection<ActivityDescriptor> Items, int Count);
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
using Elsa.Api.Client.Resources.ActivityExecutions.Models;
|
||||
using Elsa.Api.Client.Resources.ActivityExecutions.Requests;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityExecutions.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the activity executions API.
|
||||
/// </summary>
|
||||
public interface IActivityExecutionsApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a report of activity executions for a given workflow instance.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
/// <returns>The response containing the activity execution report.</returns>
|
||||
[Post("/activity-executions/report")]
|
||||
Task<ActivityExecutionReport> GetReportAsync([Body] GetActivityExecutionReportRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Lists activity executions for a given activity in a workflow instance.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
/// <returns>The response containing a list of activity executions.</returns>
|
||||
[Get("/activity-executions/list")]
|
||||
Task<ListResponse<ActivityExecutionRecord>> ListAsync(ListActivityExecutionsRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Lists activity execution summaries for a given activity in a workflow instance.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
/// <returns>The response containing a list of activity execution summaries.</returns>
|
||||
[Get("/activity-execution-summaries/list")]
|
||||
Task<ListResponse<ActivityExecutionRecordSummary>> ListSummariesAsync(ListActivityExecutionsRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single activity execution by ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the activity execution.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
/// <returns>The activity execution.</returns>
|
||||
[Get("/activity-executions/{id}")]
|
||||
Task<ActivityExecutionRecord?> GetAsync(string id, CancellationToken cancellationToken = default);
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
using Elsa.Api.Client.Resources.WorkflowInstances.Models;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityExecutions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single workflow execution, associated with an individual activity instance.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class ActivityExecutionRecord : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the workflow instance ID.
|
||||
/// </summary>
|
||||
public string WorkflowInstanceId { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the activity ID.
|
||||
/// </summary>
|
||||
public string ActivityId { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the activity node ID.
|
||||
/// </summary>
|
||||
public string ActivityNodeId { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The type of the activity.
|
||||
/// </summary>
|
||||
public string ActivityType { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The version of the activity type.
|
||||
/// </summary>
|
||||
public int ActivityTypeVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the activity.
|
||||
/// </summary>
|
||||
public string? ActivityName { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The state of the activity at the time this record is created or last updated.
|
||||
/// </summary>
|
||||
public IDictionary<string, object?>? ActivityState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Any additional payload associated with the log record.
|
||||
/// </summary>
|
||||
public IDictionary<string, object?>? Payload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Any outputs provided by the activity.
|
||||
/// </summary>
|
||||
public IDictionary<string, object?>? Outputs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Any properties provided by the activity.
|
||||
/// </summary>
|
||||
public IDictionary<string, object?> Properties { get; set; } = new Dictionary<string, object?>();
|
||||
|
||||
/// <summary>
|
||||
/// Any metadata provided by the activity. In contrast to the <see cref="Properties"/> property, this metadata is also persisted as part of the activity execution summary record.
|
||||
/// It is therefore not suitable for larger payloads.
|
||||
/// </summary>
|
||||
public IDictionary<string, object?> Metadata { get; set; } = new Dictionary<string, object?>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exception that occurred during the activity execution.
|
||||
/// </summary>
|
||||
public ExceptionState? Exception { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the time at which the activity execution began.
|
||||
/// </summary>
|
||||
public DateTimeOffset StartedAt { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the activity has any bookmarks.
|
||||
/// </summary>
|
||||
public bool HasBookmarks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status of the activity.
|
||||
/// </summary>
|
||||
public ActivityStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the time at which the activity execution completed.
|
||||
/// </summary>
|
||||
public DateTimeOffset? CompletedAt { get; set; }
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityExecutions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a summarized view of a single activity execution of an activity instance.
|
||||
/// </summary>
|
||||
public class ActivityExecutionRecordSummary : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the workflow instance ID.
|
||||
/// </summary>
|
||||
public string WorkflowInstanceId { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the activity ID.
|
||||
/// </summary>
|
||||
public string ActivityId { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the activity node ID.
|
||||
/// </summary>
|
||||
public string ActivityNodeId { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The type of the activity.
|
||||
/// </summary>
|
||||
public string ActivityType { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The version of the activity type.
|
||||
/// </summary>
|
||||
public int ActivityTypeVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the activity.
|
||||
/// </summary>
|
||||
public string? ActivityName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the time at which the activity execution began.
|
||||
/// </summary>
|
||||
public DateTimeOffset StartedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the activity has any bookmarks.
|
||||
/// </summary>
|
||||
public bool HasBookmarks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets metadata for the activity execution.
|
||||
/// </summary>
|
||||
public IDictionary<string, object?>? Metadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status of the activity.
|
||||
/// </summary>
|
||||
public ActivityStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the time at which the activity execution completed.
|
||||
/// </summary>
|
||||
public DateTimeOffset? CompletedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a summary view of the specified <see cref="ActivityExecutionRecord"/>.
|
||||
/// </summary>
|
||||
public static ActivityExecutionRecordSummary FromRecord(ActivityExecutionRecord record)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Id = record.Id,
|
||||
WorkflowInstanceId = record.WorkflowInstanceId,
|
||||
ActivityId = record.ActivityId,
|
||||
ActivityNodeId = record.ActivityNodeId,
|
||||
ActivityType = record.ActivityType,
|
||||
ActivityTypeVersion = record.ActivityTypeVersion,
|
||||
ActivityName = record.ActivityName,
|
||||
StartedAt = record.StartedAt,
|
||||
HasBookmarks = record.HasBookmarks,
|
||||
Status = record.Status,
|
||||
CompletedAt = record.CompletedAt,
|
||||
Metadata = record.Metadata
|
||||
};
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
namespace Elsa.Api.Client.Resources.ActivityExecutions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a report of activity executions.
|
||||
/// </summary>
|
||||
/// <param name="Stats">The activity execution stats.</param>
|
||||
public record ActivityExecutionReport(ICollection<ActivityExecutionStats> Stats);
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
namespace Elsa.Api.Client.Resources.ActivityExecutions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents statistics about the execution of an activity.
|
||||
/// </summary>
|
||||
public class ActivityExecutionStats
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the ID of the activity.
|
||||
/// </summary>
|
||||
public string ActivityId { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the node ID of the activity.
|
||||
/// </summary>
|
||||
public string ActivityNodeId { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of uncompleted executions.
|
||||
/// </summary>
|
||||
public long StartedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of completed executions.
|
||||
/// </summary>
|
||||
public long CompletedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of uncompleted executions.
|
||||
/// </summary>
|
||||
public long UncompletedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value whether this activity is waiting for bookmarks to be resumed.
|
||||
/// </summary>
|
||||
public bool IsBlocked { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value whether this activity is faulted.
|
||||
/// </summary>
|
||||
public bool IsFaulted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets additional metadata associated with the activity execution.
|
||||
/// </summary>
|
||||
public IDictionary<string, object>? Metadata { get; set; }
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
namespace Elsa.Api.Client.Resources.ActivityExecutions.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request for a list of activity execution records for a given activity in a workflow instance.
|
||||
/// </summary>
|
||||
public class GetActivityExecutionReportRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the workflow instance to get the execution log for.
|
||||
/// </summary>
|
||||
public string WorkflowInstanceId { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The node IDs of the activities to get the execution record for.
|
||||
/// </summary>
|
||||
public ICollection<string> ActivityNodeIds { get; set; } = default!;
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityExecutions.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request for a list of activity execution records for a given activity in a workflow instance.
|
||||
/// </summary>
|
||||
public class ListActivityExecutionsRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the workflow instance to get the execution log for.
|
||||
/// </summary>
|
||||
[Query]
|
||||
public string WorkflowInstanceId { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The node ID of the activity to get the execution record for.
|
||||
/// </summary>
|
||||
[Query]
|
||||
public string ActivityNodeId { get; set; } = default!;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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);
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Text.Json.Nodes;
|
||||
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<JsonObject> Alterations { get; set; } = new List<JsonObject>();
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
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<JsonObject> Alterations { get; set; } = new List<JsonObject>();
|
||||
|
||||
/// <summary>
|
||||
/// The IDs of the workflow instances that this plan applies to.
|
||||
/// </summary>
|
||||
public AlterationWorkflowInstanceFilter Filter { get; set; } = new();
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
using Elsa.Api.Client.Resources.WorkflowInstances.Enums;
|
||||
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>
|
||||
/// If the filter is empty, all records are matched.
|
||||
/// </summary>
|
||||
public bool EmptyFilterSelectsAll { get; set; }
|
||||
|
||||
/// <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 names associated with the workflow instances being filtered.
|
||||
/// </summary>
|
||||
public ICollection<string>? Names { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A search term used to filter workflow instances based on matching criteria.
|
||||
/// </summary>
|
||||
public string? SearchTerm { 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 ICollection<string>? DefinitionIds { 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 the workflow statuses included in the filter.
|
||||
/// </summary>
|
||||
public ICollection<WorkflowStatus>? Statuses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A collection of sub-statuses used to filter workflow instances by their specific sub-state.
|
||||
/// </summary>
|
||||
public ICollection<WorkflowSubStatus>? SubStatuses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Represents a collection of filters for activities.
|
||||
/// </summary>
|
||||
public IEnumerable<ActivityFilter>? ActivityFilters { get; set; }
|
||||
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
+19
@@ -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>();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
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<JsonObject> Alterations { get; set; } = new List<JsonObject>();
|
||||
|
||||
/// <summary>
|
||||
/// The IDs of the workflow instances that this plan applies to.
|
||||
/// </summary>
|
||||
public ICollection<string> WorkflowInstanceIds { get; set; } = new List<string>();
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using Elsa.Api.Client.Resources.CommitStrategies.Models;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.CommitStrategies.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the commit strategies API.
|
||||
/// </summary>
|
||||
public interface ICommitStrategiesApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists workflow commit strategies.
|
||||
/// </summary>
|
||||
/// <returns>A list response containing activity commit strategy descriptors and their count.</returns>
|
||||
[Get("/descriptors/commit-strategies/workflows")]
|
||||
Task<ListResponse<CommitStrategyDescriptor>> ListWorkflowStrategiesAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Lists activity commit strategies.
|
||||
/// </summary>
|
||||
/// <returns>A list response containing activity commit strategy descriptors and their count.</returns>
|
||||
[Get("/descriptors/commit-strategies/activities")]
|
||||
Task<ListResponse<CommitStrategyDescriptor>> ListActivityStrategiesAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
namespace Elsa.Api.Client.Resources.CommitStrategies.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a descriptor for a commit strategy, containing information such as its technical name,
|
||||
/// display name, and description.
|
||||
/// </summary>
|
||||
public record CommitStrategyDescriptor(string Name, string DisplayName, string Description);
|
||||
@@ -0,0 +1,23 @@
|
||||
using Elsa.Api.Client.Resources.Features.Models;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Features.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// A client for working with features.
|
||||
/// </summary>
|
||||
public interface IFeaturesApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the specified feature.
|
||||
/// </summary>
|
||||
[Get("/features/installed/{fullName}")]
|
||||
Task<FeatureDescriptor> GetAsync(string fullName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified feature.
|
||||
/// </summary>
|
||||
[Get("/features/installed")]
|
||||
Task<ListResponse<FeatureDescriptor>> ListAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Features.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a feature descriptor.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public class FeatureDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the feature.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the namespace of the feature.
|
||||
/// </summary>
|
||||
public string Namespace { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full name of the feature.
|
||||
/// </summary>
|
||||
public string FullName { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The display name for the feature.
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The description of the feature.
|
||||
/// </summary>
|
||||
public string Description { get; set; } = "";
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Elsa.Api.Client.Resources.Identity.Requests;
|
||||
using Elsa.Api.Client.Resources.Identity.Responses;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Identity.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the login API.
|
||||
/// </summary>
|
||||
public interface ILoginApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends the specified request to the login API.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The response.</returns>
|
||||
[Post("/identity/login")]
|
||||
Task<LoginResponse> LoginAsync([Body] LoginRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Elsa.Api.Client.Resources.Identity.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request to log in.
|
||||
/// </summary>
|
||||
/// <param name="Username">The username.</param>
|
||||
/// <param name="Password">The password.</param>
|
||||
public record LoginRequest(string Username, string Password);
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Elsa.Api.Client.Resources.Identity.Responses;
|
||||
|
||||
/// <summary>
|
||||
/// The response of logging in.
|
||||
/// </summary>
|
||||
public record LoginResponse(bool IsAuthenticated, string? AccessToken, string? RefreshToken);
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using Elsa.Api.Client.Resources.IncidentStrategies.Models;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.IncidentStrategies.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the variable types API.
|
||||
/// </summary>
|
||||
public interface IIncidentStrategiesApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists incident strategies.
|
||||
/// </summary>
|
||||
[Get("/descriptors/incident-strategies")]
|
||||
Task<ListResponse<IncidentStrategyDescriptor>> ListAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
namespace Elsa.Api.Client.Resources.IncidentStrategies.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an incident strategy.
|
||||
/// </summary>
|
||||
/// <param name="TypeName">The .NET type name of the strategy.</param>
|
||||
/// <param name="DisplayName">The display name of the strategy.</param>
|
||||
/// <param name="Description">The description of the strategy.</param>
|
||||
public record IncidentStrategyDescriptor(string TypeName, string DisplayName, string? Description);
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using JetBrains.Annotations;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.LogPersistenceStrategies;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client API for managing log persistence strategies.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public interface ILogPersistenceStrategiesApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists log persistence strategies.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
[Get("/descriptors/log-persistence-strategies")]
|
||||
Task<ListResponse<LogPersistenceStrategyDescriptor>> ListAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.LogPersistenceStrategies;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a log persistence strategy.
|
||||
/// </summary>
|
||||
/// <param name="TypeName">The .NET type name of the log persistence strategy.</param>
|
||||
/// <param name="DisplayName">The display name of the log persistence strategy.</param>
|
||||
/// <param name="Description">The description of the log persistence strategy.</param>
|
||||
[UsedImplicitly]
|
||||
public record LogPersistenceStrategyDescriptor(string TypeName, string DisplayName, string? Description);
|
||||
@@ -0,0 +1,16 @@
|
||||
using Elsa.Api.Client.Resources.Package.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Package.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// A client for working with packages.
|
||||
/// </summary>
|
||||
public interface IPackageApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the installed package version of Elsa.
|
||||
/// </summary>
|
||||
[Get("/package/version")]
|
||||
Task<PackageVersionResponse> GetAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Elsa.Api.Client.Resources.Package.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the installed package version of Elsa.
|
||||
/// </summary>
|
||||
/// <param name="PackageVersion">The installed package version of Elsa.</param>
|
||||
public record PackageVersionResponse(string PackageVersion);
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Resilience.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Provides operations for managing and retrieving resilience strategies within the application.
|
||||
/// </summary>
|
||||
public interface IResilienceStrategiesApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a list of resilience strategies from the resilience strategies API endpoint.
|
||||
/// </summary>
|
||||
/// <param name="category">The category to filter the strategies by.</param>
|
||||
/// <param name="cancellationToken">An optional token to cancel the operation.</param>
|
||||
/// <returns>A <see cref="ListResponse{JsonObject}"/> with the list of resilience strategies.</returns>
|
||||
[Get("/resilience/strategies")]
|
||||
Task<ListResponse<JsonObject>> ListAsync(string category, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Elsa.Api.Client.Resources.Resilience.Models;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Resilience.Contracts;
|
||||
|
||||
public interface IRetryAttemptsApi
|
||||
{
|
||||
[Get("/resilience/retries/{activityInstanceId}")]
|
||||
Task<PagedListResponse<RetryAttemptRecord>> ListAsync(string activityInstanceId, int? skip = null, int? take = null, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Elsa.Api.Client.Resources.Scripting.Models;
|
||||
using Elsa.Api.Client.Serialization;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Resilience.Models;
|
||||
|
||||
public class ResilienceStrategyConfig
|
||||
{
|
||||
public ResilienceStrategyConfigMode Mode { get; set; }
|
||||
public string? StrategyId { get; set; }
|
||||
public Expression? Expression { get; set; }
|
||||
|
||||
public JsonNode SerializeToNode()
|
||||
{
|
||||
return JsonSerializer.SerializeToNode(this, SerializerOptions.ResilienceStrategyConfigSerializerOptions)!;
|
||||
}
|
||||
|
||||
public static ResilienceStrategyConfig? Deserialize(JsonNode? node)
|
||||
{
|
||||
return node.Deserialize<ResilienceStrategyConfig?>(SerializerOptions.ResilienceStrategyConfigSerializerOptions)!;
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
namespace Elsa.Api.Client.Resources.Resilience.Models;
|
||||
|
||||
public enum ResilienceStrategyConfigMode
|
||||
{
|
||||
Identifier,
|
||||
Expression,
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Resilience.Models;
|
||||
|
||||
public class RetryAttemptRecord : Entity
|
||||
{
|
||||
public string ActivityInstanceId { get; set; } = null!;
|
||||
public string ActivityId { get; set; } = null!;
|
||||
public string WorkflowInstanceId { get; set; } = null!;
|
||||
public int AttemptNumber { get; set; }
|
||||
public TimeSpan RetryDelay { get; set; }
|
||||
public IDictionary<string, string?> Details { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Elsa.Api.Client.Resources.Scripting.Models;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using JetBrains.Annotations;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Scripting.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the expression descriptors API.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public interface IExpressionDescriptorsApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends a request to retrieve all available expression descriptors.
|
||||
/// </summary>
|
||||
[Get("/descriptors/expression-descriptors")]
|
||||
Task<ListResponse<ExpressionDescriptor>> ListAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Elsa.Api.Client.Resources.Scripting.Requests;
|
||||
using JetBrains.Annotations;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Scripting.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the workflow javascript API.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public interface IJavaScriptApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Dispatches a request to retrieve the type definitions of the specified workflow definition.
|
||||
/// </summary>
|
||||
/// <param name="definitionId">The definition ID of the workflow definition to retrieve the type definitions for.</param>
|
||||
/// <param name="request">Required request containing properties to retrieve the correct type definitions.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
/// <returns>A response containing the type definition data which can be used to extend auto completion in Monaco.</returns>
|
||||
[Post("/scripting/javascript/type-definitions/{definitionId}")]
|
||||
Task<HttpResponseMessage> GetTypeDefinitions(string definitionId, GetWorkflowJavaScriptDefinitionRequest request, CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Elsa.Api.Client.Resources.Scripting.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Scripting.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="Expression"/>.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static class ExpressionDescriptorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the expression language to use for the Monaco editor.
|
||||
/// </summary>
|
||||
public static string? GetMonacoLanguage(this ExpressionDescriptor descriptor) => descriptor.Properties.TryGetValue("MonacoLanguage", out var language) ? language : null;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Scripting.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dynamic expression.
|
||||
/// </summary>
|
||||
public class Expression
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Expression"/> class.
|
||||
/// </summary>
|
||||
[JsonConstructor]
|
||||
public Expression()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Expression"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of the expression.</param>
|
||||
/// <param name="value">The expression.</param>
|
||||
public Expression(string type, string? value = null)
|
||||
{
|
||||
Type = type;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the expression type.
|
||||
/// </summary>
|
||||
public string Type { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value representing the expression.
|
||||
/// </summary>
|
||||
public object? Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the C# expression.
|
||||
/// </summary>
|
||||
public override string ToString() => Value?.ToString() ?? "";
|
||||
|
||||
/// <summary>
|
||||
/// Creates a literal expression.
|
||||
/// </summary>
|
||||
public static Expression CreateLiteral(string value) => new("Literal", value);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an object expression.
|
||||
/// </summary>
|
||||
public static Expression CreateObject(string value) => new("Object", value);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Scripting.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a descriptor for an expression.
|
||||
/// </summary>
|
||||
public class ExpressionDescriptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExpressionDescriptor"/> class.
|
||||
/// </summary>
|
||||
[JsonConstructor]
|
||||
public ExpressionDescriptor()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExpressionDescriptor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The expression type.</param>
|
||||
/// <param name="displayName">The display name of the expression type.</param>
|
||||
public ExpressionDescriptor(string type, string displayName)
|
||||
{
|
||||
Type = type;
|
||||
DisplayName = displayName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the expression type.
|
||||
/// </summary>
|
||||
public string Type { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display name of the expression type.
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the expression value is serializable.
|
||||
/// </summary>
|
||||
public bool IsSerializable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the expression type is browsable.
|
||||
/// </summary>
|
||||
public bool IsBrowsable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the expression type properties.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> Properties { get; set; } = new Dictionary<string, string>();
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
namespace Elsa.Api.Client.Resources.Scripting.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// A request to retrieve the type definitions
|
||||
/// </summary>
|
||||
public class GetWorkflowJavaScriptDefinitionRequest(string workflowDefinitionId, string? activityTypeName, string? propertyName)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets workflow definition to retrieve type definitions for.
|
||||
/// </summary>
|
||||
public string WorkflowDefinitionId { get; set; } = workflowDefinitionId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type name of the activity to retrieve type definitions for.
|
||||
/// </summary>
|
||||
public string? ActivityTypeName { get; set; } = activityTypeName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the property to retrieve type definitions for.
|
||||
/// </summary>
|
||||
public string? PropertyName { get; set; } = propertyName;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Elsa.Api.Client.Resources.StorageDrivers.Responses;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.StorageDrivers.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the storage drivers API.
|
||||
/// </summary>
|
||||
public interface IStorageDriversApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists storage drivers.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The response containing the storage drivers.</returns>
|
||||
[Get("/descriptors/storage-drivers")]
|
||||
Task<ListStorageDriversResponse> ListAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Elsa.Api.Client.Resources.StorageDrivers.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a storage driver descriptor.
|
||||
/// </summary>
|
||||
/// <param name="TypeName">The type name of the storage driver.</param>
|
||||
/// <param name="DisplayName">The display name of the storage driver.</param>
|
||||
public record StorageDriverDescriptor(string TypeName, string DisplayName, double Priority = 0, bool Deprecated = false);
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
using Elsa.Api.Client.Resources.StorageDrivers.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.StorageDrivers.Responses;
|
||||
|
||||
/// <summary>
|
||||
/// The response containing the storage drivers.
|
||||
/// </summary>
|
||||
/// <param name="Items">The storage drivers.</param>
|
||||
public record ListStorageDriversResponse(ICollection<StorageDriverDescriptor> Items);
|
||||
@@ -0,0 +1,20 @@
|
||||
using Elsa.Api.Client.Resources.Tasks.Requests;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.Tasks.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the tasks API.
|
||||
/// </summary>
|
||||
public interface ITasksApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends the specified request to the tasks API.
|
||||
/// </summary>
|
||||
/// <param name="taskId">The Id of the task being reported as completed.</param>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The response.</returns>
|
||||
[Post("/tasks/{taskId}/complete")]
|
||||
Task ReportTaskCompletedAsync(string taskId, [Body] ReportTaskCompletedRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Elsa.Api.Client.Resources.Tasks.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request to report a task has been completed.
|
||||
/// </summary>
|
||||
/// <param name="Result">The result of the task being reported as completed.</param>
|
||||
public record ReportTaskCompletedRequest(object? Result);
|
||||
@@ -0,0 +1,18 @@
|
||||
using Elsa.Api.Client.Resources.VariableTypes.Responses;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.VariableTypes.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the variable types API.
|
||||
/// </summary>
|
||||
public interface IVariableTypesApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists variable types.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The response containing the variable types.</returns>
|
||||
[Get("/descriptors/variables")]
|
||||
Task<ListVariableTypesResponse> ListAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Elsa.Api.Client.Resources.VariableTypes.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a variable type.
|
||||
/// </summary>
|
||||
/// <param name="TypeName">The .NET type name of the variable type.</param>
|
||||
/// <param name="DisplayName">The display name of the variable type.</param>
|
||||
/// <param name="Category">The category of the variable type.</param>
|
||||
/// <param name="Description">The description of the variable type.</param>
|
||||
public record VariableTypeDescriptor(string TypeName, string DisplayName, string Category, string? Description);
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
using Elsa.Api.Client.Resources.VariableTypes.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.VariableTypes.Responses;
|
||||
|
||||
/// <summary>
|
||||
/// A response containing a list of variable types.
|
||||
/// </summary>
|
||||
/// <param name="Items">A list of variable types.</param>
|
||||
public record ListVariableTypesResponse(ICollection<VariableTypeDescriptor> Items);
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
using Elsa.Api.Client.Resources.WorkflowActivationStrategies.Models;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.WorkflowActivationStrategies.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a client for the variable types API.
|
||||
/// </summary>
|
||||
public interface IWorkflowActivationStrategiesApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists workflow activation strategies.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
[Get("/descriptors/workflow-activation-strategies")]
|
||||
Task<ListResponse<WorkflowActivationStrategyDescriptor>> ListAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
namespace Elsa.Api.Client.Resources.WorkflowActivationStrategies.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a workflow activation strategy.
|
||||
/// </summary>
|
||||
/// <param name="TypeName">The .NET type name of the activation strategy.</param>
|
||||
/// <param name="DisplayName">The display name of the activation strategy.</param>
|
||||
/// <param name="Description">The description of the activation strategy.</param>
|
||||
public record WorkflowActivationStrategyDescriptor(string TypeName, string DisplayName, string? Description);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user