Merge remote-tracking branch 'upstream/master' into elsa-2.0/fileactivities

This commit is contained in:
Cameron Cowen 2021-06-26 18:05:00 +01:00
commit 0a007a4ab8
23 changed files with 207 additions and 85 deletions

View file

@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations;
namespace Elsa.Activities.Webhooks.Endpoints.WebhookDefinitions
{
public sealed record SaveRequest
public sealed record SaveWebhookDefinitionRequest
{
public string? Id { get; init; }
[Required] public string Path { get; init; } = default!;

View file

@ -33,12 +33,11 @@ namespace Elsa.Activities.Webhooks.Endpoints.WebhookDefinitions
[SwaggerResponseExample(StatusCodes.Status200OK, typeof(WebhookDefinitionExample))]
[SwaggerOperation(
Summary = "Creates a new webhook definition or updates an existing one.",
Description =
"Creates a new webhook definition or updates an existing one.",
Description = "Creates a new webhook definition or updates an existing one.",
OperationId = "WebhookDefinitions.Post",
Tags = new[] { "WebhookDefinitions" })
]
public async Task<ActionResult<WebhookDefinition>> Handle([FromBody] SaveRequest request, [FromRoute] ApiVersion apiVersion, CancellationToken cancellationToken)
public async Task<ActionResult<WebhookDefinition>> Handle([FromBody] SaveWebhookDefinitionRequest request, [FromRoute] ApiVersion apiVersion, CancellationToken cancellationToken)
{
var webhookId = request.Id;
var webhookDefinition = !string.IsNullOrWhiteSpace(webhookId) ? await _store.FindAsync(new EntityIdSpecification<WebhookDefinition>(webhookId), cancellationToken) : default;

View file

@ -30,7 +30,7 @@ namespace Elsa.Activities.Webhooks.Endpoints.WebhookDefinitions
OperationId = "WebhookDefinitions.Put",
Tags = new[] { "WebhookDefinitions" })
]
public async Task<ActionResult<WebhookDefinition>> Handle([FromBody] SaveRequest request, [FromRoute] ApiVersion apiVersion, CancellationToken cancellationToken)
public async Task<ActionResult<WebhookDefinition>> Handle([FromBody] SaveWebhookDefinitionRequest request, [FromRoute] ApiVersion apiVersion, CancellationToken cancellationToken)
{
var webhookId = request.Id;
var webhookDefinition = await _store.FindAsync(new EntityIdSpecification<WebhookDefinition>(webhookId), cancellationToken);

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Elsa.Services;
@ -12,12 +12,45 @@ namespace Elsa.Builders
public interface ISetupActivity<T> : ISetupActivity where T : IActivity
{
ISetupActivity<T> Set<TProperty>(string propertyName, Func<ActivityExecutionContext, ValueTask<TProperty?>> valueFactory);
ISetupActivity<T> WithStorageFor<TProperty>(string propertyName, string? storageProviderName);
ISetupActivity<T> Set<TProperty>(Expression<Func<T, TProperty?>> propertyAccessor, Func<ActivityExecutionContext, ValueTask<TProperty?>> valueFactory);
ISetupActivity<T> WithStorageFor<TProperty>(Expression<Func<T, TProperty?>> propertyAccessor, string? storageProviderName);
}
public static class SetupActivityExtensions
{
public static ISetupActivity<T> Set<T, TProperty>(
this ISetupActivity<T> builder,
string propertyName,
Func<ActivityExecutionContext, ValueTask<TProperty?>> valueFactory) where T : IActivity =>
builder.Set(propertyName, async context => await valueFactory(context));
public static ISetupActivity<T> Set<T, TProperty>(
this ISetupActivity<T> builder,
string propertyName,
Func<ActivityExecutionContext, TProperty?> valueFactory) where T : IActivity =>
builder.Set(propertyName, context => new ValueTask<TProperty?>(valueFactory(context)));
public static ISetupActivity<T> Set<T, TProperty>(
this ISetupActivity<T> builder,
string propertyName,
Func<TProperty?> valueFactory) where T : IActivity =>
builder.Set(propertyName, context => new ValueTask<TProperty?>(valueFactory()));
public static ISetupActivity<T> Set<T, TProperty>(
this ISetupActivity<T> builder,
string propertyName,
Func<ValueTask<TProperty?>> valueFactory) where T : IActivity =>
builder.Set(propertyName, async _ => await valueFactory());
public static ISetupActivity<T> Set<T, TProperty>(
this ISetupActivity<T> builder,
string propertyName,
TProperty? value) where T : IActivity =>
builder.Set(propertyName, _ => new ValueTask<TProperty?>(value));
public static ISetupActivity<T> Set<T, TProperty>(
this ISetupActivity<T> builder,
Expression<Func<T, TProperty?>> propertyAccessor,

View file

@ -16,8 +16,16 @@ namespace Elsa
{
var item = state?.ContainsKey(key) == true ? state![key] : default;
if (item == null)
return defaultValue();
if (item == null)
{
if (state != null)
{
state.SetState(key, defaultValue());
item = state![key];
}
else
return defaultValue();
}
return item.ConvertTo<T>()!;
}

View file

@ -1,3 +1,5 @@
using System;
namespace Elsa.Metadata
{
public class ActivityDescriptor
@ -19,6 +21,12 @@ namespace Elsa.Metadata
public string Category { get; set; }
public ActivityTraits Traits { get; set; }
public string[] Outcomes { get; set; }
[Obsolete("Use InputProperties instead.")]
public ActivityInputDescriptor[] Properties
{
get => InputProperties;
set => InputProperties = value;
}
public ActivityInputDescriptor[] InputProperties { get; set; }
public ActivityOutputDescriptor[] OutputProperties { get; set; }
}

View file

@ -4,6 +4,43 @@ using System.Linq;
namespace Elsa.Metadata
{
[Obsolete("Use ActivityInputDescriptor instead.")]
public class ActivityPropertyDescriptor : ActivityInputDescriptor
{
public ActivityPropertyDescriptor() : base()
{
}
public ActivityPropertyDescriptor(
string name,
Type type,
string uiHint,
string label,
string? hint = default,
object? options = default,
string? category = default,
object? defaultValue = default,
string? defaultSyntax = "Literal",
IEnumerable<string>? supportedSyntaxes = default,
bool? isDisabled = default)
: base (
name,
type,
uiHint,
label,
hint,
options,
category,
0,
defaultValue,
defaultSyntax,
supportedSyntaxes,
isDisabled
)
{
}
}
public class ActivityInputDescriptor
{
public ActivityInputDescriptor()

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
@ -12,23 +12,27 @@ namespace Elsa.Builders
public IDictionary<string, Func<ActivityExecutionContext, ValueTask<object?>>> ValueProviders { get; } = new Dictionary<string, Func<ActivityExecutionContext, ValueTask<object?>>>();
public IDictionary<string, string> StorageProviders { get; } = new Dictionary<string, string>();
public ISetupActivity<T> Set<TProperty>(Expression<Func<T, TProperty?>> propertyAccessor, Func<ActivityExecutionContext, ValueTask<TProperty?>> valueFactory)
public ISetupActivity<T> Set<TProperty>(string propertyName, Func<ActivityExecutionContext, ValueTask<TProperty?>> valueFactory)
{
var propertyInfo = propertyAccessor.GetProperty()!;
ValueProviders[propertyInfo.Name] = async context => await valueFactory(context);
ValueProviders[propertyName] = async context => await valueFactory(context);
return this;
}
public ISetupActivity<T> WithStorageFor<TProperty>(Expression<Func<T, TProperty?>> propertyAccessor, string? storageProviderName)
public ISetupActivity<T> WithStorageFor<TProperty>(string propertyName, string? storageProviderName)
{
var propertyInfo = propertyAccessor.GetProperty()!;
if(storageProviderName != null)
StorageProviders[propertyInfo.Name] = storageProviderName;
if (storageProviderName != null)
StorageProviders[propertyName] = storageProviderName;
else
StorageProviders.Remove(propertyInfo.Name);
StorageProviders.Remove(propertyName);
return this;
}
public ISetupActivity<T> Set<TProperty>(Expression<Func<T, TProperty?>> propertyAccessor, Func<ActivityExecutionContext, ValueTask<TProperty?>> valueFactory) =>
Set(propertyAccessor.GetProperty()!.Name, valueFactory);
public ISetupActivity<T> WithStorageFor<TProperty>(Expression<Func<T, TProperty?>> propertyAccessor, string? storageProviderName) =>
WithStorageFor<T>(propertyAccessor.GetProperty()!.Name, storageProviderName);
}
}

View file

@ -62,7 +62,7 @@ namespace Elsa.Expressions
}
catch (Exception e)
{
_logger.LogWarning(e, "Failed to evaluate expression {Expression} using syntax {Syntax}", expression, syntax);
_logger.LogDebug(e, "Failed to evaluate expression {Expression} using syntax {Syntax}", expression, syntax);
throw;
}
}

View file

@ -167,7 +167,7 @@ namespace Microsoft.Extensions.DependencyInjection
.AddSingleton<IBackgroundWorker, BackgroundWorker>()
.AddScoped<IWorkflowPublisher, WorkflowPublisher>()
.AddScoped<IWorkflowContextManager, WorkflowContextManager>()
.AddTransient<IActivityTypeService, ActivityTypeService>()
.AddScoped<IActivityTypeService, ActivityTypeService>()
.AddActivityTypeProvider<TypeBasedActivityProvider>()
.AddScoped<IWorkflowExecutionLog, WorkflowExecutionLog>()
.AddTransient<ICreatesWorkflowExecutionContextForWorkflowBlueprint, WorkflowExecutionContextForWorkflowBlueprintFactory>()

View file

@ -24,13 +24,7 @@ namespace Elsa.Handlers
{
var activityExecutionContext = notification.ActivityExecutionContext;
var data = new
{
Input = notification.ActivityExecutionContext.Input,
State = activityExecutionContext.GetActivityData()
};
await WriteEntryAsync(notification.Resuming ? "Resuming" : "Executing", default, activityExecutionContext, data, cancellationToken);
await WriteEntryAsync(notification.Resuming ? "Resuming" : "Executing", default, activityExecutionContext, null, cancellationToken);
}
public async Task Handle(ActivityExecutionResultExecuted notification, CancellationToken cancellationToken)

View file

@ -49,7 +49,7 @@ export class ElsaWorkflowDesigner {
parentActivityId?: string;
parentActivityOutcome?: string;
addingActivity: boolean = false;
activityDisplayContexts: Map<ActivityDesignDisplayContext> = {};
activityDisplayContexts: Map<ActivityDesignDisplayContext> = null;
selectedActivities: Map<ActivityModel> = {};
handleContextMenuChange(state: ActivityContextMenuState) {
@ -113,6 +113,9 @@ export class ElsaWorkflowDesigner {
}
componentWillRender() {
if(!!this.activityDisplayContexts)
return;
const activityModels = this.workflowModel.activities;
const displayContexts: Map<ActivityDesignDisplayContext> = {};
const activityDescriptors: Array<ActivityDescriptor> = state.activityDescriptors;
@ -150,6 +153,7 @@ export class ElsaWorkflowDesigner {
updateWorkflowModel(model: WorkflowModel, emitEvent: boolean = true) {
this.workflowModel = this.cleanWorkflowModel(model);
this.activityDisplayContexts = null;
if (emitEvent)
this.workflowChanged.emit(model);
@ -378,9 +382,11 @@ export class ElsaWorkflowDesigner {
});
// Connections between activities and their outcomes.
const activityDisplayContexts = this.activityDisplayContexts || {};
this.workflowModel.activities.forEach(activity => {
this.graph.setNode(activity.activityId, this.createActivityOptions(activity));
const displayContext = this.activityDisplayContexts[activity.activityId] || undefined;
const displayContext = activityDisplayContexts[activity.activityId] || undefined;
const outcomes = !!displayContext ? displayContext.outcomes : activity.outcomes || [];
outcomes.forEach(outcome => {
@ -554,7 +560,8 @@ export class ElsaWorkflowDesigner {
}
renderActivity(activity: ActivityModel) {
const displayContext = this.activityDisplayContexts[activity.activityId] || undefined;
const activityDisplayContexts = this.activityDisplayContexts || {};
const displayContext = activityDisplayContexts[activity.activityId] || undefined;
const activityContextMenuButton = !!this.activityContextMenuButton ? this.activityContextMenuButton(activity) : '';
const activityBorderColor = !!this.activityBorderColor ? this.activityBorderColor(activity) : 'gray';
const selectedColor = !!this.activityBorderColor ? activityBorderColor : 'blue';

View file

@ -395,10 +395,13 @@ export class ElsaWorkflowInstanceJournal {
if (!activityModel)
return <p>No activity selected</p>;
// Hide expressions field from properties so that we only display the evaluated value.
const model = {...activityModel, properties: activityModel.properties.map(x => ({ name: x.name, value: x.value }))}
return (
<div>
<pre>{JSON.stringify(activityModel, null, 2)}</pre>
<pre>{JSON.stringify(model, null, 2)}</pre>
</div>
);
};

View file

@ -8,10 +8,12 @@ import {
ActivityModel,
Connection,
ConnectionModel,
EventTypes, SimpleException,
EventTypes,
SimpleException,
SyntaxNames,
WorkflowBlueprint,
WorkflowExecutionLogRecord, WorkflowFault,
WorkflowExecutionLogRecord,
WorkflowFault,
WorkflowInstance,
WorkflowModel,
WorkflowPersistenceBehavior,
@ -133,40 +135,46 @@ export class ElsaWorkflowInstanceViewerScreen {
updateModels(workflowInstance: WorkflowInstance, workflowBlueprint: WorkflowBlueprint) {
this.workflowInstance = workflowInstance;
this.workflowBlueprint = workflowBlueprint;
this.workflowModel = this.mapWorkflowModel(workflowBlueprint);
this.workflowModel = this.mapWorkflowModel(workflowBlueprint, workflowInstance);
}
mapWorkflowModel(workflowBlueprint: WorkflowBlueprint): WorkflowModel {
mapWorkflowModel(workflowBlueprint: WorkflowBlueprint, workflowInstance: WorkflowInstance): WorkflowModel {
const activities = workflowBlueprint.activities.filter(x => x.parentId == workflowBlueprint.id || !x.parentId).map(x => this.mapActivityModel(x, workflowInstance));
const connections = workflowBlueprint.connections.filter(c => activities.findIndex(a => a.activityId == c.sourceActivityId || a.activityId == c.targetActivityId) > -1).map(this.mapConnectionModel);
return {
activities: workflowBlueprint.activities.filter(x => x.parentId == workflowBlueprint.id || !x.parentId).map(this.mapActivityModel),
connections: workflowBlueprint.connections.map(this.mapConnectionModel),
activities: activities,
connections: connections,
persistenceBehavior: workflowBlueprint.persistenceBehavior,
};
}
mapActivityModel(source: ActivityBlueprint): ActivityModel {
mapActivityModel(activityBlueprint: ActivityBlueprint, workflowInstance: WorkflowInstance): ActivityModel {
const activityDescriptors: Array<ActivityDescriptor> = state.activityDescriptors;
const activityDescriptor = activityDescriptors.find(x => x.type == source.type);
const properties: Array<ActivityDefinitionProperty> = collection.map(source.properties.data, (value, key) => {
const propertyDescriptor = activityDescriptor.inputProperties.find(x => x.name == key);
const defaultSyntax = propertyDescriptor.defaultSyntax || SyntaxNames.Literal;
const activityDescriptor = activityDescriptors.find(x => x.type == activityBlueprint.type);
const activityData = workflowInstance.activityData[activityBlueprint.id] || {};
const properties: Array<ActivityDefinitionProperty> = collection.map(activityBlueprint.properties.data, (value, key) => {
const propertyDescriptor = activityDescriptor.inputProperties.find(x => x.name == key) || activityDescriptor.outputProperties.find(x => x.name == key);
const defaultSyntax = propertyDescriptor.defaultSyntax || SyntaxNames.Literal;
const expressions = {};
expressions[defaultSyntax] = value;
return ({name: key, expressions: expressions, syntax: defaultSyntax});
const v = activityData[key] || value;
expressions[defaultSyntax] = v;
return ({name: key, value: v, expressions: expressions, syntax: defaultSyntax});
});
return {
activityId: source.id,
description: source.description,
displayName: source.displayName || source.name || source.type,
name: source.name,
type: source.type,
activityId: activityBlueprint.id,
description: activityBlueprint.description,
displayName: activityBlueprint.displayName || activityBlueprint.name || activityBlueprint.type,
name: activityBlueprint.name,
type: activityBlueprint.type,
properties: properties,
outcomes: [...activityDescriptor.outcomes],
persistWorkflow: source.persistWorkflow,
saveWorkflowContext: source.saveWorkflowContext,
loadWorkflowContext: source.loadWorkflowContext,
propertyStorageProviders: source.propertyStorageProviders
persistWorkflow: activityBlueprint.persistWorkflow,
saveWorkflowContext: activityBlueprint.saveWorkflowContext,
loadWorkflowContext: activityBlueprint.loadWorkflowContext,
propertyStorageProviders: activityBlueprint.propertyStorageProviders
}
}
@ -242,8 +250,8 @@ export class ElsaWorkflowInstanceViewerScreen {
const workflowFault = !!workflowInstance ? workflowInstance.fault : null;
const activityData = workflowInstance.activityData[activity.activityId] || {};
const lifecycle = activityData['_Lifecycle'] || {};
const executing = !!lifecycle.Executing;
const executed = !!lifecycle.Executed;
const executing = !!lifecycle.executing;
const executed = !!lifecycle.executed;
if (!!workflowFault && workflowFault.faultedActivityId == activity.activityId)
return 'red';
@ -262,8 +270,8 @@ export class ElsaWorkflowInstanceViewerScreen {
const workflowFault = !!workflowInstance ? workflowInstance.fault : null;
const activityData = workflowInstance.activityData[activity.activityId] || {};
const lifecycle = activityData['_Lifecycle'] || {};
const executing = !!lifecycle.Executing;
const executed = !!lifecycle.Executed;
const executing = !!lifecycle.executing;
const executed = !!lifecycle.executed;
let icon: string;

View file

@ -173,6 +173,7 @@ export interface ActivityDefinitionProperty {
name: string;
syntax?: string;
expressions: Map<string>;
value?: any;
}
interface BlockingActivity {

View file

@ -15,12 +15,12 @@ export class SwitchPlugin implements ElsaPlugin {
if (activityModel.type !== 'Switch')
return;
const props = activityModel.properties || [];
const syntax = 'Switch';
const casesProp = props.find(x => x.name == 'Cases') || { expressions: {'Switch': ''}, syntax: syntax };
const expression = casesProp.expressions[syntax] || '[]';
const cases: Array<SwitchCase> = !!expression['$values'] ? expression['$values'] : parseJson(expression) || [];
const expression: any = casesProp.expressions[syntax] || [];
const cases: Array<SwitchCase> = !!expression['$values'] ? expression['$values'] : Array.isArray(expression) ? expression : parseJson(expression) || [];
context.outcomes = [...cases.map(x => x.name), 'Default'];
}
}

View file

@ -17,11 +17,10 @@
},
"Elsa": {
"Features": [
"Persistence:MongoDb",
"Persistence:EntityFrameworkCore:Sqlite",
"Console",
"Http",
"Email",
"Webhooks",
"Temporal:Quartz",
"JavaScript:Activities",
"UserTask",

View file

@ -40,7 +40,7 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
public async Task<IActionResult> Handle(string workflowDefinitionId, VersionOptions versionOptions, CancellationToken cancellationToken = default)
{
var workflowDefinition = await _workflowDefinitionStore.FindAsync(new WorkflowDefinitionIdSpecification(workflowDefinitionId).WithVersionOptions(versionOptions), cancellationToken);
return workflowDefinition == null ? (IActionResult) NotFound() : Json(workflowDefinition, _serializer.GetSettings());
return workflowDefinition == null ? NotFound() : Json(workflowDefinition, _serializer.GetSettings());
}
}
}

View file

@ -5,7 +5,7 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
{
public partial class Save
{
public sealed record SaveRequest
public sealed record SaveWorkflowDefinitionRequest
{
public string? WorkflowDefinitionId { get; init; }
public string? Name { get; init; }

View file

@ -35,7 +35,7 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
OperationId = "WorkflowDefinitions.Post",
Tags = new[] { "WorkflowDefinitions" })
]
public async Task<ActionResult<WorkflowDefinition>> Handle([FromBody]SaveRequest request, [FromRoute]ApiVersion apiVersion, CancellationToken cancellationToken)
public async Task<ActionResult<WorkflowDefinition>> Handle([FromBody]SaveWorkflowDefinitionRequest request, [FromRoute]ApiVersion apiVersion, CancellationToken cancellationToken)
{
var workflowDefinitionId = request.WorkflowDefinitionId;
var workflowDefinition = !string.IsNullOrWhiteSpace(workflowDefinitionId) ? await _workflowPublisher.GetDraftAsync(workflowDefinitionId, cancellationToken) : default;
@ -68,7 +68,7 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
return CreatedAtAction("Handle", "GetByVersionId", new { versionId = workflowDefinition.Id, apiVersion = apiVersion.ToString() }, workflowDefinition);
}
private IEnumerable<ConnectionDefinition> FilterInvalidConnections(SaveRequest request)
private IEnumerable<ConnectionDefinition> FilterInvalidConnections(SaveWorkflowDefinitionRequest request)
{
var validConnections =
from connection in request.Connections

View file

@ -48,7 +48,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.AddSingleton<ConnectionConverter>();
services.AddSingleton<ActivityBlueprintConverter>();
services.AddSingleton<IWorkflowBlueprintMapper, WorkflowBlueprintMapper>();
services.AddScoped<IWorkflowBlueprintMapper, WorkflowBlueprintMapper>();
services.AddSingleton<IEndpointContentSerializerSettingsProvider, EndpointContentSerializerSettingsProvider>();
services.AddAutoMapperProfile<AutoMapperProfile>();
return services;

View file

@ -9,13 +9,13 @@ namespace Elsa.Server.Api.Mapping
public class ActivityBlueprintConverter : ITypeConverter<IActivityBlueprint, ActivityBlueprintModel?>
{
public const string ActivityPropertiesKey = "ActivityProperties";
public ActivityBlueprintModel Convert(IActivityBlueprint source, ActivityBlueprintModel? destination, ResolutionContext context)
{
destination ??= new ActivityBlueprintModel();
destination.Id = source.Id;
destination. Name = source.Name;
destination.Name = source.Name;
destination.DisplayName = source.DisplayName;
destination.Description = source.Description;
destination.Type = source.Type;
@ -24,15 +24,15 @@ namespace Elsa.Server.Api.Mapping
destination.LoadWorkflowContext = source.LoadWorkflowContext;
destination.SaveWorkflowContext = source.SaveWorkflowContext;
destination.Properties = GetProperties(source, context);
return destination;
}
private Variables GetProperties(IActivityBlueprint activityBlueprint, ResolutionContext context)
{
if (!context.Items.ContainsKey(ActivityPropertiesKey))
if (!context.Items.ContainsKey(ActivityPropertiesKey))
return new Variables();
var dictionary = (IDictionary<string, Variables>) context.Items[ActivityPropertiesKey];
return dictionary[activityBlueprint.Id];
}

View file

@ -1,4 +1,6 @@
using System.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
@ -14,12 +16,14 @@ namespace Elsa.Server.Api.Services
public class WorkflowBlueprintMapper : IWorkflowBlueprintMapper
{
private readonly IWorkflowBlueprintReflector _workflowBlueprintReflector;
private readonly IActivityTypeService _activityTypeService;
private readonly IMapper _mapper;
private readonly IServiceScopeFactory _serviceScopeFactory;
public WorkflowBlueprintMapper(IWorkflowBlueprintReflector workflowBlueprintReflector, IMapper mapper, IServiceScopeFactory serviceScopeFactory)
public WorkflowBlueprintMapper(IWorkflowBlueprintReflector workflowBlueprintReflector, IActivityTypeService activityTypeService, IMapper mapper, IServiceScopeFactory serviceScopeFactory)
{
_workflowBlueprintReflector = workflowBlueprintReflector;
_activityTypeService = activityTypeService;
_mapper = mapper;
_serviceScopeFactory = serviceScopeFactory;
}
@ -36,23 +40,40 @@ namespace Elsa.Server.Api.Services
private async ValueTask<Variables> GetActivityPropertiesAsync(IWorkflowBlueprintWrapper workflowBlueprintWrapper, IActivityBlueprintWrapper activityBlueprintWrapper, CancellationToken cancellationToken)
{
var workflowBlueprint = workflowBlueprintWrapper.WorkflowBlueprint;
var activityBlueprint = activityBlueprintWrapper.ActivityBlueprint;
var activityType = await _activityTypeService.GetActivityTypeAsync(activityBlueprint.Type, cancellationToken);
var activityDescriptor = await _activityTypeService.DescribeActivityType(activityType, cancellationToken);
var activityId = activityBlueprint.Id;
var activityPropertyValueProviders = workflowBlueprint.ActivityPropertyProviders.GetProviders(activityId);
var activityWrapper = workflowBlueprintWrapper.GetActivity(activityId)!;
var properties = new Variables();
if (activityPropertyValueProviders == null)
return properties;
foreach (var valueProvider in activityPropertyValueProviders)
foreach (var property in activityDescriptor.InputProperties)
{
var value = await activityWrapper.EvaluatePropertyValueAsync(valueProvider.Key, cancellationToken);
properties.Set(valueProvider.Key, value);
var value = await TryEvaluatePropertyAsync(activityWrapper, property.Name, cancellationToken);
properties.Set(property.Name, value);
}
foreach (var property in activityDescriptor.OutputProperties)
{
// Declare output properties to have at least a complete schema.
properties.Set(property.Name, null);
}
return properties;
}
private async Task<object?> TryEvaluatePropertyAsync(IActivityBlueprintWrapper activityWrapper, string propertyName, CancellationToken cancellationToken)
{
try
{
return await activityWrapper.EvaluatePropertyValueAsync(propertyName, cancellationToken);
}
catch
{
// ignored
}
return null;
}
}
}