Skip to content

Commit

Permalink
Merge branch 'main' into custom-uiprovider
Browse files Browse the repository at this point in the history
  • Loading branch information
sfmskywalker committed Dec 29, 2023
2 parents 6fe917c + c33801d commit cfb3d03
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 137 deletions.
1 change: 1 addition & 0 deletions src/bundles/Elsa.ServerAndStudio.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"DefaultSender": "[email protected]"
},
"Http": {
"BaseUrl": "https://localhost:5001",
"BasePath": "/api/workflows"
},
"Webhooks": {
Expand Down
37 changes: 0 additions & 37 deletions src/clients/Elsa.Api.Client/Contracts/IElsaClient.cs

This file was deleted.

14 changes: 0 additions & 14 deletions src/clients/Elsa.Api.Client/Contracts/IElsaClientFactory.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Elsa.Api.Client.Contracts;
using Elsa.Api.Client.Converters;
using Elsa.Api.Client.HttpMessageHandlers;
using Elsa.Api.Client.Options;
using Elsa.Api.Client.Resources.ActivityDescriptorOptions.Contracts;
using Elsa.Api.Client.Resources.ActivityDescriptors.Contracts;
Expand All @@ -17,7 +15,6 @@
using Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts;
using Elsa.Api.Client.Resources.WorkflowExecutionContexts.Contracts;
using Elsa.Api.Client.Resources.WorkflowInstances.Contracts;
using Elsa.Api.Client.Services;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
Expand All @@ -33,40 +30,39 @@ namespace Elsa.Api.Client.Extensions;
public static class DependencyInjectionExtensions
{
/// <summary>
/// Adds the Elsa client to the service collection.
/// Adds the Elsa API client configured to use an API key to the service collection.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="baseAddress">The base address of the Elsa API.</param>
/// <param name="apiKey">The API key to use for authentication.</param>
/// <param name="configureOptions">An optional delegate that can be used to configure the client options.</param>
/// <param name="configureBuilderOptions">An optional delegate that can be used to configure the client builder options.</param>
public static IServiceCollection AddElsaClient(this IServiceCollection services, Uri baseAddress, string apiKey, Action<ElsaClientOptions>? configureOptions = default, Action<ElsaClientBuilderOptions>? configureBuilderOptions = default)
public static IServiceCollection AddElsaApiKeyClient(this IServiceCollection services, Action<ElsaClientOptions> configureOptions)
{
services.AddScoped<ApiKeyHttpMessageHandler>();
return services.AddElsaClient(
options =>
{
options.BaseAddress = baseAddress;
options.ApiKey = apiKey;
configureOptions?.Invoke(options);
},
configureBuilderOptions: options =>
{
options.ConfigureHttpClientBuilder = builder => builder.AddHttpMessageHandler<ApiKeyHttpMessageHandler>();
configureBuilderOptions?.Invoke(options);
});
var options = new ElsaClientOptions();
configureOptions(options);

return services.AddElsaClient(client =>
{
client.BaseAddress = options.BaseAddress;
client.ApiKey = options.ApiKey;
client.ConfigureHttpClient = options.ConfigureHttpClient;
});
}

/// <summary>
/// Adds the Elsa client to the service collection.
/// </summary>
public static IServiceCollection AddElsaClient(this IServiceCollection services, Action<ElsaClientOptions>? configureOptions = default, Action<ElsaClientBuilderOptions>? configureBuilderOptions = default)
public static IServiceCollection AddElsaClient(this IServiceCollection services, Action<ElsaClientBuilderOptions> configureClient)
{
var builderOptions = new ElsaClientBuilderOptions();
configureBuilderOptions?.Invoke(builderOptions);
configureClient.Invoke(builderOptions);

builderOptions.ConfigureHttpClientBuilder += builder => builder.AddHttpMessageHandler(sp => (DelegatingHandler)sp.GetRequiredService(builderOptions.AuthenticationHandler));

services.AddScoped(builderOptions.AuthenticationHandler);

services.Configure(configureOptions ?? (_ => { }));
services.AddScoped<IElsaClient, ElsaClient>();
services.Configure<ElsaClientOptions>(options =>
{
options.BaseAddress = builderOptions.BaseAddress;
options.ConfigureHttpClient = builderOptions.ConfigureHttpClient;
options.ApiKey = builderOptions.ApiKey;
});
services.AddApi<IWorkflowDefinitionsApi>(builderOptions);
services.AddApi<IWorkflowInstancesApi>(builderOptions);
services.AddApi<IActivityDescriptorsApi>(builderOptions);
Expand Down
14 changes: 14 additions & 0 deletions src/clients/Elsa.Api.Client/Extensions/HeaderExtensions.cs
Original file line number Diff line number Diff line change
@@ -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;
}
26 changes: 23 additions & 3 deletions src/clients/Elsa.Api.Client/Options/ElsaClientBuilderOptions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Elsa.Api.Client.HttpMessageHandlers;
using Microsoft.Extensions.DependencyInjection;

namespace Elsa.Api.Client.Options;
Expand All @@ -7,10 +8,29 @@ namespace Elsa.Api.Client.Options;
/// </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; }


public Action<IHttpClientBuilder> ConfigureHttpClientBuilder { get; set; } = _ => { };
}
43 changes: 0 additions & 43 deletions src/clients/Elsa.Api.Client/Services/ElsaClient.cs

This file was deleted.

12 changes: 12 additions & 0 deletions src/clients/Elsa.Api.Client/Shared/HeaderNames.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Elsa.Api.Client.Shared;

/// <summary>
/// Contains header names used by the Elsa API.
/// </summary>
public static class HeaderNames
{
/// <summary>
/// The name of the header that contains the workflow instance ID.
/// </summary>
public const string WorkflowInstanceId = "x-elsa-workflow-instance-id";
}
3 changes: 3 additions & 0 deletions src/modules/Elsa.Http/Parsers/JsonHttpContentParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public async Task<object> ReadAsync(Stream content, Type? returnType, Cancellati

using var reader = new StreamReader(content, leaveOpen: true);
var json = await reader.ReadToEndAsync();

if(returnType == typeof(string))
return json;

if (returnType == null || returnType.IsPrimitive)
return json.ConvertTo(returnType ?? typeof(string))!;
Expand Down
4 changes: 2 additions & 2 deletions src/modules/Elsa.Http/UIHints/HttpEndpointPathUIHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public class HttpEndpointPathUIHandler(IOptions<HttpActivityOptions> options) :
public ValueTask<IDictionary<string, object>> GetUIPropertiesAsync(PropertyInfo propertyInfo, object? context, CancellationToken cancellationToken = default)
{
var baseUrl = options.Value.BaseUrl;
var apiRoutePrefix = options.Value.ApiRoutePrefix;
var completeBaseUrl = new Uri(baseUrl, apiRoutePrefix);
var basePath = options.Value.BasePath;
var completeBaseUrl = new Uri(baseUrl, basePath);

return new(new Dictionary<string, object>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,5 @@ public Task StartAsync(CancellationToken cancellationToken)
}

/// <inheritdoc />
public Task StopAsync(CancellationToken cancellationToken)
{
if(_mainThreadState != IntPtr.Zero)
{
PythonEngine.EndAllowThreads(_mainThreadState);
PythonEngine.Shutdown();
}
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
6 changes: 5 additions & 1 deletion src/modules/Elsa.Workflows.Core/Activities/SetVariable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Elsa.Workflows.Attributes;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
using Elsa.Workflows.UIHints;
using JetBrains.Annotations;

namespace Elsa.Workflows.Activities;
Expand Down Expand Up @@ -100,7 +101,10 @@ public SetVariable([CallerFilePath] string? source = default, [CallerLineNumber]
/// <inheritdoc />
protected override void Execute(ActivityExecutionContext context)
{
// Always refer to the variable by ID to ensure that the variable is resolved from the correct scope.
var variableId = Variable.Id;
var variable = context.ExpressionExecutionContext.EnumerateVariablesInScope().FirstOrDefault(x => x.Id == variableId);
var value = context.Get(Value);
context.SetVariable(Variable.Name, value);
variable?.Set(context, value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,12 @@ public static IEnumerable<Variable> EnumerateVariablesInScope(this ExpressionExe

currentScope = currentScope.ParentContext;
}

if (context.TryGetWorkflowExecutionContext(out var workflowExecutionContext))
{
if (workflowExecutionContext.Workflow.ResultVariable != null)
yield return workflowExecutionContext.Workflow.ResultVariable;
}
}

/// <summary>
Expand Down

0 comments on commit cfb3d03

Please sign in to comment.