Initial work on Elsa Client

This commit is contained in:
Sipke Schoorstra 2023-04-01 16:15:35 +02:00
parent 4a8ec72598
commit 3ec9df87c1
21 changed files with 276 additions and 29 deletions

View file

@ -18,12 +18,14 @@
</head>
<body>
<elsa-workflow-toolbar></elsa-workflow-toolbar>
<div class="absolute inset-0" style="top: 64px;">
<elsa-studio server="@serverUrl" monaco-lib-path="@basePath.TrimStart('/')/_content/Elsa.Workflows.Designer/monaco-editor/min"></elsa-studio>
<elsa-custom-activities-manager></elsa-custom-activities-manager>
<elsa-notifications-manager></elsa-notifications-manager>
</div>
<elsa-shell>
<elsa-workflow-toolbar></elsa-workflow-toolbar>
<div class="absolute inset-0" style="top: 64px;">
<elsa-studio server="@serverUrl" monaco-lib-path="@basePath.TrimStart('/')/_content/Elsa.Workflows.Designer/monaco-editor/min"></elsa-studio>
<elsa-custom-activities-manager></elsa-custom-activities-manager>
<elsa-notifications-manager></elsa-notifications-manager>
</div>
</elsa-shell>
</body>
</html>

View file

@ -1,2 +1,4 @@
@namespace Elsa.AllInOne.Web.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using Esprima.Ast
@namespace Elsa.AllInOne.Web.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using Elsa.Workflows.Designer

View file

@ -1,7 +1,7 @@
namespace Elsa.Api.Client.Contracts;
/// <summary>
/// Represents a client for the Elsa API.
/// Represents a client for the Elsa API. Each API is exposed as a property.
/// </summary>
public interface IElsaClient
{
@ -9,4 +9,9 @@ public interface IElsaClient
/// Gets the workflow definitions API.
/// </summary>
IWorkflowDefinitionsApi WorkflowDefinitions { get; }
/// <summary>
/// Gets the workflow instances API.
/// </summary>
IWorkflowInstancesApi WorkflowInstances { get; }
}

View file

@ -1,3 +1,5 @@
using Elsa.Api.Client.Models;
namespace Elsa.Api.Client.Contracts;
/// <summary>
@ -5,4 +7,19 @@ namespace Elsa.Api.Client.Contracts;
/// </summary>
public interface IWorkflowDefinitionsApi
{
/// <summary>
/// Lists workflow definitions.
/// </summary>
/// <param name="request">The request containing options for listing workflow definitions.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The response containing the workflow definitions.</returns>
Task<ListWorkflowDefinitionsResponse> ListAsync(ListWorkflowDefinitionsRequest request, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a workflow definition.
/// </summary>
/// <param name="request">The request containing the ID of the workflow definition to delete.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The response.</returns>
Task<DeleteWorkflowDefinitionResponse> DeleteAsync(DeleteWorkflowDefinitionRequest request, CancellationToken cancellationToken = default);
}

View file

@ -0,0 +1,8 @@
namespace Elsa.Api.Client.Contracts;
/// <summary>
/// Represents a client for the workflow instances API.
/// </summary>
public interface IWorkflowInstancesApi
{
}

View file

@ -1,6 +1,7 @@
using Elsa.Api.Client.Contracts;
using Elsa.Api.Client.Options;
using Elsa.Api.Client.Services;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Refit;
@ -10,6 +11,7 @@ namespace Elsa.Api.Client.Extensions;
/// <summary>
/// Provides extension methods for dependency injection.
/// </summary>
[PublicAPI]
public static class DependencyInjectionExtensions
{
/// <summary>
@ -21,16 +23,22 @@ public static class DependencyInjectionExtensions
services.AddSingleton<IElsaClient, ElsaClient>();
var settings = new RefitSettings();
services.AddClient<IWorkflowDefinitionsApi>(settings);
services.AddElsaApiClient<IWorkflowDefinitionsApi>(settings);
return services;
}
private static void AddClient<T>(this IServiceCollection services, RefitSettings settings) where T : class
/// <summary>
/// Adds a refit client for the specified API type.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="settings">The refit settings.</param>
/// <typeparam name="T">The API type.</typeparam>
public static void AddElsaApiClient<T>(this IServiceCollection services, RefitSettings settings) where T : class
{
services.AddRefitClient<T>(settings).ConfigureHttpClient(ConfigureHttpClient);
services.AddRefitClient<T>(settings).ConfigureHttpClient(ConfigureElsaApiHttpClient);
}
private static void ConfigureHttpClient(IServiceProvider serviceProvider, HttpClient httpClient)
private static void ConfigureElsaApiHttpClient(IServiceProvider serviceProvider, HttpClient httpClient)
{
var options = serviceProvider.GetRequiredService<IOptions<ElsaClientOptions>>().Value;
httpClient.BaseAddress = options.BaseAddress;

View file

@ -0,0 +1,8 @@
using System.ComponentModel;
// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices
{
[EditorBrowsable(EditorBrowsableState.Never)]
internal class IsExternalInit{}
}

View file

@ -0,0 +1,12 @@
namespace Elsa.Api.Client.Contracts;
/// <summary>
/// The request for deleting a workflow definition.
/// </summary>
public class DeleteWorkflowDefinitionRequest
{
/// <summary>
/// The ID of the workflow definition to delete.
/// </summary>
public string DefinitionId { get; set; }
}

View file

@ -0,0 +1,8 @@
namespace Elsa.Api.Client.Contracts;
/// <summary>
/// The response of deleting a workflow definition.
/// </summary>
public record DeleteWorkflowDefinitionResponse
{
}

View file

@ -0,0 +1,7 @@
namespace Elsa.Api.Client.Contracts;
public class GetWorkflowDefinitionRequest
{
public string DefinitionId { get; set; } = default!;
public string? VersionOptions { get; set; }
}

View file

@ -0,0 +1,4 @@
namespace Elsa.Api.Client.Contracts;
public record GetWorkflowDefinitionResponse(
);

View file

@ -0,0 +1,34 @@
using Refit;
namespace Elsa.Api.Client.Models;
/// <summary>
/// Represents a request to list workflow definitions.
/// </summary>
public class ListWorkflowDefinitionsRequest
{
/// <summary>
/// The page number.
/// </summary>
public int? Page { get; set; }
/// <summary>
/// The page size.
/// </summary>
public int? PageSize { get; set; }
/// <summary>
/// The version options.
/// </summary>
public VersionOptions? Version { get; set; }
/// <summary>
/// The name of the workflow materializer to filter by.
/// </summary>
[AliasAs("materializer")] public string? MaterializerName { get; set; }
/// <summary>
/// The labels to filter by.
/// </summary>
[AliasAs("label")] public string[]? Labels { get; set; }
}

View file

@ -0,0 +1,8 @@
namespace Elsa.Api.Client.Models;
/// <summary>
/// Represents a response from listing workflow definitions.
/// </summary>
/// <param name="Items">The workflow definitions.</param>
/// <param name="TotalCount">The total number of workflow definitions.</param>
public record ListWorkflowDefinitionsResponse(ICollection<WorkflowDefinitionSummary> Items, int TotalCount);

View file

@ -0,0 +1,106 @@
using JetBrains.Annotations;
namespace Elsa.Api.Client.Models;
/// <summary>
/// Represents the version to get.
/// </summary>
[PublicAPI]
public struct VersionOptions
{
/// <summary>
/// Gets the latest version.
/// </summary>
public static readonly VersionOptions Latest = new() { IsLatest = true };
/// <summary>
/// Gets the published version.
/// </summary>
public static readonly VersionOptions Published = new() { IsPublished = true };
/// <summary>
/// Gets the published version if available, and if not, the latest version.
/// </summary>
public static readonly VersionOptions LatestOrPublished = new() { IsLatestOrPublished = true };
/// <summary>
/// Gets the latest, published version.
/// </summary>
public static readonly VersionOptions LatestAndPublished = new() { IsLatestOrPublished = true };
/// <summary>
/// Gets the draft version.
/// </summary>
public static readonly VersionOptions Draft = new() { IsDraft = true };
/// <summary>
/// Gets all versions.
/// </summary>
public static readonly VersionOptions All = new() { AllVersions = true };
/// <summary>
/// Gets a specific version.
/// </summary>
public static VersionOptions SpecificVersion(int version) => new() { Version = version };
/// <summary>
/// Parses a string into a <see cref="VersionOptions"/>.
/// </summary>
public static VersionOptions FromString(string value) =>
value switch
{
"AllVersions" => All,
"Draft" => Draft,
"Latest" => Latest,
"Published" => Published,
"LatestOrPublished" => LatestOrPublished,
"LatestAndPublished" => LatestAndPublished,
_ => SpecificVersion(int.Parse(value))
};
public static bool TryParse(string value, out VersionOptions versionOptions)
{
versionOptions = FromString(value);
return true;
}
/// <summary>
/// Gets the latest version.
/// </summary>
public bool IsLatest { get; private set; }
/// <summary>
/// Gets the published version if available, and if not, the latest version.
/// </summary>
public bool IsLatestOrPublished { get; private set; }
/// <summary>
/// Gets the latest, published version.
/// </summary>
public bool IsLatestAndPublished { get; private set; }
/// <summary>
/// Gets the published version.
/// </summary>
public bool IsPublished { get; private set; }
/// <summary>
/// Gets the draft version.
/// </summary>
public bool IsDraft { get; private set; }
/// <summary>
/// Gets all versions.
/// </summary>
public bool AllVersions { get; private set; }
/// <summary>
/// Gets a specific version.
/// </summary>
public int Version { get; private set; }
/// <summary>
/// Returns a simple string representation of this <see cref="VersionOptions"/>.
/// </summary>
public override string ToString() => AllVersions ? "AllVersions" : IsDraft ? "Draft" : IsLatest ? "Latest" : IsPublished ? "Published" : IsLatestOrPublished ? "LatestOrPublished" : IsLatestAndPublished ? "LatestAndPublished" : Version.ToString();
}

View file

@ -0,0 +1,9 @@
using JetBrains.Annotations;
namespace Elsa.Api.Client.Models;
/// <summary>
/// A summary of a workflow definition.
/// </summary>
[PublicAPI]
public record WorkflowDefinitionSummary(string Id, string DefinitionId, string? Name, string? Description, int? Version, bool IsLatest, bool IsPublished, string MaterializerName, DateTimeOffset CreatedAt);

View file

@ -8,12 +8,15 @@ public class ElsaClient : IElsaClient
/// <summary>
/// Initializes a new instance of the <see cref="ElsaClient"/> class.
/// </summary>
/// <param name="workflowDefinitionsApi">The workflow definitions API.</param>
public ElsaClient(IWorkflowDefinitionsApi workflowDefinitionsApi)
public ElsaClient(IWorkflowDefinitionsApi workflowDefinitions, IWorkflowInstancesApi workflowInstances)
{
WorkflowDefinitions = workflowDefinitionsApi;
WorkflowDefinitions = workflowDefinitions;
WorkflowInstances = workflowInstances;
}
/// <inheritdoc />
public IWorkflowDefinitionsApi WorkflowDefinitions { get; }
/// <inheritdoc />
public IWorkflowInstancesApi WorkflowInstances { get; }
}

View file

@ -13,11 +13,11 @@
<body>
<!--Use the studio shell component to handle automatic interaction with the Elsa Server API-->
<elsa-shell>
<elsa-workflow-toolbar></elsa-workflow-toolbar>
<div class="absolute inset-0" style="top: 64px;">
<elsa-studio server="https://localhost:5001/elsa/api" monaco-lib-path="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.31.1/min"></elsa-studio>
<elsa-custom-activities-manager></elsa-custom-activities-manager>
</div>
<elsa-workflow-toolbar></elsa-workflow-toolbar>
<div class="absolute inset-0" style="top: 64px;">
<elsa-studio server="https://localhost:5001/elsa/api" monaco-lib-path="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.31.1/min"></elsa-studio>
<elsa-custom-activities-manager></elsa-custom-activities-manager>
</div>
</elsa-shell>
<script type="module">

View file

@ -1,9 +1,11 @@
using Elsa.Abstractions;
using Elsa.Common.Models;
using Elsa.Workflows.Management.Contracts;
using JetBrains.Annotations;
namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.List;
[PublicAPI]
internal class List : ElsaEndpoint<Request, Response>
{
private readonly IWorkflowDefinitionStore _store;

View file

@ -34,8 +34,4 @@
<ProjectReference Include="..\..\common\Elsa.Features\Elsa.Features.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot" />
</ItemGroup>
</Project>

View file

@ -5,7 +5,7 @@
"packages": {
"": {
"devDependencies": {
"@elsa-workflows/elsa-workflows-designer": "3.0.3-preview.79",
"@elsa-workflows/elsa-workflows-designer": "3.0.3-preview.84",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"monaco-editor": "^0.34.1",
@ -115,9 +115,9 @@
}
},
"node_modules/@elsa-workflows/elsa-workflows-designer": {
"version": "3.0.3-preview.79",
"resolved": "https://f.feedz.io/elsa-workflows/elsa-3/npm/%40elsa-workflows%2felsa-workflows-designer/3.0.3-preview.79/download",
"integrity": "sha512-jFwED5zcXbPykUGFdw/S7KLIzXRVUxmPBomVxXFBmW+C/KOtZM13dRs/5NAEAikrRW5qdrQ+AtfQLWDj8TElug==",
"version": "3.0.3-preview.84",
"resolved": "https://f.feedz.io/elsa-workflows/elsa-3/npm/%40elsa-workflows%2felsa-workflows-designer/3.0.3-preview.84/download",
"integrity": "sha512-53+ljpsCrhntFFSEdqwEmd5y0OWwLvGVMxTxty6HiP/MbB4fctZxxQORDhkoAp01OlG6A7Lsx9cfiRDxKkqc+Q==",
"dev": true,
"dependencies": {
"@antv/layout": "^0.3.11",

View file

@ -1,9 +1,17 @@
using Elsa.Workflows.Management.Entities;
using JetBrains.Annotations;
namespace Elsa.Workflows.Management.Models;
/// <summary>
/// A summary of a workflow definition.
/// </summary>
[PublicAPI]
public record WorkflowDefinitionSummary(string Id, string DefinitionId, string? Name, string? Description, int? Version, bool IsLatest, bool IsPublished, string MaterializerName, DateTimeOffset CreatedAt)
{
/// <summary>
/// Creates a new instance of the <see cref="WorkflowDefinitionSummary"/> class from the specified <see cref="WorkflowDefinition"/> instance.
/// </summary>
public static WorkflowDefinitionSummary FromDefinition(WorkflowDefinition workflowDefinition) => new(
workflowDefinition.Id,
workflowDefinition.DefinitionId,