Merge remote-tracking branch 'upstream/master' into elsa-2.0/fileactivities
This commit is contained in:
commit
0a007a4ab8
|
|
@ -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!;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>()!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ export interface ActivityDefinitionProperty {
|
|||
name: string;
|
||||
syntax?: string;
|
||||
expressions: Map<string>;
|
||||
value?: any;
|
||||
}
|
||||
|
||||
interface BlockingActivity {
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,10 @@
|
|||
},
|
||||
"Elsa": {
|
||||
"Features": [
|
||||
"Persistence:MongoDb",
|
||||
"Persistence:EntityFrameworkCore:Sqlite",
|
||||
"Console",
|
||||
"Http",
|
||||
"Email",
|
||||
"Webhooks",
|
||||
"Temporal:Quartz",
|
||||
"JavaScript:Activities",
|
||||
"UserTask",
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue