diff --git a/src/modules/Elsa.ActivityDefinitions/Activities/ActivityDefinitionActivity.cs b/src/modules/Elsa.ActivityDefinitions/Activities/ActivityDefinitionActivity.cs
index bc6ec790f..2819d2e13 100644
--- a/src/modules/Elsa.ActivityDefinitions/Activities/ActivityDefinitionActivity.cs
+++ b/src/modules/Elsa.ActivityDefinitions/Activities/ActivityDefinitionActivity.cs
@@ -10,6 +10,7 @@ namespace Elsa.ActivityDefinitions.Activities;
///
public class ActivityDefinitionActivity : ActivityBase
{
+ ///
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
// Construct the root activity stored in the activity definitions.
@@ -17,8 +18,8 @@ public class ActivityDefinitionActivity : ActivityBase
var root = await materializer.MaterializeAsync(this, context.CancellationToken);
// Schedule the activity for execution.
- await context.ScheduleActivityAsync(root, onChildCompletedAsync);
+ await context.ScheduleActivityAsync(root, OnChildCompletedAsync);
}
- private async ValueTask onChildCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
+ private async ValueTask OnChildCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs b/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs
index e2faa861e..5f3f70e50 100644
--- a/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs
+++ b/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs
@@ -32,7 +32,7 @@ public static class ObjectConverter
if (value is DahomeyJsonNode { ValueKind: JsonValueKind.Object } dahomyJsonObject)
return ToObject(dahomyJsonObject, targetType, options);
- if (value is JsonElement { ValueKind: JsonValueKind.Object } jsonObject)
+ if (value is JsonElement { ValueKind: JsonValueKind.Object or JsonValueKind.Array } jsonObject)
return jsonObject.Deserialize(targetType, options);
var underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType;
diff --git a/src/modules/Elsa.JavaScript/Providers/JavaScriptExpressionSyntaxProvider.cs b/src/modules/Elsa.JavaScript/Providers/JavaScriptExpressionSyntaxProvider.cs
index 60a73d448..655b96361 100644
--- a/src/modules/Elsa.JavaScript/Providers/JavaScriptExpressionSyntaxProvider.cs
+++ b/src/modules/Elsa.JavaScript/Providers/JavaScriptExpressionSyntaxProvider.cs
@@ -27,15 +27,7 @@ public class JavaScriptExpressionSyntaxProvider : IExpressionSyntaxProvider
Syntax = SyntaxName,
Type = typeof(JavaScriptExpression),
CreateExpression = CreateJavaScriptExpression,
- CreateBlockReference = context =>
- {
- var reference = new JavaScriptExpressionBlockReference(context.GetExpression());
-
- if (string.IsNullOrWhiteSpace(reference.Id))
- reference.Id = GenerateId();
-
- return reference;
- },
+ CreateBlockReference = context => new JavaScriptExpressionBlockReference(context.GetExpression()),
CreateSerializableObject = context => new
{
Type = SyntaxName,
diff --git a/src/modules/Elsa.Liquid/Providers/LiquidExpressionSyntaxProvider.cs b/src/modules/Elsa.Liquid/Providers/LiquidExpressionSyntaxProvider.cs
index b4948670b..ee5b667f1 100644
--- a/src/modules/Elsa.Liquid/Providers/LiquidExpressionSyntaxProvider.cs
+++ b/src/modules/Elsa.Liquid/Providers/LiquidExpressionSyntaxProvider.cs
@@ -23,15 +23,7 @@ public class LiquidExpressionSyntaxProvider : IExpressionSyntaxProvider
Syntax = SyntaxName,
Type = typeof(LiquidExpression),
CreateExpression = CreateLiquidExpression,
- CreateBlockReference = context =>
- {
- var reference = new LiquidExpressionBlockReference(context.GetExpression());
-
- if (string.IsNullOrWhiteSpace(reference.Id))
- reference.Id = GenerateId();
-
- return reference;
- },
+ CreateBlockReference = context => new LiquidExpressionBlockReference(context.GetExpression()),
CreateSerializableObject = context => new
{
Type = SyntaxName,
diff --git a/src/modules/Elsa.ProtoActor/Grains/WorkflowGrain.cs b/src/modules/Elsa.ProtoActor/Grains/WorkflowGrain.cs
index 1800a7381..d467c0e89 100644
--- a/src/modules/Elsa.ProtoActor/Grains/WorkflowGrain.cs
+++ b/src/modules/Elsa.ProtoActor/Grains/WorkflowGrain.cs
@@ -176,6 +176,7 @@ public class WorkflowGrain : WorkflowGrainBase
ActivityInstanceId = x.ActivityInstanceId,
Hash = x.Hash,
Data = x.Data.EmptyIfNull(),
+ AutoBurn = x.AutoBurn,
CallbackMethodName = x.CallbackMethodName.EmptyIfNull()
});
}
\ No newline at end of file
diff --git a/src/modules/Elsa.ProtoActor/Implementations/ProtoActorWorkflowRuntime.cs b/src/modules/Elsa.ProtoActor/Implementations/ProtoActorWorkflowRuntime.cs
index a38fd9f16..d780aad0d 100644
--- a/src/modules/Elsa.ProtoActor/Implementations/ProtoActorWorkflowRuntime.cs
+++ b/src/modules/Elsa.ProtoActor/Implementations/ProtoActorWorkflowRuntime.cs
@@ -244,5 +244,6 @@ public class ProtoActorWorkflowRuntime : IWorkflowRuntime
x.Data.NullIfEmpty(),
x.ActivityId,
x.ActivityInstanceId,
+ x.AutoBurn,
x.CallbackMethodName.NullIfEmpty()));
}
\ No newline at end of file
diff --git a/src/modules/Elsa.ProtoActor/Protos/Messages.proto b/src/modules/Elsa.ProtoActor/Protos/Messages.proto
index 1cb5379f2..013ee8bda 100644
--- a/src/modules/Elsa.ProtoActor/Protos/Messages.proto
+++ b/src/modules/Elsa.ProtoActor/Protos/Messages.proto
@@ -81,7 +81,8 @@ message BookmarkDto {
optional string Data = 4;
string ActivityId = 5;
string ActivityInstanceId = 6;
- optional string CallbackMethodName = 7;
+ optional bool AutoBurn = 7;
+ optional string CallbackMethodName = 8;
}
message Json {
diff --git a/src/modules/Elsa.Scheduling/Activities/Delay.cs b/src/modules/Elsa.Scheduling/Activities/Delay.cs
index f69734eb2..e6aaca98c 100644
--- a/src/modules/Elsa.Scheduling/Activities/Delay.cs
+++ b/src/modules/Elsa.Scheduling/Activities/Delay.cs
@@ -1,4 +1,5 @@
-using System.Text.Json.Serialization;
+using System.Runtime.CompilerServices;
+using System.Text.Json.Serialization;
using Elsa.Common.Services;
using Elsa.Expressions.Models;
using Elsa.Scheduling.Models;
@@ -8,42 +9,72 @@ using Elsa.Workflows.Core.Models;
namespace Elsa.Scheduling.Activities;
+///
+/// Delay execution for the specified amount of time.
+///
[Activity( "Elsa", "Scheduling", "Delay execution for the specified amount of time.")]
public class Delay : Activity
{
+ ///
[JsonConstructor]
- public Delay()
+ public Delay([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
{
}
- public Delay(Func timeSpan, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking) : this(new Input(timeSpan))
+ ///
+ public Delay(
+ Func timeSpan,
+ DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking,
+ [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(new Input(timeSpan), blockingStrategy, source, line)
{
}
-
- public Delay(Func> timeSpan, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking) : this(new Input(timeSpan))
+
+ ///
+ public Delay(
+ Func> timeSpan,
+ DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking,
+ [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(new Input(timeSpan), blockingStrategy, source, line)
{
}
-
- public Delay(Input timeSpan, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking)
+
+ ///
+ public Delay(
+ Input timeSpan,
+ DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking,
+ [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
{
TimeSpan = timeSpan;
Strategy = blockingStrategy;
}
- public Delay(TimeSpan timeSpan, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking)
+ ///
+ public Delay(
+ TimeSpan timeSpan,
+ DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking,
+ [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
{
TimeSpan = new Input(timeSpan);
Strategy = blockingStrategy;
}
- public Delay(Variable timeSpan, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking)
+ ///
+ public Delay(
+ Variable timeSpan,
+ DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking,
+ [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
{
TimeSpan = new Input(timeSpan);
Strategy = blockingStrategy;
}
+ ///
+ /// The amount of time to delay execution.
+ ///
[Input] public Input TimeSpan { get; set; } = default!;
+ ///
+ /// A value controlling whether the delay should happen in-process (synchronously or out of process (asynchronously).
+ ///
[Input] public DelayBlockingStrategy Strategy { get; set; } = DelayBlockingStrategy.NonBlocking;
///
@@ -97,11 +128,33 @@ public class Delay : Activity
await NonBlockingStrategy(timeSpan, context);
}
+ ///
+ /// Creates a new from the specified number of milliseconds.
+ ///
public static Delay FromMilliseconds(double value, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking) => new(System.TimeSpan.FromMilliseconds(value), blockingStrategy);
+
+ ///
+ /// Creates a new from the specified number of seconds.
+ ///
public static Delay FromSeconds(double value, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking) => new(System.TimeSpan.FromSeconds(value), blockingStrategy);
+
+ ///
+ /// Creates a new from the specified number of minutes.
+ ///
public static Delay FromMinutes(double value, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking) => new(System.TimeSpan.FromMinutes(value), blockingStrategy);
+
+ ///
+ /// Creates a new from the specified number of hours.
+ ///
public static Delay FromHours(double value, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking) => new(System.TimeSpan.FromHours(value), blockingStrategy);
+
+ ///
+ /// Creates a new from the specified number of days.
+ ///
public static Delay FromDays(double value, DelayBlockingStrategy blockingStrategy = DelayBlockingStrategy.NonBlocking) => new(System.TimeSpan.FromDays(value), blockingStrategy);
}
+///
+/// A bookmark payload for .
+///
public record DelayPayload(DateTimeOffset ResumeAt);
\ No newline at end of file
diff --git a/src/modules/Elsa.Scheduling/Activities/StartAt.cs b/src/modules/Elsa.Scheduling/Activities/StartAt.cs
index fd9c9c8af..ea06d2ae5 100644
--- a/src/modules/Elsa.Scheduling/Activities/StartAt.cs
+++ b/src/modules/Elsa.Scheduling/Activities/StartAt.cs
@@ -1,4 +1,6 @@
-using Elsa.Common.Services;
+using System.Runtime.CompilerServices;
+using System.Text.Json.Serialization;
+using Elsa.Common.Services;
using Elsa.Expressions.Models;
using Elsa.Workflows.Core;
using Elsa.Workflows.Core.Attributes;
@@ -7,44 +9,69 @@ using Microsoft.Extensions.Logging;
namespace Elsa.Scheduling.Activities;
+///
+/// Triggers the workflow at a specific future timestamp.
+///
[Activity("Elsa", "Scheduling", "Trigger execution at a specific time in the future.")]
public class StartAt : Trigger
{
- public const string InputKey = "ExecuteAt";
-
- public StartAt()
+ private const string InputKey = "ExecuteAt";
+
+ ///
+ [JsonConstructor]
+ public StartAt([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
{
}
- public StartAt(Input dateTime) => DateTime = dateTime;
+ ///
+ public StartAt(Input dateTime, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line) => DateTime = dateTime;
- public StartAt(Func dateTime) : this(new Input(dateTime))
- {
- }
-
- public StartAt(Func> dateTime) : this(new Input(dateTime))
- {
- }
-
- public StartAt(Func> dateTime) : this(new Input(dateTime))
- {
- }
-
- public StartAt(Func dateTime) : this(new Input(dateTime))
+ ///
+ public StartAt(Func dateTime, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default)
+ : this(new Input(dateTime), source, line)
{
}
- public StartAt(DateTimeOffset dateTime) => DateTime = new Input(dateTime);
- public StartAt(Variable dateTime) => DateTime = new Input(dateTime);
+ ///
+ public StartAt(
+ Func> dateTime,
+ [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(new Input(dateTime), source, line)
+ {
+ }
+ ///
+ public StartAt(Func> dateTime, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default)
+ : this(new Input(dateTime), source, line)
+ {
+ }
+
+ ///
+ public StartAt(Func dateTime, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default)
+ : this(new Input(dateTime), source, line)
+ {
+ }
+
+ ///
+ public StartAt(DateTimeOffset dateTime, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line) =>
+ DateTime = new Input(dateTime);
+
+ ///
+ public StartAt(Variable dateTime, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line) =>
+ DateTime = new Input(dateTime);
+
+ ///
+ /// The timestamp at which the workflow should be triggered.
+ ///
[Input] public Input DateTime { get; set; } = default!;
+ ///
protected override object GetTriggerPayload(TriggerIndexingContext context)
{
var executeAt = context.ExpressionExecutionContext.Get(DateTime);
return new StartAtPayload(executeAt);
}
+ ///
protected override void Execute(ActivityExecutionContext context)
{
// If external input was received, it means this activity got triggered and does not need to create a bookmark.
@@ -69,7 +96,10 @@ public class StartAt : Trigger
context.CreateBookmark(payload);
}
+ ///
+ /// Creates a new activity set to trigger at the specified timestamp.
+ ///
public static StartAt From(DateTimeOffset value) => new(value);
}
-public record StartAtPayload(DateTimeOffset ExecuteAt);
\ No newline at end of file
+internal record StartAtPayload(DateTimeOffset ExecuteAt);
\ No newline at end of file
diff --git a/src/modules/Elsa.Scheduling/Activities/Timer.cs b/src/modules/Elsa.Scheduling/Activities/Timer.cs
index 740dbeb1c..d3affe586 100644
--- a/src/modules/Elsa.Scheduling/Activities/Timer.cs
+++ b/src/modules/Elsa.Scheduling/Activities/Timer.cs
@@ -1,4 +1,5 @@
-using System.Text.Json.Serialization;
+using System.Runtime.CompilerServices;
+using System.Text.Json.Serialization;
using Elsa.Common.Services;
using Elsa.Workflows.Core;
using Elsa.Workflows.Core.Attributes;
@@ -12,22 +13,29 @@ namespace Elsa.Scheduling.Activities;
[Activity( "Elsa", "Scheduling", "Trigger workflow execution at a specific interval.")]
public class Timer : EventGenerator
{
+ ///
[JsonConstructor]
- public Timer()
+ public Timer([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
{
}
- public Timer(TimeSpan interval) : this(new Input(interval))
+ ///
+ public Timer(TimeSpan interval, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(new Input(interval), source, line)
{
}
- public Timer(Input interval)
+ ///
+ public Timer(Input interval, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line)
{
Interval = interval;
}
+ ///
+ /// Th interval at which the timer should execute.
+ ///
[Input] public Input Interval { get; set; } = default!;
+ ///
protected override object GetTriggerPayload(TriggerIndexingContext context)
{
var interval = context.ExpressionExecutionContext.Get(Interval);
@@ -36,8 +44,15 @@ public class Timer : EventGenerator
return new TimerPayload(executeAt, interval);
}
+ ///
+ /// Creates a new activity set to trigger at the specified interval.
+ ///
public static Timer FromTimeSpan(TimeSpan value) => new(value);
+
+ ///
+ /// Creates a new activity set to trigger at the specified interval in seconds.
+ ///
public static Timer FromSeconds(double value) => FromTimeSpan(TimeSpan.FromSeconds(value));
}
-public record TimerPayload(DateTimeOffset StartAt, TimeSpan Interval);
\ No newline at end of file
+internal record TimerPayload(DateTimeOffset StartAt, TimeSpan Interval);
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Activities/AnswerCall.cs b/src/modules/Elsa.Telnyx/Activities/AnswerCall.cs
index 8313c72b5..5f542455c 100644
--- a/src/modules/Elsa.Telnyx/Activities/AnswerCall.cs
+++ b/src/modules/Elsa.Telnyx/Activities/AnswerCall.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Attributes;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Attributes;
using Elsa.Telnyx.Bookmarks;
using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
@@ -9,19 +10,64 @@ using Elsa.Workflows.Core.Activities.Flowchart.Attributes;
using Elsa.Workflows.Core.Activities.Flowchart.Models;
using Elsa.Workflows.Core.Attributes;
using Elsa.Workflows.Core.Models;
+using Elsa.Workflows.Core.Services;
using Elsa.Workflows.Runtime.Services;
using Refit;
namespace Elsa.Telnyx.Activities;
+///
+[FlowNode("Connected", "Disconnected")]
+public class FlowAnswerCall : AnswerCallBase
+{
+ ///
+ public FlowAnswerCall([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
+ protected override async ValueTask HandleConnectedAsync(ActivityExecutionContext context) => await context.CompleteActivityAsync(new Outcomes("Connected"));
+
+ ///
+ protected override async ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => await context.CompleteActivityAsync(new Outcomes("Disconnected"));
+}
+
+///
+public class AnswerCall : AnswerCallBase
+{
+ ///
+ public AnswerCall([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
+ /// The activity to schedule when the call was successfully answered.
+ ///
+ [Port]
+ public IActivity? Connected { get; set; }
+
+ ///
+ /// The activity to schedule when the call was no longer active.
+ ///
+ [Port]
+ public IActivity? Disconnected { get; set; }
+
+ protected override async ValueTask HandleConnectedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Connected);
+ protected override async ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Disconnected);
+}
+
///
/// Answer an incoming call. You must issue this command before executing subsequent commands on an incoming call.
///
[Activity(Constants.Namespace, "Answer an incoming call. You must issue this command before executing subsequent commands on an incoming call.", Kind = ActivityKind.Task)]
-[FlowNode("Connected", "Disconnected")]
[WebhookDriven(WebhookEventTypes.CallAnswered)]
-public class AnswerCall : ActivityBase, IBookmarksPersistedHandler
+public abstract class AnswerCallBase : ActivityBase, IBookmarksPersistedHandler
{
+ ///
+ protected AnswerCallBase(string? source = default, int? line = default) : base(source, line)
+ {
+ }
+
///
/// The call control ID to answer. Leave blank when the workflow is driven by an incoming call and you wish to pick up that one.
///
@@ -38,14 +84,16 @@ public class AnswerCall : ActivityBase, IBookmarksPersisted
///
/// Invokes Telnyx to answer the call.
///
- ///
public async ValueTask BookmarksPersistedAsync(ActivityExecutionContext context) => await InvokeTelnyxAsync(context);
-
+
+ protected abstract ValueTask HandleConnectedAsync(ActivityExecutionContext context);
+ protected abstract ValueTask HandleDisconnectedAsync(ActivityExecutionContext context);
+
private async ValueTask ResumeAsync(ActivityExecutionContext context)
{
var payload = context.GetInput();
context.Set(Result, payload);
- await context.CompleteActivityAsync(new Outcomes("Connected"));
+ await HandleConnectedAsync(context);
}
///
@@ -56,15 +104,15 @@ public class AnswerCall : ActivityBase, IBookmarksPersisted
var callControlId = context.GetPrimaryCallControlId(CallControlId) ?? throw new Exception("CallControlId is required.");
var request = new AnswerCallRequest();
var telnyxClient = context.GetRequiredService();
-
+
try
{
- await telnyxClient.Calls.AnswerCallAsync(callControlId, request, context.CancellationToken);
+ await telnyxClient.Calls.AnswerCallAsync(callControlId, request, context.CancellationToken);
}
catch (ApiException e)
{
if (!await e.CallIsNoLongerActiveAsync()) throw;
- await context.CompleteActivityAsync(new Outcomes("Disconnected"));
+ await HandleDisconnectedAsync(context);
}
}
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Activities/BridgeCalls.cs b/src/modules/Elsa.Telnyx/Activities/BridgeCalls.cs
index f7c777327..519a71e5b 100644
--- a/src/modules/Elsa.Telnyx/Activities/BridgeCalls.cs
+++ b/src/modules/Elsa.Telnyx/Activities/BridgeCalls.cs
@@ -1,30 +1,55 @@
-using Elsa.Telnyx.Client.Models;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Attributes;
+using Elsa.Telnyx.Bookmarks;
+using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
using Elsa.Telnyx.Extensions;
using Elsa.Telnyx.Payloads.Call;
using Elsa.Workflows.Core;
using Elsa.Workflows.Core.Activities.Flowchart.Attributes;
-using Elsa.Workflows.Core.Activities.Flowchart.Models;
using Elsa.Workflows.Core.Attributes;
using Elsa.Workflows.Core.Models;
using Elsa.Workflows.Core.Services;
+using Elsa.Workflows.Runtime.Services;
using Refit;
namespace Elsa.Telnyx.Activities;
+///
[FlowNode("Bridged", "Disconnected")]
public class FlowBridgeCalls : BridgeCallsBase
{
+ ///
+ public FlowBridgeCalls([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
protected override ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => context.CompleteActivityAsync("Disconnected");
protected override ValueTask HandleBridgedAsync(ActivityExecutionContext context) => context.CompleteActivityAsync("Bridged");
}
+///
public class BridgeCalls : BridgeCallsBase
{
- [Port]public IActivity? Disconnected { get; set; }
- [Port]public IActivity? Bridged { get; set; }
+ ///
+ public BridgeCalls([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+ ///
+ /// The to execute when the source leg call is no longer active.
+ ///
+ [Port]public IActivity? Disconnected { get; set; }
+
+ ///
+ /// The to execute when the two calls are bridged.
+ ///
+ [Port]public IActivity? Bridged { get; set; }
+
+ ///
protected override async ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Disconnected, OnCompleted);
+
+ ///
protected override async ValueTask HandleBridgedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Bridged, OnCompleted);
}
@@ -32,9 +57,13 @@ public class BridgeCalls : BridgeCallsBase
/// Bridge two calls.
///
[Activity(Constants.Namespace, "Bridge two calls.", Kind = ActivityKind.Task)]
-[FlowNode("Bridged", "Disconnected")]
-public abstract class BridgeCallsBase : ActivityBase
+public abstract class BridgeCallsBase : ActivityBase, IBookmarksPersistedHandler
{
+ ///
+ protected BridgeCallsBase(string? source = default, int? line = default) : base(source, line)
+ {
+ }
+
///
/// The source call control ID of one of the call to bridge with. Leave empty to use the ambient inbound call control Id, if there is one.
///
@@ -48,7 +77,7 @@ public abstract class BridgeCallsBase : ActivityBase
public Input? CallControlIdB { get; set; }
///
- protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
+ public async ValueTask BookmarksPersistedAsync(ActivityExecutionContext context)
{
var callControlIdA = context.GetPrimaryCallControlId(CallControlIdA) ?? throw new Exception("CallControlA is required");
var callControlIdB = context.GetSecondaryCallControlId(CallControlIdB) ?? throw new Exception("CallControlB is required");
@@ -58,26 +87,34 @@ public abstract class BridgeCallsBase : ActivityBase
try
{
await telnyxClient.Calls.BridgeCallsAsync(callControlIdA, request, context.CancellationToken);
- context.CreateBookmark(ResumeAsync);
}
catch (ApiException e)
{
if (!await e.CallIsNoLongerActiveAsync()) throw;
- await context.CompleteActivityAsync("Disconnected");
+ await HandleDisconnectedAsync(context);
}
}
+ ///
+ protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
+ {
+ var callControlIdA = context.GetPrimaryCallControlId(CallControlIdA) ?? throw new Exception("CallControlA is required");
+ var callControlIdB = context.GetSecondaryCallControlId(CallControlIdB) ?? throw new Exception("CallControlB is required");
+ var bookmarkA = new CallBridgedBookmarkPayload(callControlIdA);
+ var bookmarkB = new CallBridgedBookmarkPayload(callControlIdB);
+ context.CreateBookmarks(new[]{ bookmarkA, bookmarkB }, ResumeAsync);
+ }
+
protected abstract ValueTask HandleDisconnectedAsync(ActivityExecutionContext context);
protected abstract ValueTask HandleBridgedAsync(ActivityExecutionContext context);
-
protected async ValueTask OnCompleted(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
private async ValueTask ResumeAsync(ActivityExecutionContext context)
{
var payload = context.GetInput()!;
var callControlIdA = context.GetPrimaryCallControlId(CallControlIdA);
- var callControlIdB = context.GetPrimaryCallControlId(CallControlIdA);
+ var callControlIdB = context.GetSecondaryCallControlId(CallControlIdB);
if (payload.CallControlId == callControlIdA) context.SetProperty("CallBridgedPayloadA", payload);
if (payload.CallControlId == callControlIdB) context.SetProperty("CallBridgedPayloadB", payload);
@@ -88,11 +125,8 @@ public abstract class BridgeCallsBase : ActivityBase
if (callBridgedPayloadA != null && callBridgedPayloadB != null)
{
context.Set(Result, new BridgedCallsOutput(callBridgedPayloadA, callBridgedPayloadB));
- await context.CompleteActivityAsync(new Outcomes("Bridged"));
- return;
+ await HandleBridgedAsync(context);
}
-
- context.CreateBookmark();
}
}
diff --git a/src/modules/Elsa.Telnyx/Activities/Dial.cs b/src/modules/Elsa.Telnyx/Activities/Dial.cs
index d02f0b9ac..2860648e2 100644
--- a/src/modules/Elsa.Telnyx/Activities/Dial.cs
+++ b/src/modules/Elsa.Telnyx/Activities/Dial.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Attributes;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Attributes;
using Elsa.Telnyx.Bookmarks;
using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
@@ -23,6 +24,11 @@ namespace Elsa.Telnyx.Activities;
[WebhookDriven(WebhookEventTypes.CallAnswered, WebhookEventTypes.CallHangup, WebhookEventTypes.CallMachineGreetingEnded, WebhookEventTypes.CallMachinePremiumGreetingEnded)]
public abstract class DialBase : ActivityBase
{
+ ///
+ protected DialBase(string? source = default, int? line = default) : base(source, line)
+ {
+ }
+
[Input(Description = "The DID or SIP URI to dial out and bridge to the given call.")]
public Input To { get; set; } = default!;
@@ -117,32 +123,57 @@ public abstract class DialBase : ActivityBase
}
}
+///
[FlowNode("Answered", "Hangup", "Voicemail")]
public class FlowDial : DialBase
{
+ private FlowDial([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
protected override async ValueTask OnHandleAnsweredAsync(ActivityExecutionContext context, CallAnsweredPayload payload) => await context.CompleteActivityWithOutcomesAsync("Answered");
+
+ ///
protected override async ValueTask OnHandleHangupAsync(ActivityExecutionContext context, CallHangupPayload payload) => await context.CompleteActivityWithOutcomesAsync("Hangup");
+
+ ///
protected override async ValueTask OnHandleMachineGreetingEndedAsync(ActivityExecutionContext context, CallMachineGreetingEndedBase payload) => await context.CompleteActivityWithOutcomesAsync("Voicemail");
}
+///
+/// Dial a phone number or SIP URI.
+///
public class Dial : DialBase
{
+ ///
+ public Dial([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
+ /// The to execute when the call was answered.
+ ///
[Port] public IActivity? Answered { get; set; }
+
+ ///
+ /// The to execute when there is no reply.
+ ///
[Port] public IActivity? Hangup { get; set; }
+
+ ///
+ /// The to execute when a robot answered the call.
+ ///
[Port] public IActivity? Voicemail { get; set; }
- protected override async ValueTask OnHandleAnsweredAsync(ActivityExecutionContext context, CallAnsweredPayload payload)
- {
+ ///
+ protected override async ValueTask OnHandleAnsweredAsync(ActivityExecutionContext context, CallAnsweredPayload payload) =>
await context.ScheduleActivityAsync(Answered);
- }
- protected override async ValueTask OnHandleHangupAsync(ActivityExecutionContext context, CallHangupPayload payload)
- {
- await context.ScheduleActivityAsync(Hangup);
- }
+ ///
+ protected override async ValueTask OnHandleHangupAsync(ActivityExecutionContext context, CallHangupPayload payload) => await context.ScheduleActivityAsync(Hangup);
- protected override async ValueTask OnHandleMachineGreetingEndedAsync(ActivityExecutionContext context, CallMachineGreetingEndedBase payload)
- {
+ ///
+ protected override async ValueTask OnHandleMachineGreetingEndedAsync(ActivityExecutionContext context, CallMachineGreetingEndedBase payload) =>
await context.ScheduleActivityAsync(Voicemail);
- }
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Activities/GatherUsingAudio.cs b/src/modules/Elsa.Telnyx/Activities/GatherUsingAudio.cs
index 7e562fe02..a691873a3 100644
--- a/src/modules/Elsa.Telnyx/Activities/GatherUsingAudio.cs
+++ b/src/modules/Elsa.Telnyx/Activities/GatherUsingAudio.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Attributes;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Attributes;
using Elsa.Telnyx.Bookmarks;
using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
@@ -21,6 +22,11 @@ namespace Elsa.Telnyx.Activities;
[WebhookDriven(WebhookEventTypes.CallGatherEnded)]
public class GatherUsingAudio : ActivityBase, IBookmarksPersistedHandler
{
+ ///
+ public GatherUsingAudio([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
///
/// The call control ID of the call from which to gather input. Leave empty to use the ambient call control ID, if there is any.
///
diff --git a/src/modules/Elsa.Telnyx/Activities/GatherUsingSpeak.cs b/src/modules/Elsa.Telnyx/Activities/GatherUsingSpeak.cs
index 5060b00fc..c839a5996 100644
--- a/src/modules/Elsa.Telnyx/Activities/GatherUsingSpeak.cs
+++ b/src/modules/Elsa.Telnyx/Activities/GatherUsingSpeak.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Attributes;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Attributes;
using Elsa.Telnyx.Bookmarks;
using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
@@ -22,6 +23,11 @@ namespace Elsa.Telnyx.Activities;
[WebhookDriven(WebhookEventTypes.CallGatherEnded)]
public class GatherUsingSpeak : ActivityBase, IBookmarksPersistedHandler
{
+ ///
+ public GatherUsingSpeak([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
///
/// The call control ID of the call from which to gather input. Leave empty to use the ambient call control ID, if there is any.
///
diff --git a/src/modules/Elsa.Telnyx/Activities/HangupCall.cs b/src/modules/Elsa.Telnyx/Activities/HangupCall.cs
index 0c9244af8..335a2dc4f 100644
--- a/src/modules/Elsa.Telnyx/Activities/HangupCall.cs
+++ b/src/modules/Elsa.Telnyx/Activities/HangupCall.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Client.Models;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
using Elsa.Telnyx.Extensions;
using Elsa.Workflows.Core;
@@ -10,20 +11,45 @@ using Refit;
namespace Elsa.Telnyx.Activities;
+///
[FlowNode("Done", "Disconnected")]
public class FlowHangupCall : HangupCallBase
{
+ ///
+ public FlowHangupCall([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
protected override ValueTask HandleDoneAsync(ActivityExecutionContext context) => context.CompleteActivityWithOutcomesAsync("Done");
+
+ ///
protected override ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => context.CompleteActivityWithOutcomesAsync("Disconnected");
}
+///
public class HangupCall : HangupCallBase
{
- [Port] public IActivity? Done { get; set; }
+ ///
+ public HangupCall([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
+ /// The to execute when the call was no longer active.
+ ///
[Port] public IActivity? Disconnected { get; set; }
- protected override async ValueTask HandleDoneAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Done, OnCompletedAsync);
+ ///
+ protected override async ValueTask HandleDoneAsync(ActivityExecutionContext context) => await context.CompleteActivityAsync(OnCompletedAsync);
+
+ ///
protected override async ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Disconnected, OnCompletedAsync);
+
+ ///
+ /// Executed when any child activity completed.
+ ///
+ private async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
}
///
@@ -32,6 +58,11 @@ public class HangupCall : HangupCallBase
[Activity(Constants.Namespace, "Hang up the call.", Kind = ActivityKind.Task)]
public abstract class HangupCallBase : ActivityBase
{
+ ///
+ protected HangupCallBase([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
///
/// Unique identifier and token for controlling the call.
///
@@ -57,7 +88,13 @@ public abstract class HangupCallBase : ActivityBase
}
}
+ ///
+ /// Executed when the call was hangup.
+ ///
protected abstract ValueTask HandleDoneAsync(ActivityExecutionContext context);
+
+ ///
+ /// Executed when the call was no longer active.
+ ///
protected abstract ValueTask HandleDisconnectedAsync(ActivityExecutionContext context);
- protected async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Activities/IncomingCall.cs b/src/modules/Elsa.Telnyx/Activities/IncomingCall.cs
index f422f787e..66ace6af3 100644
--- a/src/modules/Elsa.Telnyx/Activities/IncomingCall.cs
+++ b/src/modules/Elsa.Telnyx/Activities/IncomingCall.cs
@@ -1,3 +1,4 @@
+using System.Runtime.CompilerServices;
using Elsa.Expressions.Models;
using Elsa.Telnyx.Bookmarks;
using Elsa.Telnyx.Extensions;
@@ -11,6 +12,9 @@ using Elsa.Workflows.Management.Models;
namespace Elsa.Telnyx.Activities;
+///
+/// Triggered when an inbound phone call is received for any of the specified source or destination phone numbers.
+///
[Activity(
"Telnyx",
"Telnyx",
@@ -18,13 +22,27 @@ namespace Elsa.Telnyx.Activities;
Kind = ActivityKind.Trigger)]
public class IncomingCall : Trigger
{
+ ///
+ public IncomingCall([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
+ /// A list of destination numbers to respond to.
+ ///
[Input(Description = "A list of destination numbers to respond to.", UIHint = InputUIHints.MultiText)]
public Input> To { get; set; } = default!;
+ ///
+ /// A list of source numbers to respond to.
+ ///
[Input(Description = "A list of source numbers to respond to.", UIHint = InputUIHints.MultiText)]
public Input> From { get; set; } = default!;
- [Input(Description = "Match any inbound calls")]
+ ///
+ /// Match any inbound calls.
+ ///
+ [Input(Description = "Match any inbound calls.")]
public Input CatchAll { get; set; } = default!;
///
diff --git a/src/modules/Elsa.Telnyx/Activities/LookupNumber.cs b/src/modules/Elsa.Telnyx/Activities/LookupNumber.cs
index 309ba1236..0220d5d5f 100644
--- a/src/modules/Elsa.Telnyx/Activities/LookupNumber.cs
+++ b/src/modules/Elsa.Telnyx/Activities/LookupNumber.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Client.Models;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
using Elsa.Workflows.Core;
using Elsa.Workflows.Core.Attributes;
@@ -13,6 +14,11 @@ namespace Elsa.Telnyx.Activities;
[Activity(Constants.Namespace, "Returns information about the provided phone number.", Kind = ActivityKind.Task)]
public class LookupNumber : Activity
{
+ ///
+ public LookupNumber([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
///
/// The phone number to be looked up.
///
diff --git a/src/modules/Elsa.Telnyx/Activities/PlayAudio.cs b/src/modules/Elsa.Telnyx/Activities/PlayAudio.cs
index 6cd23802e..d2a6886ce 100644
--- a/src/modules/Elsa.Telnyx/Activities/PlayAudio.cs
+++ b/src/modules/Elsa.Telnyx/Activities/PlayAudio.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Attributes;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Attributes;
using Elsa.Telnyx.Bookmarks;
using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
@@ -14,20 +15,47 @@ using Refit;
namespace Elsa.Telnyx.Activities;
+///
[FlowNode("Playback started", "Disconnected")]
public class FlowPlayAudio : PlayAudioBase
{
+ ///
+ public FlowPlayAudio([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
protected override ValueTask HandlePlaybackStartedAsync(ActivityExecutionContext context) => context.CompleteActivityWithOutcomesAsync("Playback started");
+
+ ///
protected override ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => context.CompleteActivityWithOutcomesAsync("Disconnected");
}
+///
public class PlayAudio : PlayAudioBase
{
+ ///
+ public PlayAudio([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
+ /// The to execute when audio playback has started.
+ ///
[Port] public IActivity? PlaybackStarted { get; set; }
+
+ ///
+ /// The to execute when the call was no longer active.
+ ///
[Port] public IActivity? Disconnected { get; set; }
+ ///
protected override async ValueTask HandlePlaybackStartedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(PlaybackStarted, OnCompletedAsync);
+
+ ///
protected override async ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Disconnected, OnCompletedAsync);
+
+ private async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
}
///
@@ -38,6 +66,11 @@ public class PlayAudio : PlayAudioBase
[WebhookDriven(WebhookEventTypes.CallPlaybackStarted)]
public abstract class PlayAudioBase : ActivityBase, IBookmarksPersistedHandler
{
+ ///
+ protected PlayAudioBase([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
///
/// Unique identifier and token for controlling the call.
///
@@ -119,8 +152,16 @@ public abstract class PlayAudioBase : ActivityBase, IBookmarksPersistedHandler
///
protected override void Execute(ActivityExecutionContext context) => context.CreateBookmark(new WebhookEventBookmarkPayload(WebhookEventTypes.CallPlaybackStarted), ResumeAsync);
+ ///
+ /// Called when playback has started.
+ ///
protected abstract ValueTask HandlePlaybackStartedAsync(ActivityExecutionContext context);
+
+
+ ///
+ /// Called when the call was no longer active.
+ ///
protected abstract ValueTask HandleDisconnectedAsync(ActivityExecutionContext context);
- protected async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
+
private async ValueTask ResumeAsync(ActivityExecutionContext context) => await HandlePlaybackStartedAsync(context);
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Activities/SpeakText.cs b/src/modules/Elsa.Telnyx/Activities/SpeakText.cs
index c130c60cc..41504653d 100644
--- a/src/modules/Elsa.Telnyx/Activities/SpeakText.cs
+++ b/src/modules/Elsa.Telnyx/Activities/SpeakText.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Attributes;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Attributes;
using Elsa.Telnyx.Bookmarks;
using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
@@ -13,10 +14,18 @@ using Refit;
namespace Elsa.Telnyx.Activities;
+///
+/// Convert text to speech and play it back on the call.
+///
[Activity(Constants.Namespace, "Convert text to speech and play it back on the call.", Kind = ActivityKind.Task)]
[WebhookDriven(WebhookEventTypes.CallSpeakEnded)]
public abstract class SpeakTextBase : ActivityBase
{
+ ///
+ protected SpeakTextBase([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
///
/// Unique identifier and token for controlling the call.
///
@@ -105,31 +114,56 @@ public abstract class SpeakTextBase : ActivityBase
}
}
+ ///
+ /// Called when the call was no longer active.
+ ///
protected abstract ValueTask HandleDisconnected(ActivityExecutionContext context);
+
+ ///
+ /// Called when speaking has finished.
+ ///
protected abstract ValueTask HandleFinishedSpeaking(ActivityExecutionContext context);
private async ValueTask ResumeAsync(ActivityExecutionContext context) => await HandleFinishedSpeaking(context);
}
+///
[FlowNode("Finished speaking", "Disconnected")]
public class FlowSpeakText : SpeakTextBase
{
+ ///
+ public FlowSpeakText([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
protected override async ValueTask HandleDisconnected(ActivityExecutionContext context) => await context.CompleteActivityWithOutcomesAsync("Disconnected");
+
+ ///
protected override async ValueTask HandleFinishedSpeaking(ActivityExecutionContext context) => await context.CompleteActivityWithOutcomesAsync("Finished speaking");
}
+///
public class SpeakText : SpeakTextBase
{
- [Port]public IActivity? FinishedSpeaking { get; set; }
- [Port]public IActivity? Disconnected { get; set; }
+ ///
+ public SpeakText([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
- protected override async ValueTask HandleDisconnected(ActivityExecutionContext context)
- {
- await context.ScheduleActivityAsync(Disconnected);
- }
+ ///
+ /// The to execute when speaking has finished.
+ ///
+ [Port]public IActivity? FinishedSpeaking { get; set; }
+
+ ///
+ /// The to execute when the call was no longer active.
+ ///
+ [Port]public IActivity? Disconnected { get; set; }
- protected override async ValueTask HandleFinishedSpeaking(ActivityExecutionContext context)
- {
- await context.ScheduleActivityAsync(FinishedSpeaking);
- }
+ ///
+ protected override async ValueTask HandleDisconnected(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Disconnected);
+
+ ///
+ protected override async ValueTask HandleFinishedSpeaking(ActivityExecutionContext context) => await context.ScheduleActivityAsync(FinishedSpeaking);
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Activities/StartRecording.cs b/src/modules/Elsa.Telnyx/Activities/StartRecording.cs
index c4fb03f36..95ee46c98 100644
--- a/src/modules/Elsa.Telnyx/Activities/StartRecording.cs
+++ b/src/modules/Elsa.Telnyx/Activities/StartRecording.cs
@@ -1,4 +1,7 @@
-using Elsa.Telnyx.Client.Models;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Attributes;
+using Elsa.Telnyx.Bookmarks;
+using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
using Elsa.Telnyx.Extensions;
using Elsa.Telnyx.Payloads.Call;
@@ -12,28 +15,61 @@ using Refit;
namespace Elsa.Telnyx.Activities;
+///
[FlowNode("Recording finished", "Disconnected")]
public class FlowStartRecording : StartRecordingBase
{
+ ///
+ public FlowStartRecording([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
protected override ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => context.CompleteActivityWithOutcomesAsync("Disconnected");
+
+ ///
protected override ValueTask HandleCallRecordingSavedAsync(ActivityExecutionContext context) => context.CompleteActivityWithOutcomesAsync("Recording finished");
}
+///
public class StartRecording : StartRecordingBase
{
+ ///
+ public StartRecording([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
+ /// The to execute when recording has finished.
+ ///
[Port] public IActivity? RecordingFinished { get; set; }
+
+ ///
+ /// The to executed when the call was no longer active.
+ ///
[Port] public IActivity? Disconnected { get; set; }
+ ///
protected override async ValueTask HandleCallRecordingSavedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(RecordingFinished, OnCompletedAsync);
+
+ ///
protected override async ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Disconnected, OnCompletedAsync);
+
+ private async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
}
///
/// Start recording the call.
///
[Activity(Constants.Namespace, "Start recording the call.", Kind = ActivityKind.Task)]
+[WebhookDriven(WebhookEventTypes.CallRecordingSaved)]
public abstract class StartRecordingBase : ActivityBase
{
+ ///
+ protected StartRecordingBase(string? source = default, int? line = default) : base(source, line)
+ {
+ }
+
///
/// Unique identifier and token for controlling the call.
///
@@ -87,7 +123,8 @@ public abstract class StartRecordingBase : ActivityBase
+ /// Called when the recording was saved.
+ ///
protected abstract ValueTask HandleCallRecordingSavedAsync(ActivityExecutionContext context);
+
+
+ ///
+ /// Called when the call was no longer active.
+ ///
protected abstract ValueTask HandleDisconnectedAsync(ActivityExecutionContext context);
- protected async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
private async ValueTask ResumeAsync(ActivityExecutionContext context)
{
diff --git a/src/modules/Elsa.Telnyx/Activities/StopAudioPlayback.cs b/src/modules/Elsa.Telnyx/Activities/StopAudioPlayback.cs
index 325704027..dece1896a 100644
--- a/src/modules/Elsa.Telnyx/Activities/StopAudioPlayback.cs
+++ b/src/modules/Elsa.Telnyx/Activities/StopAudioPlayback.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Client.Models;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
using Elsa.Telnyx.Extensions;
using Elsa.Workflows.Core;
@@ -10,29 +11,55 @@ using Refit;
namespace Elsa.Telnyx.Activities;
-[FlowNode("Playback ended", "Disconnected")]
+///
+[FlowNode("Done", "Disconnected")]
public class FlowStopAudioPlayback : StopAudioPlaybackBase
{
- protected override ValueTask HandlePlaybackEndedAsync(ActivityExecutionContext context) => context.CompleteActivityWithOutcomesAsync("Playback ended");
+ ///
+ public FlowStopAudioPlayback([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
+ protected override ValueTask HandleDoneAsync(ActivityExecutionContext context) => context.CompleteActivityWithOutcomesAsync("Done");
+
+ ///
protected override ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => context.CompleteActivityWithOutcomesAsync("Disconnected");
}
+///
public class StopAudioPlayback : StopAudioPlaybackBase
{
- [Port] public IActivity? PlaybackEnded { get; set; }
+ ///
+ public StopAudioPlayback([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
+ ///
+ /// The to execute when the call was no longer active.
+ ///
[Port] public IActivity? Disconnected { get; set; }
- protected override async ValueTask HandlePlaybackEndedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(PlaybackEnded, OnCompletedAsync);
+ ///
+ protected override async ValueTask HandleDoneAsync(ActivityExecutionContext context) => await context.CompleteActivityAsync();
+
+ ///
protected override async ValueTask HandleDisconnectedAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Disconnected, OnCompletedAsync);
+
+ private async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
}
///
/// Stop audio playback.
///
[Activity(Constants.Namespace, Description = "Stop audio playback.", Kind = ActivityKind.Task)]
-[FlowNode("Playback ended", "Disconnected")]
public abstract class StopAudioPlaybackBase : ActivityBase
{
+ ///
+ protected StopAudioPlaybackBase(string? source = default, int? line = default) : base(source, line)
+ {
+ }
+
///
/// Unique identifier and token for controlling the call.
///
@@ -53,6 +80,7 @@ public abstract class StopAudioPlaybackBase : ActivityBase
)]
public Input Stop { get; set; } = new("all");
+ ///
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
var request = new StopAudioPlaybackRequest(Stop.Get(context));
@@ -62,18 +90,21 @@ public abstract class StopAudioPlaybackBase : ActivityBase
try
{
await telnyxClient.Calls.StopAudioPlaybackAsync(callControlId, request, context.CancellationToken);
- context.CreateBookmark(ResumeAsync);
+ await HandleDoneAsync(context);
}
catch (ApiException e)
{
if (!await e.CallIsNoLongerActiveAsync()) throw;
- await context.CompleteActivityWithOutcomesAsync("Disconnected");
+ await HandleDisconnectedAsync(context);
}
}
-
- protected abstract ValueTask HandlePlaybackEndedAsync(ActivityExecutionContext context);
+
+ ///
+ /// Called when audio playback is stopping.
+ ///
+ protected abstract ValueTask HandleDoneAsync(ActivityExecutionContext context);
+ ///
+ /// Called when the call was no longer active.
+ ///
protected abstract ValueTask HandleDisconnectedAsync(ActivityExecutionContext context);
- protected async ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync();
-
- private async ValueTask ResumeAsync(ActivityExecutionContext context) => await context.CompleteActivityWithOutcomesAsync("Playback ended");
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Activities/StopRecording.cs b/src/modules/Elsa.Telnyx/Activities/StopRecording.cs
index 2446a35b1..92aad50a3 100644
--- a/src/modules/Elsa.Telnyx/Activities/StopRecording.cs
+++ b/src/modules/Elsa.Telnyx/Activities/StopRecording.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Client.Models;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
using Elsa.Telnyx.Extensions;
using Elsa.Workflows.Core;
@@ -16,6 +17,11 @@ namespace Elsa.Telnyx.Activities;
[FlowNode("Recording stopped", "Disconnected")]
public class StopRecording : ActivityBase
{
+ ///
+ public StopRecording([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
///
/// Unique identifier and token for controlling the call.
///
@@ -44,6 +50,4 @@ public class StopRecording : ActivityBase
await context.CompleteActivityWithOutcomesAsync("Disconnected");
}
}
-
- private static string? EmptyToNull(string? value) => value is "" ? null : value;
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Activities/TransferCall.cs b/src/modules/Elsa.Telnyx/Activities/TransferCall.cs
index 587b3cd62..c97f49159 100644
--- a/src/modules/Elsa.Telnyx/Activities/TransferCall.cs
+++ b/src/modules/Elsa.Telnyx/Activities/TransferCall.cs
@@ -1,4 +1,5 @@
-using Elsa.Telnyx.Client.Models;
+using System.Runtime.CompilerServices;
+using Elsa.Telnyx.Client.Models;
using Elsa.Telnyx.Client.Services;
using Elsa.Telnyx.Extensions;
using Elsa.Telnyx.Payloads.Call;
@@ -18,6 +19,11 @@ namespace Elsa.Telnyx.Activities;
[FlowNode("Transferred", "Hangup", "Disconnected")]
public class TransferCall : Activity
{
+ ///
+ public TransferCall([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
///
/// Unique identifier and token for controlling the call.
///
diff --git a/src/modules/Elsa.Telnyx/Activities/WebhookEvent.cs b/src/modules/Elsa.Telnyx/Activities/WebhookEvent.cs
index c5638f557..c400948fc 100644
--- a/src/modules/Elsa.Telnyx/Activities/WebhookEvent.cs
+++ b/src/modules/Elsa.Telnyx/Activities/WebhookEvent.cs
@@ -1,5 +1,8 @@
using System.ComponentModel;
+using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
+using Elsa.Telnyx.Attributes;
using Elsa.Telnyx.Bookmarks;
using Elsa.Telnyx.Helpers;
using Elsa.Telnyx.Models;
@@ -17,22 +20,25 @@ namespace Elsa.Telnyx.Activities;
[Browsable(false)]
public class WebhookEvent : ActivityBase
{
+ ///
[JsonConstructor]
- public WebhookEvent()
+ public WebhookEvent([CallerFilePath]string? source = default, [CallerLineNumber]int? line = default) : base(source, line)
{
}
- public WebhookEvent(string eventType, Variable result)
+ ///
+ public WebhookEvent(string eventType, string activityTypeName, Variable result, int version = 1, [CallerFilePath]string? source = default, [CallerLineNumber]int? line = default)
+ : base(activityTypeName, version, source, line)
{
- EventType = new (eventType);
+ EventType = eventType;
Result = new(result);
}
///
/// The Telnyx webhook event type to listen for.
///
- [Input(Description = "The Telnyx webhook event type to listen for")]
- public Input EventType { get; set; } = default!;
+ [Description("The Telnyx webhook event type to listen for")]
+ public string EventType { get; set; } = default!;
///
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
@@ -41,9 +47,10 @@ public class WebhookEvent : ActivityBase
await Resume(context);
else
{
- var eventType = context.Get(EventType)!;
+ var eventType = EventType;
var payload = new WebhookEventBookmarkPayload(eventType);
- context.CreateBookmark(payload, Resume);
+
+ context.CreateBookmark(new CreateBookmarkOptions(payload, Resume, Type));
}
}
diff --git a/src/modules/Elsa.Telnyx/Bookmarks/CallBridgedBookmarkPayload.cs b/src/modules/Elsa.Telnyx/Bookmarks/CallBridgedBookmarkPayload.cs
new file mode 100644
index 000000000..4cf148b22
--- /dev/null
+++ b/src/modules/Elsa.Telnyx/Bookmarks/CallBridgedBookmarkPayload.cs
@@ -0,0 +1,3 @@
+namespace Elsa.Telnyx.Bookmarks;
+
+public record CallBridgedBookmarkPayload(string CallControlId);
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Client/Models/Responses.cs b/src/modules/Elsa.Telnyx/Client/Models/Responses.cs
index bd88f2aff..45f6dfb1e 100644
--- a/src/modules/Elsa.Telnyx/Client/Models/Responses.cs
+++ b/src/modules/Elsa.Telnyx/Client/Models/Responses.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
+using Dahomey.Json.Util;
namespace Elsa.Telnyx.Client.Models;
@@ -10,7 +11,13 @@ public record DialResponse(
string CallSessionId,
bool IsAlive,
string RecordType
-);
+)
+{
+ [JsonConstructor]
+ public DialResponse() : this(default!, default!, default!, default, default!)
+ {
+ }
+}
public record NumberLookupResponse(
CallerName CallerName,
@@ -21,7 +28,13 @@ public record NumberLookupResponse(
string PhoneNumber,
Portability Portability,
string RecordType
-);
+)
+{
+ [JsonConstructor]
+ public NumberLookupResponse() : this(default!, default!, default!, default!, default!, default!, default!, default!)
+ {
+ }
+}
public record Portability(
string Altspid,
@@ -37,7 +50,13 @@ public record Portability(
string SpidCarrierName,
string SpidCarrierType,
string State
-);
+)
+{
+ [JsonConstructor]
+ public Portability() : this(default!, default!, default!, default!, default!, default!, default!, default, default!, default!, default!, default!, default!)
+ {
+ }
+}
public record Carrier(
string ErrorCode,
@@ -45,7 +64,13 @@ public record Carrier(
int MobileNetworkCode,
string Name,
string Type
-);
+)
+{
+ [JsonConstructor]
+ public Carrier() : this(default!, default!, default, default!, default!)
+ {
+ }
+}
public record CallerName
{
diff --git a/src/modules/Elsa.Telnyx/Handlers/TriggerBridgeCallActivities.cs b/src/modules/Elsa.Telnyx/Handlers/TriggerBridgeCallActivities.cs
new file mode 100644
index 000000000..c008f158a
--- /dev/null
+++ b/src/modules/Elsa.Telnyx/Handlers/TriggerBridgeCallActivities.cs
@@ -0,0 +1,43 @@
+using Elsa.Mediator.Services;
+using Elsa.Telnyx.Activities;
+using Elsa.Telnyx.Bookmarks;
+using Elsa.Telnyx.Events;
+using Elsa.Telnyx.Extensions;
+using Elsa.Telnyx.Payloads.Abstract;
+using Elsa.Telnyx.Payloads.Call;
+using Elsa.Workflows.Core;
+using Elsa.Workflows.Core.Helpers;
+using Elsa.Workflows.Runtime.Services;
+using Microsoft.Extensions.Logging;
+
+namespace Elsa.Telnyx.Handlers;
+
+///
+/// Triggers all workflows starting with or blocked on a activity.
+///
+internal class TriggerBridgeCallActivities : INotificationHandler
+{
+ private readonly IWorkflowRuntime _workflowRuntime;
+ private readonly ILogger _logger;
+
+ public TriggerBridgeCallActivities(IWorkflowRuntime workflowRuntime, ILogger logger)
+ {
+ _workflowRuntime = workflowRuntime;
+ _logger = logger;
+ }
+
+ public async Task HandleAsync(TelnyxWebhookReceived notification, CancellationToken cancellationToken)
+ {
+ var webhook = notification.Webhook;
+ var payload = webhook.Data.Payload;
+
+ if (payload is not CallBridgedPayload callBridgedPayload)
+ return;
+
+ var correlationId = ((Payload)webhook.Data.Payload).GetCorrelationId();;
+ var activityTypeName = ActivityTypeNameHelper.GenerateTypeName();
+ var input = new Dictionary().AddInput(callBridgedPayload);
+ var callBridgedBookmarkPayload = new CallBridgedBookmarkPayload(callBridgedPayload.CallControlId);
+ await _workflowRuntime.TriggerWorkflowsAsync(activityTypeName, callBridgedBookmarkPayload, new TriggerWorkflowsRuntimeOptions(correlationId, input), cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Handlers/TriggerIncomingCallActivities.cs b/src/modules/Elsa.Telnyx/Handlers/TriggerIncomingCallActivities.cs
index 4f25f9975..a79a26769 100644
--- a/src/modules/Elsa.Telnyx/Handlers/TriggerIncomingCallActivities.cs
+++ b/src/modules/Elsa.Telnyx/Handlers/TriggerIncomingCallActivities.cs
@@ -34,6 +34,9 @@ internal class TriggerIncomingCallActivities : INotificationHandler();
var input = new Dictionary().AddInput(webhook);
diff --git a/src/modules/Elsa.Telnyx/Handlers/TriggerWebhookActivities.cs b/src/modules/Elsa.Telnyx/Handlers/TriggerWebhookActivities.cs
index f7a0881f0..9fe70afb4 100644
--- a/src/modules/Elsa.Telnyx/Handlers/TriggerWebhookActivities.cs
+++ b/src/modules/Elsa.Telnyx/Handlers/TriggerWebhookActivities.cs
@@ -7,6 +7,7 @@ using Elsa.Telnyx.Events;
using Elsa.Telnyx.Extensions;
using Elsa.Telnyx.Payloads.Abstract;
using Elsa.Workflows.Core;
+using Elsa.Workflows.Core.Helpers;
using Elsa.Workflows.Runtime.Services;
using Microsoft.Extensions.Logging;
@@ -31,8 +32,7 @@ internal class TriggerWebhookActivities : INotificationHandler()?.ActivityType}";
+ var activityType = payload.GetType().GetCustomAttribute()?.ActivityType;
if (activityType == null)
return;
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallAnsweredPayload.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallAnsweredPayload.cs
index 0f57b7d8d..f29b4328e 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallAnsweredPayload.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallAnsweredPayload.cs
@@ -2,10 +2,9 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallAnswered, ActivityTypeName, "Call Answered", "Triggered when an incoming call is answered.")]
+[Webhook(WebhookEventTypes.CallAnswered, WebhookActivityTypeNames.CallAnswered, "Call Answered", "Triggered when an incoming call is answered.")]
public sealed record CallAnsweredPayload : CallPayload
{
- public const string ActivityTypeName = "CallAnswered";
public string From { get; init; } = default!;
public string To { get; init; } = default!;
public string State { get; init; } = default!;
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallBridgedPayload.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallBridgedPayload.cs
index b5e0b2136..42d5f121d 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallBridgedPayload.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallBridgedPayload.cs
@@ -2,10 +2,9 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallBridged, ActivityTypeName, "Call Bridged", "Triggered when an a call is bridged.")]
+[Webhook(WebhookEventTypes.CallBridged, WebhookActivityTypeNames.CallBridged, "Call Bridged", "Triggered when an a call is bridged.")]
public sealed record CallBridgedPayload : CallPayload
{
- public const string ActivityTypeName = "CallBridged";
public string From { get; init; } = default!;
public string To { get; init; } = default!;
public string State { get; init; } = default!;
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallDtmfReceivedPayload.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallDtmfReceivedPayload.cs
index 36d2f3e42..d1629dfcb 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallDtmfReceivedPayload.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallDtmfReceivedPayload.cs
@@ -2,10 +2,9 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallDtmfReceived, ActivityTypeName, "Call DTMF Received", "Triggered when DTMF input is received.")]
+[Webhook(WebhookEventTypes.CallDtmfReceived, WebhookActivityTypeNames.CallDtmfReceived, "Call DTMF Received", "Triggered when DTMF input is received.")]
public sealed record CallDtmfReceivedPayload : CallPayload
{
- public const string ActivityTypeName = "CallDtmfReceived";
public string Digit { get; set; } = default!;
public string From { get; set; } = default!;
public string To { get; set; } = default!;
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallGatherEndedPayload.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallGatherEndedPayload.cs
index 2d688a0f6..ccc2dccb1 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallGatherEndedPayload.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallGatherEndedPayload.cs
@@ -2,10 +2,9 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallGatherEnded, ActivityTypeName, "Call Gather Ended", "Triggered when an call gather has ended.")]
+[Webhook(WebhookEventTypes.CallGatherEnded, WebhookActivityTypeNames.CallGatherEnded, "Call Gather Ended", "Triggered when an call gather has ended.")]
public sealed record CallGatherEndedPayload : CallPayload
{
- public const string ActivityTypeName = "CallGatherEnded";
public string Digits { get; set; } = default!;
public string From { get; set; } = default!;
public string To { get; set; } = default!;
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallHangupPayload.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallHangupPayload.cs
index 1c9850789..8f3a7e9ce 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallHangupPayload.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallHangupPayload.cs
@@ -2,10 +2,9 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallHangup, ActivityTypeName, "Call Hangup", "Triggered when an incoming call was hangup.")]
+[Webhook(WebhookEventTypes.CallHangup, WebhookActivityTypeNames.CallHangup, "Call Hangup", "Triggered when an incoming call was hangup.")]
public sealed record CallHangupPayload : CallPayload
{
- public const string ActivityTypeName = "CallHangup";
public DateTimeOffset StartTime { get; init; }
public DateTimeOffset EndTime { get; init; }
public string SipHangupCause { get; init; } = default!;
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallInitiatedPayload.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallInitiatedPayload.cs
index d06ec4100..cd17d6086 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallInitiatedPayload.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallInitiatedPayload.cs
@@ -2,10 +2,9 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallInitiated, ActivityTypeName, "Call Initiated", "Triggered when an incoming call is received.")]
+[Webhook(WebhookEventTypes.CallInitiated, WebhookActivityTypeNames.CallInitiated, "Call Initiated", "Triggered when an incoming call is received.")]
public sealed record CallInitiatedPayload : CallPayload
-{
- public const string ActivityTypeName = "CallInitiated";
+{
public string Direction { get; init; } = default!;
public string State { get; init; } = default!;
public string To { get; init; } = default!;
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallMachineGreetingEnded.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallMachineGreetingEnded.cs
index cd0f75813..0e05fddb3 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallMachineGreetingEnded.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallMachineGreetingEnded.cs
@@ -2,8 +2,5 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallMachineGreetingEnded, ActivityTypeName, "Call Machine Greeting Ended", "Triggered when a machine greeting has ended.")]
-public sealed record CallMachineGreetingEnded : CallMachineGreetingEndedBase
-{
- public const string ActivityTypeName = "CallMachineGreetingEnded";
-}
\ No newline at end of file
+[Webhook(WebhookEventTypes.CallMachineGreetingEnded, WebhookActivityTypeNames.CallMachineGreetingEnded, "Call Machine Greeting Ended", "Triggered when a machine greeting has ended.")]
+public sealed record CallMachineGreetingEnded : CallMachineGreetingEndedBase;
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallMachinePremiumDetectionEnded.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallMachinePremiumDetectionEnded.cs
index d1706ad5e..69c3c67e8 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallMachinePremiumDetectionEnded.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallMachinePremiumDetectionEnded.cs
@@ -2,8 +2,12 @@ using Elsa.Telnyx.Attributes;
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallMachinePremiumDetectionEnded, ActivityTypeName, "Call Machine Premium Detection Ended", "Triggered when machine detection has ended.")]
+[Webhook(
+ WebhookEventTypes.CallMachinePremiumDetectionEnded,
+ WebhookActivityTypeNames.CallMachinePremiumDetectionEnded,
+ "Call Machine Premium Detection Ended",
+ "Triggered when machine detection has ended."
+)]
public sealed record CallMachinePremiumDetectionEnded : CallMachineDetectionEndedBase
{
- public const string ActivityTypeName = nameof(CallMachinePremiumDetectionEnded);
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallMachinePremiumGreetingEnded.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallMachinePremiumGreetingEnded.cs
index 56499c094..1ed9a9238 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallMachinePremiumGreetingEnded.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallMachinePremiumGreetingEnded.cs
@@ -2,8 +2,10 @@ using Elsa.Telnyx.Attributes;
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallMachinePremiumGreetingEnded, ActivityTypeName, "Call Machine Premium Greeting Ended", "Triggered when a machine greeting has ended.")]
-public sealed record CallMachinePremiumGreetingEnded : CallMachineGreetingEndedBase
-{
- public const string ActivityTypeName = nameof(CallMachinePremiumGreetingEnded);
-}
\ No newline at end of file
+[Webhook(
+ WebhookEventTypes.CallMachinePremiumGreetingEnded,
+ WebhookActivityTypeNames.CallMachinePremiumGreetingEnded,
+ "Call Machine Premium Greeting Ended",
+ "Triggered when a machine greeting has ended."
+)]
+public sealed record CallMachinePremiumGreetingEnded : CallMachineGreetingEndedBase;
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallPlaybackEndedPayload.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallPlaybackEndedPayload.cs
index 20cd6c38d..700bd93d9 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallPlaybackEndedPayload.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallPlaybackEndedPayload.cs
@@ -2,9 +2,8 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallPlaybackEnded, ActivityTypeName, "Call Playback Ended", "Triggered when an audio playback has ended.")]
+[Webhook(WebhookEventTypes.CallPlaybackEnded, WebhookActivityTypeNames.CallPlaybackEnded, "Call Playback Ended", "Triggered when an audio playback has ended.")]
public sealed record CallPlaybackEndedPayload : CallPlayback
{
- public const string ActivityTypeName = "CallPlaybackEnded";
public string Status { get; set; } = default!;
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallPlaybackStartedPayload.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallPlaybackStartedPayload.cs
index 122c4cc10..ab624a8fc 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallPlaybackStartedPayload.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallPlaybackStartedPayload.cs
@@ -2,8 +2,5 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallPlaybackStarted, ActivityTypeName, "Call Playback Started", "Triggered when an audio playback has started.")]
-public sealed record CallPlaybackStartedPayload : CallPlayback
-{
- public const string ActivityTypeName = "CallPlaybackStarted";
-}
\ No newline at end of file
+[Webhook(WebhookEventTypes.CallPlaybackStarted, WebhookActivityTypeNames.CallPlaybackStarted, "Call Playback Started", "Triggered when an audio playback has started.")]
+public sealed record CallPlaybackStartedPayload : CallPlayback;
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallRecordingSavedPayload.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallRecordingSavedPayload.cs
index 3820a1839..b06d0c155 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallRecordingSavedPayload.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallRecordingSavedPayload.cs
@@ -2,10 +2,9 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallRecordingSaved, ActivityTypeName, "Call Recording Saved", "Triggered when a recording has been saved.")]
+[Webhook(WebhookEventTypes.CallRecordingSaved, WebhookActivityTypeNames.CallRecordingSaved, "Call Recording Saved", "Triggered when a recording has been saved.")]
public sealed record CallRecordingSavedPayload : CallPayload
{
- public const string ActivityTypeName = "CallRecordingSaved";
public string Channels { get; set; } = default!;
public CallRecordingUrls PublicRecordingUrls { get; set; } = default!;
public CallRecordingUrls RecordingUrls { get; set; } = default!;
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallSpeakEnded.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallSpeakEnded.cs
index 35b50bfd0..940c5612b 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallSpeakEnded.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallSpeakEnded.cs
@@ -2,8 +2,5 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallSpeakEnded, ActivityTypeName, "Call Speak Ended", "Triggered when speaking has ended.")]
-public sealed record CallSpeakEnded : CallPayload
-{
- public const string ActivityTypeName = "CallSpeakEnded";
-}
\ No newline at end of file
+[Webhook(WebhookEventTypes.CallSpeakEnded, WebhookActivityTypeNames.CallSpeakEnded, "Call Speak Ended", "Triggered when speaking has ended.")]
+public sealed record CallSpeakEnded : CallPayload;
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Payloads/Call/CallSpeakStarted.cs b/src/modules/Elsa.Telnyx/Payloads/Call/CallSpeakStarted.cs
index bb498efed..dbde3fec1 100644
--- a/src/modules/Elsa.Telnyx/Payloads/Call/CallSpeakStarted.cs
+++ b/src/modules/Elsa.Telnyx/Payloads/Call/CallSpeakStarted.cs
@@ -2,8 +2,5 @@
namespace Elsa.Telnyx.Payloads.Call;
-[Webhook(WebhookEventTypes.CallSpeakStarted, ActivityTypeName, "Call Speak Started", "Triggered when speaking has started.")]
-public sealed record CallSpeakStarted : CallPayload
-{
- public const string ActivityTypeName = "CallSpeakStarted";
-}
\ No newline at end of file
+[Webhook(WebhookEventTypes.CallSpeakStarted, WebhookActivityTypeNames.CallSpeakStarted, "Call Speak Started", "Triggered when speaking has started.")]
+public sealed record CallSpeakStarted : CallPayload;
\ No newline at end of file
diff --git a/src/modules/Elsa.Telnyx/Providers/WebhookEventActivityProvider.cs b/src/modules/Elsa.Telnyx/Providers/WebhookEventActivityProvider.cs
index 79ea53ba2..2584e78c6 100644
--- a/src/modules/Elsa.Telnyx/Providers/WebhookEventActivityProvider.cs
+++ b/src/modules/Elsa.Telnyx/Providers/WebhookEventActivityProvider.cs
@@ -39,9 +39,7 @@ public class WebhookEventActivityProvider : IActivityProvider
private ActivityDescriptor CreateDescriptor(Type payloadType)
{
var webhookAttribute = payloadType.GetCustomAttribute() ?? throw new Exception($"No WebhookAttribute found on payload type {payloadType}");
- var ns = Constants.Namespace;
var typeName = webhookAttribute.ActivityType;
- var fullTypeName = $"{ns}.{typeName}";
var displayNameAttr = payloadType.GetCustomAttribute();
var displayName = displayNameAttr?.DisplayName ?? webhookAttribute.DisplayName;
var categoryAttr = payloadType.GetCustomAttribute();
@@ -51,7 +49,7 @@ public class WebhookEventActivityProvider : IActivityProvider
return new()
{
- TypeName = fullTypeName,
+ TypeName = typeName,
Version = 1,
DisplayName = displayName,
Description = description,
@@ -62,8 +60,8 @@ public class WebhookEventActivityProvider : IActivityProvider
Constructor = context =>
{
var activity = _activityFactory.Create(context);
- activity.Type = fullTypeName;
- activity.EventType = new Input(webhookAttribute!.EventType);
+ activity.Type = typeName;
+ activity.EventType = webhookAttribute!.EventType;
return activity;
}
diff --git a/src/modules/Elsa.Telnyx/WebhookActivityTypeNames.cs b/src/modules/Elsa.Telnyx/WebhookActivityTypeNames.cs
new file mode 100644
index 000000000..e0b939045
--- /dev/null
+++ b/src/modules/Elsa.Telnyx/WebhookActivityTypeNames.cs
@@ -0,0 +1,20 @@
+namespace Elsa.Telnyx;
+
+public static class WebhookActivityTypeNames
+{
+ public const string CallAnswered = $"{Constants.Namespace}.{nameof(CallAnswered)}";
+ public const string CallBridged = $"{Constants.Namespace}.{nameof(CallBridged)}";
+ public const string CallDtmfReceived = $"{Constants.Namespace}.{nameof(CallDtmfReceived)}";
+ public const string CallGatherEnded = $"{Constants.Namespace}.{nameof(CallGatherEnded)}";
+ public const string CallHangup = $"{Constants.Namespace}.{nameof(CallHangup)}";
+ public const string CallInitiated = $"{Constants.Namespace}.{nameof(CallInitiated)}";
+ public const string CallMachineGreetingEnded = $"{Constants.Namespace}.{nameof(CallMachineGreetingEnded)}";
+ public const string CallMachinePremiumGreetingEnded = $"{Constants.Namespace}.{nameof(CallMachinePremiumGreetingEnded)}";
+ public const string CallMachineDetectionEnded = $"{Constants.Namespace}.{nameof(CallMachineDetectionEnded)}";
+ public const string CallMachinePremiumDetectionEnded = $"{Constants.Namespace}.{nameof(CallMachinePremiumDetectionEnded)}";
+ public const string CallPlaybackStarted = $"{Constants.Namespace}.{nameof(CallPlaybackStarted)}";
+ public const string CallPlaybackEnded = $"{Constants.Namespace}.{nameof(CallPlaybackEnded)}";
+ public const string CallRecordingSaved = $"{Constants.Namespace}.{nameof(CallRecordingSaved)}";
+ public const string CallSpeakStarted = $"{Constants.Namespace}.{nameof(CallSpeakStarted)}";
+ public const string CallSpeakEnded = $"{Constants.Namespace}.{nameof(CallSpeakEnded)}";
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Activities/Break.cs b/src/modules/Elsa.Workflows.Core/Activities/Break.cs
index 4efc328fe..d636eaec8 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Break.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Break.cs
@@ -1,12 +1,21 @@
+using System.Runtime.CompilerServices;
using Elsa.Workflows.Core.Attributes;
using Elsa.Workflows.Core.Models;
using Elsa.Workflows.Core.Signals;
namespace Elsa.Workflows.Core.Activities;
-[Activity("Elsa", "Control Flow", "Break out of a loop")]
+///
+/// Break out of a loop.
+///
+[Activity("Elsa", "Control Flow", "Break out of a loop.")]
public class Break : Activity
{
+ ///
+ public Break([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
+ {
+ }
+
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
await context.SendSignalAsync(new BreakSignal());
diff --git a/src/modules/Elsa.Workflows.Core/Activities/Complete.cs b/src/modules/Elsa.Workflows.Core/Activities/Complete.cs
index 23b0c15bc..8b333a742 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Complete.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Complete.cs
@@ -1,4 +1,5 @@
using System.ComponentModel;
+using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using Elsa.Expressions.Models;
using Elsa.Workflows.Core.Activities.Flowchart.Models;
@@ -16,27 +17,33 @@ public class Complete : Activity
{
///
[JsonConstructor]
- public Complete()
- {
- }
-
- ///
- public Complete(params string[] outcomes) : this(new Input>(outcomes))
+ public Complete([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
{
}
///
- public Complete(Func> outcomes) : this(new Input>(outcomes))
+ public Complete(IEnumerable outcomes, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default)
+ : this(new Input>(outcomes.ToList()), source, line)
{
}
///
- public Complete(Func outcome) : this(context => new[] { outcome(context) })
+ public Complete(Func> outcomes, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default)
+ : this(new Input>(outcomes), source, line)
{
}
///
- public Complete(Input> outcomes) => Outcomes = outcomes;
+ public Complete(Func outcome, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default)
+ : this(context => new[] { outcome(context) }, source, line)
+ {
+ }
+
+ ///
+ public Complete(Input> outcomes, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : this(source, line)
+ {
+ Outcomes = outcomes;
+ }
///
/// The outcome or set of outcomes to complete this activity with.
diff --git a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
index 3f5e6cede..b501fc107 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
@@ -1,4 +1,5 @@
using System.ComponentModel;
+using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using Elsa.Expressions.Models;
using Elsa.Workflows.Core.Activities.Flowchart.Models;
@@ -15,7 +16,7 @@ namespace Elsa.Workflows.Core.Activities;
public abstract class Composite : ActivityBase
{
///
- protected Composite()
+ protected Composite(string? source = default, int? line = default) : base(source, line)
{
OnSignalReceived(OnCompleteCompositeSignal);
}
@@ -70,29 +71,73 @@ public abstract class Composite : ActivityBase
private async ValueTask OnCompleteCompositeSignal(CompleteCompositeSignal signal, SignalContext context)
{
- var activityExecutionContext = context.ReceiverActivityExecutionContext;
-
- // Remove the existing completed handler.
- activityExecutionContext.WorkflowExecutionContext.PopCompletionCallback(activityExecutionContext, Root);
-
- // Complete this activity.
- await activityExecutionContext.CompleteActivityAsync(signal.Result);
+ // Complete the sender first so that it notifies its parents to complete.
+ await context.SenderActivityExecutionContext.CompleteActivityAsync();
+
+ // Then complete this activity.
+ await context.ReceiverActivityExecutionContext.CompleteActivityAsync(signal.Result);
context.StopPropagation();
}
- protected static Inline Inline(Func activity) => new(activity);
- protected static Inline Inline(Func activity) => new(activity);
- protected static Inline Inline(Action activity) => new(activity);
- protected static Inline Inline(Action activity) => new(activity);
- protected static Inline Inline(Func> activity, MemoryBlockReference? output = default) => new(activity, output);
- protected static Inline Inline(Func> activity, MemoryBlockReference? output = default) => new(activity, output);
- protected static Inline Inline(Func activity, MemoryBlockReference? output = default) => new(activity, output);
- protected static Inline Inline(Func activity, MemoryBlockReference? output = default) => new(activity, output);
+ ///
+ /// Creates a new activity.
+ ///
+ protected static Inline From(Func activity, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(activity, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static Inline From(Func activity, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(activity, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static Inline From(Action activity, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(activity, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static Inline From(Action activity, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(activity, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static Inline From(Func> activity, MemoryBlockReference? output = default, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(activity, output, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static Inline From(Func> activity, MemoryBlockReference? output = default, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(activity, output, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static Inline From(Func activity, MemoryBlockReference? output, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(activity, output, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static Inline Inline(Func activity, MemoryBlockReference? output = default, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(activity, output, source, line);
- protected static SetVariable SetVariable(Variable variable, T value) => new(variable, value);
- protected static SetVariable SetVariable(Variable variable, Func value) => new(variable, value);
- protected static SetVariable SetVariable(Variable variable, Func value) => new(variable, value);
- protected static SetVariable SetVariable(Variable variable, Variable value) => new(variable, value);
+ ///
+ /// Creates a new activity.
+ ///
+ protected static SetVariable SetVariable(Variable variable, T value, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(variable, value, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static SetVariable SetVariable(Variable variable, Func value, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(variable, value, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static SetVariable SetVariable(Variable variable, Func value, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(variable, value, source, line);
+
+ ///
+ /// Creates a new activity.
+ ///
+ protected static SetVariable SetVariable(Variable variable, Variable value, [CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) => new(variable, value, source, line);
}
///
@@ -101,7 +146,7 @@ public abstract class Composite : ActivityBase
public abstract class Composite : ActivityBase
{
///
- protected Composite()
+ protected Composite([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
{
OnSignalReceived(OnCompleteCompositeSignal);
}
@@ -128,18 +173,18 @@ public abstract class Composite : ActivityBase
{
}
- private async ValueTask OnRootCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext)
- {
- await OnCompletedAsync(context, childContext);
- await context.CompleteActivityAsync();
- }
-
+ ///
+ /// Override this method to handle the completion event for this composite activity.
+ ///
protected virtual ValueTask OnCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext)
{
OnCompleted(context, childContext);
return new();
}
+ ///
+ /// Override this method to handle the completion event for this composite activity.
+ ///
protected virtual void OnCompleted(ActivityExecutionContext context, ActivityExecutionContext childContext)
{
}
@@ -154,6 +199,12 @@ public abstract class Composite : ActivityBase
///
protected async Task CompleteAsync(ActivityExecutionContext context, params string[] outcomes) => await CompleteAsync(context, new Outcomes(outcomes));
+ private async ValueTask OnRootCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext)
+ {
+ await OnCompletedAsync(context, childContext);
+ await context.CompleteActivityAsync();
+ }
+
private async ValueTask OnCompleteCompositeSignal(CompleteCompositeSignal signal, SignalContext context)
{
var activityExecutionContext = context.ReceiverActivityExecutionContext;
@@ -166,12 +217,43 @@ public abstract class Composite : ActivityBase
context.StopPropagation();
}
+ ///
+ /// Creates a new activity.
+ ///
protected static Inline From(Func activity) => new(activity);
+
+ ///
+ /// Creates a new activity.
+ ///
protected static Inline From(Func activity) => new(activity);
+
+ ///
+ /// Creates a new activity.
+ ///
protected static Inline From(Action activity) => new(activity);
+
+ ///
+ /// Creates a new activity.
+ ///
protected static Inline From(Action activity) => new(activity);
+
+ ///
+ /// Creates a new activity.
+ ///
protected static Inline From(Func> activity, MemoryBlockReference? output = default) => new(activity, output);
+
+ ///
+ /// Creates a new activity.
+ ///
protected static Inline From(Func> activity, MemoryBlockReference? output = default) => new(activity, output);
+
+ ///
+ /// Creates a new activity.
+ ///
protected static Inline From(Func activity, MemoryBlockReference? output = default) => new(activity, output);
+
+ ///
+ /// Creates a new activity.
+ ///
protected static Inline From(Func activity, MemoryBlockReference? output = default) => new(activity, output);
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Activities/Container.cs b/src/modules/Elsa.Workflows.Core/Activities/Container.cs
index 1ea8de193..21f9cc90a 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Container.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Container.cs
@@ -1,6 +1,5 @@
using System.Collections.ObjectModel;
using Elsa.Workflows.Core.Attributes;
-using Elsa.Workflows.Core.Behaviors;
using Elsa.Workflows.Core.Models;
using Elsa.Workflows.Core.Services;
@@ -11,23 +10,22 @@ namespace Elsa.Workflows.Core.Activities;
///
public abstract class Container : ActivityBase, IContainer
{
- protected Container()
+ ///
+ protected Container(string? source = default, int? line = default) : base(source, line)
{
}
-
- protected Container(params IActivity[] activities)
- {
- Activities = activities;
- }
-
- protected Container(ICollection variables, params IActivity[] activities) : this(activities)
- {
- Variables = variables;
- }
+ ///
+ /// The s to execute.
+ ///
[Port] public ICollection Activities { get; set; } = new HashSet();
+
+ ///
+ /// The variables available to this scope.
+ ///
public ICollection Variables { get; set; } = new Collection();
+ ///
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
// Register variables.
@@ -37,12 +35,18 @@ public abstract class Container : ActivityBase, IContainer
await ScheduleChildrenAsync(context);
}
+ ///
+ /// Schedule the for execution.
+ ///
protected virtual ValueTask ScheduleChildrenAsync(ActivityExecutionContext context)
{
ScheduleChildren(context);
return ValueTask.CompletedTask;
}
+ ///
+ /// Schedule the for execution.
+ ///
protected virtual void ScheduleChildren(ActivityExecutionContext context)
{
}
diff --git a/src/modules/Elsa.Workflows.Core/Activities/Event.cs b/src/modules/Elsa.Workflows.Core/Activities/Event.cs
index 3d2e5a1f6..f9dfe1abb 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Event.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Event.cs
@@ -1,3 +1,4 @@
+using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using Elsa.Expressions.Models;
using Elsa.Workflows.Core.Attributes;
@@ -13,36 +14,41 @@ public class Event : Trigger