diff --git a/src/core/Elsa.Core/Activities/Break.cs b/src/core/Elsa.Core/Activities/Break.cs new file mode 100644 index 000000000..8a99b64dc --- /dev/null +++ b/src/core/Elsa.Core/Activities/Break.cs @@ -0,0 +1,10 @@ +using Elsa.Attributes; +using Elsa.Models; + +namespace Elsa.Activities; + +[Activity("Elsa", "Control Flow", "Break out of a loop")] +public class Break : Activity +{ + // TODO. +} \ No newline at end of file diff --git a/src/core/Elsa.Core/Activities/Finish.cs b/src/core/Elsa.Core/Activities/Finish.cs new file mode 100644 index 000000000..797160e38 --- /dev/null +++ b/src/core/Elsa.Core/Activities/Finish.cs @@ -0,0 +1,10 @@ +using Elsa.Attributes; +using Elsa.Models; + +namespace Elsa.Activities; + +[Activity("Elsa", "Control Flow", "Mark the workflow as Finished")] +public class Finish : Activity +{ + // TODO. +} \ No newline at end of file diff --git a/src/core/Elsa.Core/Activities/ForEach.cs b/src/core/Elsa.Core/Activities/ForEach.cs index 8a5d807fc..adc82a415 100644 --- a/src/core/Elsa.Core/Activities/ForEach.cs +++ b/src/core/Elsa.Core/Activities/ForEach.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using Elsa.Attributes; using Elsa.Contracts; using Elsa.Models; @@ -60,6 +61,20 @@ public class ForEach : Activity public class ForEach : ForEach { + [JsonConstructor] + public ForEach() + { + } + + public ForEach(Input> items) + { + Items = items; + } + + public ForEach(ICollection items) : this(new Input>(items)) + { + } + [Input] public new Input> Items { diff --git a/src/core/Elsa.Core/Activities/Switch.cs b/src/core/Elsa.Core/Activities/Switch.cs index 7cc73f76e..5ff51c75b 100644 --- a/src/core/Elsa.Core/Activities/Switch.cs +++ b/src/core/Elsa.Core/Activities/Switch.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using Elsa.Attributes; using Elsa.Contracts; using Elsa.Expressions; @@ -33,7 +34,7 @@ public class Switch : Activity private async Task FindMatchingCaseAsync(ExpressionExecutionContext context) { var expressionEvaluator = context.GetRequiredService(); - + foreach (var switchCase in Cases) { var result = await expressionEvaluator.EvaluateAsync(switchCase.Condition, context); @@ -51,11 +52,38 @@ public class Switch : Activity /// public class SwitchCase { - // ReSharper disable once EmptyConstructor + [JsonConstructor] public SwitchCase() { } + public SwitchCase(string label, IExpression condition, IActivity activity) + { + Label = label; + Condition = condition; + Activity = activity; + } + + public SwitchCase(string label, DelegateReference condition, IActivity activity) : this(label, new DelegateExpression(condition), activity) + { + } + + public SwitchCase(string label, Func> condition, IActivity activity) : this(label, new DelegateReference(condition), activity) + { + } + + public SwitchCase(string label, Func> condition, IActivity activity) : this(label, new DelegateReference(condition), activity) + { + } + + public SwitchCase(string label, Func condition, IActivity activity) : this(label, new DelegateReference(condition), activity) + { + } + + public SwitchCase(string label, Func condition, IActivity activity) : this(label, new DelegateReference(condition), activity) + { + } + public string Label { get; set; } = default!; public IExpression Condition { get; set; } = new LiteralExpression(false); public IActivity? Activity { get; set; } diff --git a/src/modules/Elsa.Modules.Scheduling/Activities/RunAt.cs b/src/modules/Elsa.Modules.Scheduling/Activities/RunAt.cs new file mode 100644 index 000000000..9aa7a81d2 --- /dev/null +++ b/src/modules/Elsa.Modules.Scheduling/Activities/RunAt.cs @@ -0,0 +1,64 @@ +using System; +using System.Threading.Tasks; +using Elsa.Attributes; +using Elsa.Contracts; +using Elsa.Models; +using Microsoft.Extensions.Logging; + +namespace Elsa.Modules.Scheduling.Activities; + +[Activity("Elsa", "Scheduling", "Delay execution for the specified amount of time.")] +public class RunAt : Activity +{ + public RunAt() + { + } + + public RunAt(Input dateTime) => DateTime = dateTime; + + public RunAt(Func dateTime) : this(new Input(dateTime)) + { + } + + public RunAt(Func> dateTime) : this(new Input(dateTime)) + { + } + + public RunAt(Func> dateTime) : this(new Input(dateTime)) + { + } + + public RunAt(Func dateTime) : this(new Input(dateTime)) + { + } + + public RunAt(DateTimeOffset dateTime) => DateTime = new Input(dateTime); + public RunAt(Variable dateTime) => DateTime = new Input(dateTime); + + [Input] public Input DateTime { get; set; } = default!; + + protected override void Execute(ActivityExecutionContext context) + { + // TODO: Update e.g. ScheduleWorkflows and other places to make sure this activity works correctly when suspending & resuming workflows. + + var executeAt = context.ExpressionExecutionContext.Get(DateTime); + var clock = context.ExpressionExecutionContext.GetRequiredService(); + var now = clock.UtcNow; + var logger = context.GetRequiredService>(); + + if (executeAt <= now) + { + logger.LogDebug("Scheduled trigger time lies in the past ('{Delta}'). Skipping scheduling", now - executeAt); + context.JournalData.Add("Executed At", now); + return; + } + + var payload = new RunAtPayload(executeAt); + + context.CreateBookmark(payload); + } + + public static RunAt From(DateTimeOffset value) => new(value); +} + +public record RunAtPayload(DateTimeOffset ResumeAt); \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Scheduling/Elsa.Modules.Scheduling.csproj b/src/modules/Elsa.Modules.Scheduling/Elsa.Modules.Scheduling.csproj index e8f0fbcec..18211728a 100644 --- a/src/modules/Elsa.Modules.Scheduling/Elsa.Modules.Scheduling.csproj +++ b/src/modules/Elsa.Modules.Scheduling/Elsa.Modules.Scheduling.csproj @@ -10,8 +10,4 @@ - - - -