Configure control flow activities
This commit is contained in:
parent
299b871c50
commit
cebb57caaa
|
|
@ -3,6 +3,8 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Design;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
|
@ -17,25 +19,30 @@ namespace Elsa.Activities.ControlFlow
|
|||
)]
|
||||
public class Finish : Activity
|
||||
{
|
||||
[ActivityProperty(Hint = "The value to set as the workflow's output")]
|
||||
[ActivityProperty(Hint = "The value to set as the workflow's output", SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public object? OutputValue { get; set; }
|
||||
|
||||
[ActivityProperty(Hint = "The outcomes to set on the container activity")]
|
||||
[ActivityProperty(
|
||||
Hint = "The outcomes to set on the container activity",
|
||||
UIHint = ActivityPropertyUIHints.MultiText,
|
||||
DefaultValue = Elsa.OutcomeNames.Done,
|
||||
DefaultSyntax = SyntaxNames.Json,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Json, SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public IEnumerable<string> OutcomeNames { get; set; } = new[] { Elsa.OutcomeNames.Done };
|
||||
|
||||
protected override async ValueTask<IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context)
|
||||
{
|
||||
var parentBlueprint = context.ActivityBlueprint.Parent;
|
||||
|
||||
|
||||
// Remove any blocking activities within the scope of the composite activity.
|
||||
var blockingActivities = context.WorkflowExecutionContext.WorkflowInstance.BlockingActivities;
|
||||
var blockingActivityIds = blockingActivities.Select(x => x.ActivityId).ToList();
|
||||
var containedBlockingActivityIds = parentBlueprint == null ? blockingActivityIds : parentBlueprint.Activities.Where(x => blockingActivityIds.Contains(x.Id)).Select(x => x.Id).ToList();
|
||||
var containedBlockingActivities = blockingActivities.Where(x => containedBlockingActivityIds.Contains(x.ActivityId));
|
||||
|
||||
foreach (var blockingActivity in containedBlockingActivities)
|
||||
|
||||
foreach (var blockingActivity in containedBlockingActivities)
|
||||
await context.WorkflowExecutionContext.RemoveBlockingActivityAsync(blockingActivity);
|
||||
|
||||
|
||||
// Evict & remove any scope activities within the scope of the composite activity.
|
||||
var scopes = context.WorkflowInstance.Scopes.Select(x => x).Reverse().ToList();
|
||||
var scopeIds = scopes.Select(x => x.ActivityId).ToList();
|
||||
|
|
@ -47,9 +54,9 @@ namespace Elsa.Activities.ControlFlow
|
|||
await context.WorkflowExecutionContext.EvictScopeAsync(scopeActivity);
|
||||
scopes.RemoveAll(x => x.ActivityId == scopeId);
|
||||
}
|
||||
|
||||
|
||||
context.WorkflowInstance.Scopes = new SimpleStack<ActivityScope>(scopes.AsEnumerable().Reverse());
|
||||
|
||||
|
||||
// Return output.
|
||||
var output = new FinishOutput(OutputValue, OutcomeNames);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
|
|
@ -14,16 +15,16 @@ namespace Elsa.Activities.ControlFlow
|
|||
)]
|
||||
public class For : Activity
|
||||
{
|
||||
[ActivityProperty(Hint = "The starting number.")]
|
||||
[ActivityProperty(Hint = "The starting number.", SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public long Start { get; set; }
|
||||
|
||||
[ActivityProperty(Hint = "The ending number.")]
|
||||
[ActivityProperty(Hint = "The ending number.", SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public long End { get; set; }
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the incrementing number on each step.")]
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the incrementing number on each step.", SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public long Step { get; set; } = 1;
|
||||
|
||||
[ActivityProperty(Hint = "The operator to use when comparing the current value against the end value.")]
|
||||
[ActivityProperty(Hint = "The operator to use when comparing the current value against the end value.", SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public Operator Operator { get; set; } = Operator.LessThan;
|
||||
|
||||
internal long? CurrentValue
|
||||
|
|
@ -46,9 +47,9 @@ namespace Elsa.Activities.ControlFlow
|
|||
Break = false;
|
||||
return Done();
|
||||
}
|
||||
|
||||
|
||||
var currentValue = CurrentValue ?? Start;
|
||||
|
||||
|
||||
var loop = Operator switch
|
||||
{
|
||||
Operator.LessThan => currentValue < End,
|
||||
|
|
@ -62,7 +63,7 @@ namespace Elsa.Activities.ControlFlow
|
|||
{
|
||||
CurrentValue = currentValue + Step;
|
||||
var scope = context.CreateScope();
|
||||
|
||||
|
||||
scope.Variables.Set(nameof(CurrentValue), currentValue);
|
||||
return Outcome(OutcomeNames.Iterate, currentValue);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ using System.Collections.ObjectModel;
|
|||
using System.Linq;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Design;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
|
|
@ -16,21 +18,26 @@ namespace Elsa.Activities.ControlFlow
|
|||
)]
|
||||
public class ForEach : Activity
|
||||
{
|
||||
[ActivityProperty(Hint = "A collection of items to iterate over.")]
|
||||
[ActivityProperty(
|
||||
Hint = "A collection of items to iterate over.",
|
||||
UIHint = ActivityPropertyUIHints.MultiLine,
|
||||
DefaultSyntax = SyntaxNames.Json,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Json, SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public ICollection<object> Items { get; set; } = new Collection<object>();
|
||||
|
||||
|
||||
private int? CurrentIndex
|
||||
{
|
||||
get => GetState<int?>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
|
||||
private bool Break
|
||||
{
|
||||
get => GetState<bool>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
|
||||
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
|
||||
{
|
||||
if (Break)
|
||||
|
|
@ -39,7 +46,7 @@ namespace Elsa.Activities.ControlFlow
|
|||
Break = false;
|
||||
return Done();
|
||||
}
|
||||
|
||||
|
||||
var collection = Items.ToList();
|
||||
var currentIndex = CurrentIndex ?? 0;
|
||||
|
||||
|
|
@ -50,7 +57,7 @@ namespace Elsa.Activities.ControlFlow
|
|||
|
||||
scope.Variables.Set("CurrentIndex", currentIndex);
|
||||
scope.Variables.Set("CurrentValue", currentValue);
|
||||
|
||||
|
||||
CurrentIndex = currentIndex + 1;
|
||||
return Combine(Outcome(OutcomeNames.Iterate, currentValue));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Elsa.ActivityResults;
|
|||
using Elsa.Attributes;
|
||||
using Elsa.Design;
|
||||
using Elsa.Events;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
|
@ -19,8 +20,11 @@ namespace Elsa.Activities.ControlFlow
|
|||
public class Fork : Activity
|
||||
{
|
||||
[ActivityProperty(
|
||||
Hint = "Enter one or more branch names.",
|
||||
UIHint = ActivityPropertyUIHints.MultiText,
|
||||
Hint = "Enter one or more branch names.")]
|
||||
DefaultSyntax = SyntaxNames.Json,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Json }
|
||||
)]
|
||||
public ISet<string> Branches { get; set; } = new HashSet<string>();
|
||||
|
||||
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) => Outcomes(Branches);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Elsa.ActivityResults;
|
|||
using Elsa.Attributes;
|
||||
using Elsa.Design;
|
||||
using Elsa.Events;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using MediatR;
|
||||
|
|
@ -23,7 +24,7 @@ namespace Elsa.Activities.ControlFlow
|
|||
public const string True = "True";
|
||||
public const string False = "False";
|
||||
|
||||
[ActivityProperty(Hint = "The condition to evaluate.", UIHint = ActivityPropertyUIHints.SingleLine)]
|
||||
[ActivityProperty(Hint = "The condition to evaluate.", UIHint = ActivityPropertyUIHints.SingleLine, SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public bool Condition { get; set; }
|
||||
|
||||
public bool EnteredScope
|
||||
|
|
@ -54,12 +55,12 @@ namespace Elsa.Activities.ControlFlow
|
|||
|
||||
public Task Handle(ScopeEvicted notification, CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.EvictedScope.Type != nameof(If))
|
||||
if (notification.EvictedScope.Type != nameof(If))
|
||||
return Task.CompletedTask;
|
||||
|
||||
|
||||
var data = notification.WorkflowExecutionContext.WorkflowInstance.ActivityData.GetItem(notification.EvictedScope.Id, () => new JObject());
|
||||
data.SetState(nameof(EnteredScope), false);
|
||||
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Elsa.ActivityResults;
|
|||
using Elsa.Attributes;
|
||||
using Elsa.Design;
|
||||
using Elsa.Events;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
|
@ -39,7 +40,8 @@ namespace Elsa.Activities.ControlFlow
|
|||
[ActivityProperty(
|
||||
UIHint = ActivityPropertyUIHints.Dropdown,
|
||||
Hint = "WaitAll: wait for all incoming activities to have executed. WaitAny: continue execution as soon as any of the incoming activity has executed.",
|
||||
Options = new[] { "WaitAll", "WaitAny" }
|
||||
Options = new[] { "WaitAll", "WaitAny" },
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public JoinMode Mode { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ using System.Collections.ObjectModel;
|
|||
using System.Linq;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Design;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
|
|
@ -16,7 +18,12 @@ namespace Elsa.Activities.ControlFlow
|
|||
)]
|
||||
public class ParallelForEach : Activity
|
||||
{
|
||||
[ActivityProperty(Hint = "A collection of items to iterate over.")]
|
||||
[ActivityProperty(
|
||||
Hint = "A collection of items to iterate over.",
|
||||
UIHint = ActivityPropertyUIHints.MultiLine,
|
||||
DefaultSyntax = SyntaxNames.Json,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Json, SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public ICollection<object> Items { get; set; } = new Collection<object>();
|
||||
|
||||
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
|||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Events;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using MediatR;
|
||||
|
|
@ -24,9 +25,13 @@ namespace Elsa.Activities.ControlFlow
|
|||
[ActivityProperty(Hint = "The conditions to evaluate.")]
|
||||
public ICollection<SwitchCase> Cases { get; set; } = new List<SwitchCase>();
|
||||
|
||||
[ActivityProperty(Hint = "The conditions to evaluate.")]
|
||||
[ActivityProperty(
|
||||
Hint = "The switch mode determines whether the first match should be scheduled, or all matches.",
|
||||
DefaultValue = SwitchMode.MatchFirst,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public SwitchMode Mode { get; set; } = SwitchMode.MatchFirst;
|
||||
|
||||
|
||||
public bool EnteredScope
|
||||
{
|
||||
get => GetState<bool>();
|
||||
|
|
@ -48,23 +53,23 @@ namespace Elsa.Activities.ControlFlow
|
|||
return Done();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var matches = Cases.Where(x => x.Condition).Select(x => x.Name).ToList();
|
||||
var results = Mode == SwitchMode.MatchFirst ? matches.Any() ? new[] { matches.First() } : new string[0] : matches.ToArray();
|
||||
var outcomes = results;
|
||||
|
||||
|
||||
return Outcomes(outcomes);
|
||||
}
|
||||
|
||||
Task INotificationHandler<ScopeEvicted>.Handle(ScopeEvicted notification, CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.EvictedScope.Type != nameof(Switch))
|
||||
if (notification.EvictedScope.Type != nameof(Switch))
|
||||
return Task.CompletedTask;
|
||||
|
||||
|
||||
var data = notification.WorkflowExecutionContext.WorkflowInstance.ActivityData.GetItem(notification.EvictedScope.Id, () => new JObject());
|
||||
data.SetState(nameof(EnteredScope), false);
|
||||
data.SetState("Unwinding", false);
|
||||
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Design;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
|
|
@ -14,9 +15,13 @@ namespace Elsa.Activities.ControlFlow
|
|||
)]
|
||||
public class While : Activity
|
||||
{
|
||||
[ActivityProperty(Hint = "The condition to evaluate.", UIHint = ActivityPropertyUIHints.SingleLine)]
|
||||
[ActivityProperty(
|
||||
Hint = "The condition to evaluate.",
|
||||
UIHint = ActivityPropertyUIHints.SingleLine,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
)]
|
||||
public bool Condition { get; set; }
|
||||
|
||||
|
||||
private bool Break
|
||||
{
|
||||
get => GetState<bool>();
|
||||
|
|
@ -30,12 +35,12 @@ namespace Elsa.Activities.ControlFlow
|
|||
Break = false;
|
||||
return Done();
|
||||
}
|
||||
|
||||
|
||||
var loop = Condition;
|
||||
|
||||
if (!loop)
|
||||
if (!loop)
|
||||
return Done();
|
||||
|
||||
|
||||
context.CreateScope();
|
||||
return Outcome(OutcomeNames.Iterate);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue