< Summary

Information
Class: Elsa.Workflows.Activities.CompositeWithResult
Assembly: Elsa.Workflows.Core
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 9
Coverable lines: 9
Total lines: 230
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 2
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
.ctor(...)0%620%
.ctor(...)100%210%
get_Result()100%210%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Core/Activities/Composite.cs

#LineLine coverage
 1using System.ComponentModel;
 2using System.Runtime.CompilerServices;
 3using System.Text.Json.Serialization;
 4using Elsa.Expressions.Models;
 5using Elsa.Extensions;
 6using Elsa.Workflows.Activities.Flowchart.Models;
 7using Elsa.Workflows.Attributes;
 8using Elsa.Workflows.Memory;
 9using Elsa.Workflows.Models;
 10using Elsa.Workflows.Signals;
 11using JetBrains.Annotations;
 12
 13namespace Elsa.Workflows.Activities;
 14
 15/// <summary>
 16/// Represents a composite activity that has a single <see cref="Root"/> activity. Like a workflow, but without workflow
 17/// </summary>
 18[PublicAPI]
 19public abstract class Composite : Activity, IVariableContainer, IComposite
 20{
 21    /// <inheritdoc />
 22    protected Composite(string? source = null, int? line = null) : base(source, line)
 23    {
 24        OnSignalReceived<CompleteCompositeSignal>(OnCompleteCompositeSignal);
 25    }
 26
 27    /// <inheritdoc />
 28    [JsonIgnore]  // Composite activities' Variables is intended to be constructed from code only.
 29    public ICollection<Variable> Variables { get; init; } = new List<Variable>();
 30
 31    /// <summary>
 32    /// A variable to allow activities to set a result.
 33    /// </summary>
 34    [JsonIgnore]
 35    public Variable? ResultVariable { get; set; }
 36
 37    /// <summary>
 38    /// The activity to schedule when this activity executes.
 39    /// </summary>
 40    [Port]
 41    [Browsable(false)]
 42    [JsonIgnoreCompositeRoot]
 43    public IActivity Root { get; set; } = new Sequence();
 44
 45    /// <inheritdoc />
 46    protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
 47    {
 48        ConfigureActivities(context);
 49
 50        // Register variables.
 51        foreach (var variable in Variables)
 52            variable.Set(context, variable.Value);
 53
 54        await context.ScheduleActivityAsync(Root, OnRootCompletedAsync);
 55    }
 56
 57    /// <summary>
 58    /// Override this method to configure activity properties before execution.
 59    /// </summary>
 60    protected virtual void ConfigureActivities(ActivityExecutionContext context)
 61    {
 62    }
 63
 64    private async ValueTask OnRootCompletedAsync(ActivityCompletedContext context)
 65    {
 66        await OnCompletedAsync(context);
 67        await context.TargetContext.CompleteActivityAsync();
 68    }
 69
 70    /// <summary>
 71    /// Completes this composite activity.
 72    /// </summary>
 73    protected async Task CompleteAsync(ActivityExecutionContext context, object? result = null) => await context.SendSig
 74
 75    /// <summary>
 76    /// Completes this composite activity.
 77    /// </summary>
 78    protected async Task CompleteAsync(ActivityExecutionContext context, params string[] outcomes) => await CompleteAsyn
 79
 80    /// <summary>
 81    /// Override this method to execute custom logic when the composite activity completes.
 82    /// </summary>
 83    /// <param name="context">The context of the composite activity.</param>
 84    protected virtual ValueTask OnCompletedAsync(ActivityCompletedContext context)
 85    {
 86        OnCompleted(context);
 87        return new();
 88    }
 89
 90    /// <summary>
 91    /// Override this method to execute custom logic when the composite activity completes.
 92    /// </summary>
 93    /// <param name="context">The context of the composite activity.</param>
 94    protected virtual void OnCompleted(ActivityCompletedContext context)
 95    {
 96    }
 97
 98    private async ValueTask OnCompleteCompositeSignal(CompleteCompositeSignal signal, SignalContext context)
 99    {
 100        // Set the outcome into the context for the parent activity to pick up.
 101        context.SenderActivityExecutionContext.WorkflowExecutionContext.TransientProperties[nameof(CompleteCompositeSign
 102
 103        var completedContext = new ActivityCompletedContext(context.ReceiverActivityExecutionContext, context.SenderActi
 104        await OnCompletedAsync(completedContext);
 105
 106        // Complete the sender first so that it notifies its parents to complete.
 107        await context.SenderActivityExecutionContext.CompleteActivityAsync();
 108
 109        // Then complete this activity.
 110        await context.ReceiverActivityExecutionContext.CompleteActivityAsync(signal.Value);
 111        context.StopPropagation();
 112
 113    }
 114
 115    /// <summary>
 116    /// Creates a new <see cref="Activities.Inline"/> activity.
 117    /// </summary>
 118    protected static Inline Inline(Func<ActivityExecutionContext, ValueTask> activity, [CallerFilePath] string? source =
 119
 120    /// <summary>
 121    /// Creates a new <see cref="Activities.Inline"/> activity.
 122    /// </summary>
 123    protected static Inline Inline(Func<ValueTask> activity, [CallerFilePath] string? source = null, [CallerLineNumber] 
 124
 125    /// <summary>
 126    /// Creates a new <see cref="Activities.Inline"/> activity.
 127    /// </summary>
 128    protected static Inline Inline(Action<ActivityExecutionContext> activity, [CallerFilePath] string? source = null, [C
 129
 130    /// <summary>
 131    /// Creates a new <see cref="Activities.Inline"/> activity.
 132    /// </summary>
 133    protected static Inline Inline(Action activity, [CallerFilePath] string? source = null, [CallerLineNumber] int? line
 134
 135    /// <summary>
 136    /// Creates a new <see cref="Activities.Inline"/> activity.
 137    /// </summary>
 138    protected static Inline<TResult> Inline<TResult>(Func<ActivityExecutionContext, ValueTask<TResult>> activity, Memory
 139
 140    /// <summary>
 141    /// Creates a new <see cref="Activities.Inline"/> activity.
 142    /// </summary>
 143    protected static Inline<TResult> Inline<TResult>(Func<ValueTask<TResult>> activity, MemoryBlockReference? output = n
 144
 145    /// <summary>
 146    /// Creates a new <see cref="Activities.Inline"/> activity.
 147    /// </summary>
 148    protected static Inline<TResult> Inline<TResult>(Func<ActivityExecutionContext, TResult> activity, MemoryBlockRefere
 149
 150    /// <summary>
 151    /// Creates a new <see cref="Activities.Inline"/> activity.
 152    /// </summary>
 153    protected static Inline<TResult> Inline<TResult>(Func<TResult> activity, MemoryBlockReference? output = null, [Calle
 154
 155    /// <summary>
 156    /// Creates a new <see cref="Activities.SetVariable"/> activity.
 157    /// </summary>
 158    protected static SetVariable<T> SetVariable<T>(Variable<T> variable, T value, [CallerFilePath] string? source = null
 159
 160    /// <summary>
 161    /// Creates a new <see cref="Activities.SetVariable"/> activity.
 162    /// </summary>
 163    protected static SetVariable<T> SetVariable<T>(Variable<T> variable, Func<ExpressionExecutionContext, T> value, [Cal
 164
 165    /// <summary>
 166    /// Creates a new <see cref="Activities.SetVariable"/> activity.
 167    /// </summary>
 168    protected static SetVariable<T> SetVariable<T>(Variable<T> variable, Func<T> value, [CallerFilePath] string? source 
 169
 170    /// <summary>
 171    /// Creates a new <see cref="Activities.SetVariable"/> activity.
 172    /// </summary>
 173    protected static SetVariable<T> SetVariable<T>(Variable<T> variable, Variable<T> value, [CallerFilePath] string? sou
 174
 175    public virtual void Setup()
 176    {
 177    }
 178}
 179
 180/// <summary>
 181/// Base class for custom activities with auto-complete behavior that return a result.
 182/// </summary>
 183[PublicAPI]
 184public abstract class CompositeWithResult : Composite
 185{
 186    /// <inheritdoc />
 0187    protected CompositeWithResult(string? source = null, int? line = null) : base(source, line)
 188    {
 0189    }
 190
 191    /// <inheritdoc />
 0192    protected CompositeWithResult(MemoryBlockReference? output, string? source = null, int? line = null) : base(source, 
 193    {
 0194        if (output != null) Result = new Output(output);
 0195    }
 196
 197    /// <inheritdoc />
 0198    protected CompositeWithResult(Output? output, string? source = null, int? line = null) : base(source, line)
 199    {
 0200        Result = output;
 0201    }
 202
 203    /// <summary>
 204    /// The result value of the composite.
 205    /// </summary>
 0206    [Output] public Output? Result { get; set; }
 207}
 208
 209/// <summary>
 210/// Represents a composite activity that has a single <see cref="Composite.Root"/> activity and returns a result.
 211/// </summary>
 212[PublicAPI]
 213public abstract class Composite<T> : Composite, IActivityWithResult<T>
 214{
 215    /// <inheritdoc />
 216    protected Composite([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line
 217    {
 218    }
 219
 220    /// <summary>
 221    /// The result of the activity.
 222    /// </summary>
 223    [Output] public Output<T>? Result { get; set; }
 224
 225    Output? IActivityWithResult.Result
 226    {
 227        get => Result;
 228        set => Result = (Output<T>?)value;
 229    }
 230}