Refactored Switch Activity (#545)
* Add IfThen activity + sample * Add match mode * Rename IfThen to Switch
This commit is contained in:
parent
460c75227d
commit
993e08ea89
7
Elsa.sln
7
Elsa.sln
|
|
@ -193,6 +193,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "server", "server", "{BBCFC6
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.Server.Host", "src\samples\server\Elsa.Samples.Server.Host\Elsa.Samples.Server.Host.csproj", "{63E52936-6C1D-4F45-8B56-86C23E9A853F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.SwitchConsole", "src\samples\console\Elsa.Samples.SwitchConsole\Elsa.Samples.SwitchConsole.csproj", "{D6DD6E38-BB34-4B2F-9A42-4C17AF30C9CD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -459,6 +461,10 @@ Global
|
|||
{63E52936-6C1D-4F45-8B56-86C23E9A853F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{63E52936-6C1D-4F45-8B56-86C23E9A853F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63E52936-6C1D-4F45-8B56-86C23E9A853F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6DD6E38-BB34-4B2F-9A42-4C17AF30C9CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6DD6E38-BB34-4B2F-9A42-4C17AF30C9CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6DD6E38-BB34-4B2F-9A42-4C17AF30C9CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6DD6E38-BB34-4B2F-9A42-4C17AF30C9CD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -549,6 +555,7 @@ Global
|
|||
{3CF1D3EA-7D93-44B0-80A2-77983A5357BA} = {4673732F-2853-47BD-91B8-C95C229D2C89}
|
||||
{BBCFC623-2113-464D-8A1F-3CCDABF1241C} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
|
||||
{63E52936-6C1D-4F45-8B56-86C23E9A853F} = {BBCFC623-2113-464D-8A1F-3CCDABF1241C}
|
||||
{D6DD6E38-BB34-4B2F-9A42-4C17AF30C9CD} = {FC9F520F-BA51-4AD2-BFEE-EF787798E734}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ namespace Elsa.Activities.Timers.HostedServices
|
|||
var workflow = runAtWorkflow.workflow;
|
||||
var activity = runAtWorkflow.activity;
|
||||
var workflowWrapper = await _workflowBlueprintReflector.ReflectAsync(serviceScope, workflow, cancellationToken);
|
||||
var timerWrapper = workflowWrapper.GetActivity<StartAt>(activity.Id);
|
||||
var timerWrapper = workflowWrapper.GetActivity<StartAt>(activity.Id)!;
|
||||
var startAt = await timerWrapper.GetPropertyValueAsync(x => x.Instant, cancellationToken);
|
||||
|
||||
await _workflowScheduler.ScheduleWorkflowAsync(workflow, activity.Id, startAt, cancellationToken);
|
||||
|
|
@ -91,7 +91,7 @@ namespace Elsa.Activities.Timers.HostedServices
|
|||
var workflow = timerWorkflow.workflow;
|
||||
var activity = timerWorkflow.activity;
|
||||
var workflowWrapper = await _workflowBlueprintReflector.ReflectAsync(serviceScope, workflow, cancellationToken);
|
||||
var timerEventWrapper = workflowWrapper.GetActivity<Timer>(activity.Id);
|
||||
var timerEventWrapper = workflowWrapper.GetActivity<Timer>(activity.Id)!;
|
||||
var timeOut = await timerEventWrapper.GetPropertyValueAsync(x => x.Timeout, cancellationToken);
|
||||
var startAt = now.Plus(timeOut);
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ namespace Elsa.Activities.Timers.HostedServices
|
|||
var workflow = cronWorkflow.workflow;
|
||||
var activity = cronWorkflow.activity;
|
||||
var workflowWrapper = await _workflowBlueprintReflector.ReflectAsync(serviceScope, workflow, cancellationToken);
|
||||
var timerEventWrapper = workflowWrapper.GetActivity<Cron>(activity.Id);
|
||||
var timerEventWrapper = workflowWrapper.GetActivity<Cron>(activity.Id)!;
|
||||
var cronExpression = await timerEventWrapper.GetPropertyValueAsync(x => x.CronExpression, cancellationToken);
|
||||
|
||||
await _workflowScheduler.ScheduleWorkflowAsync(workflow, activity.Id, cronExpression!, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,5 @@ namespace Elsa.Client.Models
|
|||
/// </summary>
|
||||
[DataMember(Order = 11)]
|
||||
public Variables CustomAttributes { get; set;} = new();
|
||||
|
||||
[DataMember(Order = 12)] public string? DisplayName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -16,14 +16,14 @@ namespace Elsa.ActivityResults
|
|||
|
||||
Outcomes = outcomeList;
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<string> Outcomes { get; }
|
||||
|
||||
protected override void Execute(ActivityExecutionContext activityExecutionContext)
|
||||
{
|
||||
var outcomes = activityExecutionContext.Outcomes = Outcomes.ToList();
|
||||
var workflowExecutionContext = activityExecutionContext.WorkflowExecutionContext;
|
||||
|
||||
|
||||
var nextActivities = GetNextActivities(
|
||||
workflowExecutionContext,
|
||||
activityExecutionContext.ActivityBlueprint.Id,
|
||||
|
|
@ -37,14 +37,17 @@ namespace Elsa.ActivityResults
|
|||
string sourceId,
|
||||
IEnumerable<string> outcomes)
|
||||
{
|
||||
var orderedOutcomes = outcomes.Select((outcome, order) => (outcome, order));
|
||||
|
||||
var query =
|
||||
from connection in workflowContext.WorkflowBlueprint.Connections
|
||||
from outcome in outcomes
|
||||
from outcome in orderedOutcomes
|
||||
let connectionOutcome = connection.Source.Outcome ?? OutcomeNames.Done
|
||||
let isConnectionOutcome = connectionOutcome.Equals(outcome, StringComparison.OrdinalIgnoreCase)
|
||||
let isConnectionOutcome = connectionOutcome.Equals(outcome.outcome, StringComparison.OrdinalIgnoreCase)
|
||||
where connection.Source.Activity.Id == sourceId && isConnectionOutcome
|
||||
from activityBlueprint in workflowContext.WorkflowBlueprint.Activities
|
||||
where activityBlueprint.Id == connection.Target.Activity.Id
|
||||
orderby outcome.order
|
||||
select activityBlueprint.Id;
|
||||
|
||||
return query.Distinct();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Elsa.Core")]
|
||||
[assembly: InternalsVisibleTo("Elsa.Core")]
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ namespace Elsa.Builders
|
|||
this ISetupActivity<T> builder,
|
||||
Expression<Func<T, TProperty?>> propertyAccessor,
|
||||
Func<ActivityExecutionContext, TProperty?> valueFactory) where T : IActivity =>
|
||||
builder.Set(propertyAccessor, context => new ValueTask<TProperty>(valueFactory(context)));
|
||||
builder.Set(propertyAccessor, context => new ValueTask<TProperty?>(valueFactory(context)));
|
||||
|
||||
public static ISetupActivity<T> Set<T, TProperty>(
|
||||
this ISetupActivity<T> builder,
|
||||
Expression<Func<T, TProperty?>> propertyAccessor,
|
||||
Func<TProperty?> valueFactory) where T : IActivity =>
|
||||
builder.Set(propertyAccessor, context => new ValueTask<TProperty>(valueFactory()));
|
||||
builder.Set(propertyAccessor, context => new ValueTask<TProperty?>(valueFactory()));
|
||||
|
||||
public static ISetupActivity<T> Set<T, TProperty>(
|
||||
this ISetupActivity<T> builder,
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ namespace Elsa.Builders
|
|||
bool DeleteCompletedInstances { get; }
|
||||
bool IsEnabled { get; }
|
||||
IWorkflowBuilder WithWorkflowDefinitionId(string value);
|
||||
IWorkflowBuilder WithDisplayName(string value);
|
||||
IWorkflowBuilder WithDescription(string value);
|
||||
IWorkflowBuilder WithVersion(int value);
|
||||
IWorkflowBuilder AsSingleton();
|
||||
IWorkflowBuilder AsTransient();
|
||||
|
|
|
|||
27
src/core/Elsa.Abstractions/Extensions/ObjectConverter.cs
Normal file
27
src/core/Elsa.Abstractions/Extensions/ObjectConverter.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System.ComponentModel;
|
||||
using NodaTime;
|
||||
using NodaTime.Text;
|
||||
|
||||
namespace Elsa
|
||||
{
|
||||
public static class ObjectConverter
|
||||
{
|
||||
public static T? ConvertTo<T>(this object? value)
|
||||
{
|
||||
if (value == null)
|
||||
return default!;
|
||||
|
||||
if (value is T convertedValue)
|
||||
return convertedValue;
|
||||
|
||||
if (value == default!)
|
||||
return default!;
|
||||
|
||||
if (typeof(T) == typeof(Duration))
|
||||
return (T?)((object?)DurationPattern.JsonRoundtrip.Parse(value!.ToString()).Value)!;
|
||||
|
||||
var converter = TypeDescriptor.GetConverter(typeof(T));
|
||||
return converter.CanConvertFrom(value.GetType()) ? (T?) converter.ConvertFrom(value) : default;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/core/Elsa.Abstractions/IsExternalInit.cs
Normal file
17
src/core/Elsa.Abstractions/IsExternalInit.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved to be used by the compiler for tracking metadata.
|
||||
/// This class should not be used by developers in source code.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal static class IsExternalInit
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -21,19 +21,7 @@ namespace Elsa.Models
|
|||
public IDictionary<string, object?> Data { get; set; }
|
||||
|
||||
public object? Get(string name) => Has(name) ? Data[name] : default;
|
||||
|
||||
public T Get<T>(string name)
|
||||
{
|
||||
if (!Has(name))
|
||||
return default!;
|
||||
|
||||
var value = Get(name);
|
||||
|
||||
if (value == null)
|
||||
return default!;
|
||||
|
||||
return (T)value!;
|
||||
}
|
||||
public T? Get<T>(string name) => !Has(name) ? default : Get(name).ConvertTo<T>();
|
||||
|
||||
public Variables Set(string name, object? value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ namespace Elsa.Services.Models
|
|||
return await activityTypeService.ActivateActivityAsync(ActivityBlueprint, cancellationToken);
|
||||
}
|
||||
|
||||
public T GetInput<T>() => (T) Input!;
|
||||
public T? GetInput<T>() => Input.ConvertTo<T>();
|
||||
public object? GetOutputFrom(string activityName) => WorkflowExecutionContext.GetOutputFrom(activityName);
|
||||
public T GetOutputFrom<T>(string activityName) => (T) GetOutputFrom(activityName)!;
|
||||
public void SetWorkflowContext(object? value) => WorkflowExecutionContext.SetWorkflowContext(value);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ namespace Elsa.Services.Models
|
|||
string? TenantId { get; }
|
||||
bool IsSingleton { get; }
|
||||
bool IsEnabled { get; }
|
||||
string? Description { get; }
|
||||
bool IsPublished { get; }
|
||||
bool IsLatest { get; }
|
||||
|
||||
|
|
|
|||
34
src/core/Elsa.Core/Activities/ControlFlow/IfThen/Switch.cs
Normal file
34
src/core/Elsa.Core/Activities/ControlFlow/IfThen/Switch.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
[ActivityAttribute(
|
||||
DisplayName = "Switch",
|
||||
Category = "Control Flow",
|
||||
Description = "Evaluate multiple conditions and continue execution depending on the results.",
|
||||
Outcomes = new[] { OutcomeNames.Done }
|
||||
)]
|
||||
public class Switch : Activity
|
||||
{
|
||||
[ActivityProperty(Hint = "The conditions to evaluate.")]
|
||||
public ICollection<SwitchCase> Cases { get; set; } = new List<SwitchCase>();
|
||||
|
||||
[ActivityProperty(Hint = "The conditions to evaluate.")]
|
||||
public SwitchMode Mode { get; set; } = SwitchMode.MatchFirst;
|
||||
|
||||
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
|
||||
{
|
||||
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 = new[] { OutcomeNames.Done }.Concat(results);
|
||||
return Outcomes(outcomes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
public static class SwitchBuilderExtensions
|
||||
{
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Action<ISetupActivity<Switch>>? setup = default, Action<IActivityBuilder>? activity = default)
|
||||
{
|
||||
var activityBuilder = builder.Then(setup);
|
||||
activity?.Invoke(activityBuilder);
|
||||
return activityBuilder;
|
||||
}
|
||||
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Func<ActivityExecutionContext, ValueTask<ICollection<SwitchCase>>> cases, SwitchMode mode, Action<IActivityBuilder>? activity = default) => builder.Switch(x => x.WithCases(cases).WithMode(mode), activity);
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Func<ActivityExecutionContext, ValueTask<ICollection<SwitchCase>>> cases, Action<IActivityBuilder>? activity = default) => builder.Switch(x => x.WithCases(cases), activity);
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Func<ActivityExecutionContext, ICollection<SwitchCase>> cases, SwitchMode mode, Action<IActivityBuilder>? activity = default) => builder.Switch(x => x.WithCases(cases).WithMode(mode), activity);
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Func<ActivityExecutionContext, ICollection<SwitchCase>> cases, Action<IActivityBuilder>? activity = default) => builder.Switch(x => x.WithCases(cases), activity);
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Func<ICollection<SwitchCase>> cases, SwitchMode mode, Action<IActivityBuilder>? activity = default) => builder.Switch(x => x.WithCases(cases).WithMode(mode), activity);
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Func<ICollection<SwitchCase>> cases, Action<IActivityBuilder>? activity = default) => builder.Switch(x => x.WithCases(cases), activity);
|
||||
public static IActivityBuilder Switch(this IBuilder builder, ICollection<SwitchCase> cases, SwitchMode mode, Action<IActivityBuilder>? activity = default) => builder.Switch(x => x.WithCases(cases).WithMode(mode), activity);
|
||||
public static IActivityBuilder Switch(this IBuilder builder, ICollection<SwitchCase> cases, Action<IActivityBuilder>? activity = default) => builder.Switch(x => x.WithCases(cases), activity);
|
||||
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Action<SwitchCaseBuilder> cases, Action<IActivityBuilder>? activity = default) => builder.Switch(cases, SwitchMode.MatchFirst, activity);
|
||||
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Action<SwitchCaseBuilder> cases, SwitchMode mode, Action<IActivityBuilder>? activity = default)
|
||||
{
|
||||
return builder.Switch(x =>
|
||||
{
|
||||
cases(x);
|
||||
return new ValueTask();
|
||||
}, mode, activity);
|
||||
}
|
||||
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Func<SwitchCaseBuilder, ValueTask> cases, Action<IActivityBuilder>? activity = default) => builder.Switch(cases, SwitchMode.MatchFirst, activity);
|
||||
|
||||
public static IActivityBuilder Switch(this IBuilder builder, Func<SwitchCaseBuilder, ValueTask> cases, SwitchMode mode, Action<IActivityBuilder>? activity = default)
|
||||
{
|
||||
return builder.Switch(async context =>
|
||||
{
|
||||
var switchCaseBuilder = new SwitchCaseBuilder(context);
|
||||
await cases(switchCaseBuilder);
|
||||
return switchCaseBuilder.Cases;
|
||||
}, mode, activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
public record SwitchCase(string Name, bool Condition);
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using System.Collections.Generic;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
public class SwitchCaseBuilder
|
||||
{
|
||||
public ActivityExecutionContext Context { get; }
|
||||
public ICollection<SwitchCase> Cases { get; } = new List<SwitchCase>();
|
||||
public SwitchCaseBuilder(ActivityExecutionContext context) => Context = context;
|
||||
|
||||
public SwitchCaseBuilder Add(string name, bool condition)
|
||||
{
|
||||
Cases.Add(new SwitchCase(name, condition));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
public static class SwitchExtensions
|
||||
{
|
||||
public static ISetupActivity<Switch> WithCases(this ISetupActivity<Switch> activity, Func<ActivityExecutionContext, ValueTask<ICollection<SwitchCase>>> value) => activity.Set(x => x.Cases, value!);
|
||||
public static ISetupActivity<Switch> WithCases(this ISetupActivity<Switch> activity, Func<ActivityExecutionContext, ICollection<SwitchCase>> value) => activity.Set(x => x.Cases, value!);
|
||||
public static ISetupActivity<Switch> WithCases(this ISetupActivity<Switch> activity, Func<ICollection<SwitchCase>> value) => activity.Set(x => x.Cases, value!);
|
||||
public static ISetupActivity<Switch> WithCases(this ISetupActivity<Switch> activity, ICollection<SwitchCase> value) => activity.Set(x => x.Cases, value!);
|
||||
public static ISetupActivity<Switch> WithMode(this ISetupActivity<Switch> activity, SwitchMode value) => activity.Set(x => x.Mode, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
public enum SwitchMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Yields the outcome of the first condition evaluating to true.
|
||||
/// </summary>
|
||||
MatchFirst,
|
||||
|
||||
/// <summary>
|
||||
/// Yields the outcome of all conditions evaluating to true.
|
||||
/// </summary>
|
||||
MatchAny
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
[Activity(
|
||||
Category = "Control Flow",
|
||||
Description = "Switch execution based on a given expression."
|
||||
)]
|
||||
public class Switch : Activity
|
||||
{
|
||||
public const string DefaultOutcome = "Default";
|
||||
|
||||
public Switch()
|
||||
{
|
||||
Cases = new HashSet<string>()
|
||||
{
|
||||
OutcomeNames.Default
|
||||
};
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The value to switch on.")]
|
||||
public string Value { get; set; } = default!;
|
||||
|
||||
private HashSet<string> _cases = default!;
|
||||
|
||||
[ActivityProperty(Hint = "A comma-separated list of possible outcomes of the expression.")]
|
||||
public HashSet<string> Cases
|
||||
{
|
||||
get => _cases;
|
||||
set => _cases = new HashSet<string>(value, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
|
||||
{
|
||||
var result = Value;
|
||||
var outcome = ContainsCase(result) ? result : DefaultOutcome;
|
||||
return Outcome(outcome, result);
|
||||
}
|
||||
|
||||
private bool ContainsCase(string @case) => Cases.Contains(@case);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.Builders;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
public static class SwitchExtensions
|
||||
{
|
||||
public static ISetupActivity<Switch> WithCases(this ISetupActivity<Switch> activity, Func<ActivityExecutionContext, IEnumerable<string>> value) => activity.Set(x => x.Cases, value);
|
||||
public static ISetupActivity<Switch> WithCases(this ISetupActivity<Switch> activity, Func<IEnumerable<string>> value) => activity.Set(x => x.Cases, value);
|
||||
public static ISetupActivity<Switch> WithCases(this ISetupActivity<Switch> activity, IEnumerable<string> value) => activity.Set(x => x.Cases, value);
|
||||
public static ISetupActivity<Switch> WithCases(this ISetupActivity<Switch> activity, params string[] value) => activity.Set(x => x.Cases, new HashSet<string>(value));
|
||||
|
||||
public static ISetupActivity<Switch> WithValue(this ISetupActivity<Switch> activity, Func<ActivityExecutionContext, string> value) => activity.Set(x => x.Value, value);
|
||||
public static ISetupActivity<Switch> WithValue(this ISetupActivity<Switch> activity, Func<string> value) => activity.Set(x => x.Value, value);
|
||||
public static ISetupActivity<Switch> WithValue(this ISetupActivity<Switch> activity, string value) => activity.Set(x => x.Value, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,17 +8,17 @@ namespace Elsa.Activities.Signaling
|
|||
{
|
||||
public static class InterruptTriggerExtensions
|
||||
{
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, ValueTask<string>> value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, string> value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, Func<ValueTask<string>> value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, Func<string> value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, string value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, ValueTask<string?>> value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, string?> value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, Func<ValueTask<string?>> value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, Func<string?> value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithWorkflowInstanceId(this ISetupActivity<InterruptTrigger> activity, string? value) => activity.Set(x => x.WorkflowInstanceId, value);
|
||||
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, ValueTask<string>> value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, string> value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, Func<ValueTask<string>> value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, Func<string> value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, string value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, ValueTask<string?>> value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, string?> value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, Func<ValueTask<string?>> value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, Func<string?> value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithBlockingActivityId(this ISetupActivity<InterruptTrigger> activity, string? value) => activity.Set(x => x.BlockingActivityId, value);
|
||||
|
||||
public static ISetupActivity<InterruptTrigger> WithInput(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, ValueTask<object?>> value) => activity.Set(x => x.Input, value);
|
||||
public static ISetupActivity<InterruptTrigger> WithInput(this ISetupActivity<InterruptTrigger> activity, Func<ActivityExecutionContext, object?> value) => activity.Set(x => x.Input, value);
|
||||
|
|
|
|||
|
|
@ -45,13 +45,13 @@ namespace Elsa.Builders
|
|||
return this;
|
||||
}
|
||||
|
||||
public IWorkflowBuilder WithDisplayName(string value)
|
||||
public new IWorkflowBuilder WithDisplayName(string value)
|
||||
{
|
||||
DisplayName = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IWorkflowBuilder WithDescription(string? value)
|
||||
public new IWorkflowBuilder WithDescription(string? value)
|
||||
{
|
||||
Description = value;
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Ccontrolflow_005Ccondition/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Ccontrolflow_005Cfor/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Ccontrolflow_005Cifthen/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Cprimitives_005Csetname/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Csignaling_005Cactivities_005Creceivesignal/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Csignaling_005Creceivesignal/@EntryIndexedValue">True</s:Boolean>
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
.AddActivity<ParallelForEach>()
|
||||
.AddActivity<Fork>()
|
||||
.AddActivity<IfElse>()
|
||||
.AddActivity<Switch>()
|
||||
.AddActivity<Join>()
|
||||
.AddActivity<Switch>()
|
||||
.AddActivity<While>()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\core\Elsa\Elsa.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using Elsa.Activities.Console;
|
||||
using Elsa.Activities.ControlFlow;
|
||||
using Elsa.Builders;
|
||||
|
||||
namespace Elsa.Samples.SwitchConsole
|
||||
{
|
||||
public class GrayscaleWorkflow : IWorkflow
|
||||
{
|
||||
private readonly Random _random;
|
||||
|
||||
public GrayscaleWorkflow()
|
||||
{
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
public void Build(IWorkflowBuilder workflow)
|
||||
{
|
||||
workflow
|
||||
.WriteLine("--Grayscale Calculator--", "Start")
|
||||
.WriteLine("Enter a number between 0 and 100.")
|
||||
.ReadLine()
|
||||
.Switch(cases =>
|
||||
{
|
||||
var input = cases.Context.GetInput<int>();
|
||||
cases
|
||||
.Add("Black", input >= 0 && input < 20)
|
||||
.Add("Dark Gray", input >= 20 && input < 50)
|
||||
.Add("Light Gray", input >= 50 && input < 70)
|
||||
.Add("Gray", input >= 20 && input < 70)
|
||||
.Add("White", input >= 70 && input <= 100)
|
||||
.Add("Invalid", input < 0 || input > 100);
|
||||
},
|
||||
SwitchMode.MatchFirst,
|
||||
ifThen =>
|
||||
{
|
||||
ifThen.When("Black").WriteLine("That number is black");
|
||||
ifThen.When("Dark Gray").WriteLine("That number is dark gray");
|
||||
ifThen.When("Light Gray").WriteLine("That number is light gray");
|
||||
ifThen.When("Gray").WriteLine("That number is gray");
|
||||
ifThen.When("White").WriteLine("That number is white");
|
||||
ifThen.When("Invalid").WriteLine("That number is invalid");
|
||||
})
|
||||
.WriteLine("Goodbye");
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/samples/console/Elsa.Samples.SwitchConsole/Program.cs
Normal file
32
src/samples/console/Elsa.Samples.SwitchConsole/Program.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Samples.SwitchConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// Demonstrates a workflow with a While looping construct.
|
||||
/// </summary>
|
||||
static class Program
|
||||
{
|
||||
private static async Task Main()
|
||||
{
|
||||
// Create a service container with Elsa services.
|
||||
var services = new ServiceCollection()
|
||||
.AddElsa(options => options
|
||||
.AddConsoleActivities()
|
||||
.AddWorkflow<GrayscaleWorkflow>())
|
||||
.BuildServiceProvider();
|
||||
|
||||
// Run startup actions (not needed when registering Elsa with a Host).
|
||||
var startupRunner = services.GetRequiredService<IStartupRunner>();
|
||||
await startupRunner.StartupAsync();
|
||||
|
||||
// Get a workflow runner.
|
||||
var workflowRunner = services.GetRequiredService<IWorkflowRunner>();
|
||||
|
||||
// Execute the workflow.
|
||||
await workflowRunner.RunWorkflowAsync<GrayscaleWorkflow>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
using Elsa.Activities.Http;
|
||||
using Elsa.Builders;
|
||||
|
||||
namespace Elsa.Samples.Server.Host.Workflows
|
||||
namespace ElsaDashboard.Samples.Monolith.Workflows
|
||||
{
|
||||
public class GoodbyeWorld : IWorkflow
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using Elsa.Activities.Http;
|
||||
using Elsa.Builders;
|
||||
|
||||
namespace Elsa.Samples.Server.Host.Workflows
|
||||
namespace ElsaDashboard.Samples.Monolith.Workflows
|
||||
{
|
||||
public class HelloWorld : IWorkflow
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using Elsa.Activities.Http;
|
||||
using Elsa.Builders;
|
||||
|
||||
namespace Elsa.Samples.Server.Host.Workflows
|
||||
namespace ElsaDashboard.Samples.Monolith.Workflows
|
||||
{
|
||||
public class HelloWorldV2 : IWorkflow
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using Elsa.Activities.Primitives;
|
|||
using Elsa.Builders;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||
|
||||
namespace Elsa.Samples.Server.Host.Workflows
|
||||
namespace ElsaDashboard.Samples.Monolith.Workflows
|
||||
{
|
||||
public class NamingWorkflow : IWorkflow
|
||||
{
|
||||
|
|
@ -19,7 +19,7 @@ namespace Elsa.Samples.Server.Host.Workflows
|
|||
.Correlate(() => Guid.NewGuid().ToString("N"))
|
||||
.WriteHttpResponse(x => x.WithStatusCode(HttpStatusCode.OK).WithContent(context => $"Tell me your name please. Use correlation ID {context.WorkflowExecutionContext.CorrelationId}").WithContentType("text/plain"))
|
||||
.HttpRequestReceived(x => x.WithPath("/signup").WithMethod(HttpMethod.Post.ToString()).WithReadContent())
|
||||
.SetVariable("Name", context => (string) context.GetInput<HttpRequestModel>().Body)
|
||||
.SetVariable("Name", context => (string?) context.GetInput<HttpRequestModel>().Body)
|
||||
.SetName(context => context.GetVariable<string>("Name"))
|
||||
|
||||
.WriteHttpResponse(x => x
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ namespace Elsa.Server.Api.Endpoints.WorkflowRegistry
|
|||
public string? TenantId { get; set; }
|
||||
public bool IsSingleton { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public bool IsPublished { get; set; }
|
||||
public bool IsLatest { get; set; }
|
||||
public Variables Variables { get; set; } = new();
|
||||
|
|
@ -17,7 +16,6 @@ namespace Elsa.Server.Api.Endpoints.WorkflowRegistry
|
|||
public WorkflowPersistenceBehavior PersistenceBehavior { get; set; }
|
||||
public bool DeleteCompletedInstances { get; set; }
|
||||
public Variables CustomAttributes { get; set; } = new();
|
||||
public string? DisplayName { get; set; }
|
||||
}
|
||||
|
||||
public class CompositeActivityBlueprintModel : ActivityBlueprintModel
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
using Elsa.Activities.Console;
|
||||
using Elsa.Activities.ControlFlow;
|
||||
using Elsa.Builders;
|
||||
|
||||
namespace Elsa.Core.IntegrationTests.Workflows
|
||||
{
|
||||
public class SwitchWorkflow : IWorkflow
|
||||
{
|
||||
public void Build(IWorkflowBuilder workflow)
|
||||
{
|
||||
workflow
|
||||
.WriteLine("Start")
|
||||
.Then<Switch>(
|
||||
@switch => @switch.WithCases("Case 1", "Case 2", "Case 3").WithValue(context => (string)context.WorkflowExecutionContext.Input!),
|
||||
@switch =>
|
||||
{
|
||||
@switch
|
||||
.When("Case 1")
|
||||
.WriteLine("Case 1 executed", id: "WriteLine1");
|
||||
|
||||
@switch
|
||||
.When("Case 2")
|
||||
.WriteLine("Case 2 executed", id: "WriteLine2");
|
||||
|
||||
@switch
|
||||
.When("Case 3")
|
||||
.WriteLine("Case 3 executed", id: "WriteLine3");
|
||||
|
||||
@switch
|
||||
.When("Default")
|
||||
.WriteLine("Default case executed", id: "WriteLineDefault");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// using System.Linq;
|
||||
// using System.Threading.Tasks;
|
||||
// using Elsa.Testing.Shared.Unit;
|
||||
// using Xunit;
|
||||
// using Xunit.Abstractions;
|
||||
//
|
||||
// namespace Elsa.Core.IntegrationTests.Workflows
|
||||
// {
|
||||
// public class SwitchWorkflowTests : WorkflowsUnitTestBase
|
||||
// {
|
||||
// public SwitchWorkflowTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// [Theory(DisplayName = "Runs Switch")]
|
||||
// [InlineData("Case 1", "WriteLine1")]
|
||||
// [InlineData("Case 2", "WriteLine2")]
|
||||
// [InlineData("Case 3", "WriteLine3")]
|
||||
// [InlineData("Different Case", "WriteLineDefault")]
|
||||
// public async Task Test01(string input, string expectedActivityId)
|
||||
// {
|
||||
// var workflowInstance = await WorkflowRunner.RunWorkflowAsync<SwitchWorkflow>(input: input);
|
||||
// var executedActivityIds = workflowInstance.ExecutionLog.Select(x => x.ActivityId).ToList();
|
||||
//
|
||||
// Assert.Contains(expectedActivityId, executedActivityIds);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
Loading…
Reference in a new issue