diff --git a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
index 1c6db7127..6c9f047ec 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs
@@ -1,7 +1,9 @@
+using System.ComponentModel;
using Elsa.Expressions.Models;
using Elsa.Workflows.Core.Attributes;
using Elsa.Workflows.Core.Models;
using Elsa.Workflows.Core.Services;
+using Elsa.Workflows.Core.Signals;
namespace Elsa.Workflows.Core.Activities;
@@ -15,6 +17,7 @@ public class Composite : ActivityBase
/// The activity to schedule when this activity executes.
///
[Port]
+ [Browsable(false)]
public IActivity Root { get; set; } = new Sequence();
///
@@ -62,10 +65,16 @@ public class Composite : ActivityBase
///
public class Composite : ActivityBase
{
+ public Composite()
+ {
+ OnSignalReceived(OnCompleteCompositeSignal);
+ }
+
///
/// The activity to schedule when this activity executes.
///
[Port]
+ [Browsable(false)]
public IActivity Root { get; protected set; } = new Sequence();
protected override void Execute(ActivityExecutionContext context)
@@ -105,4 +114,10 @@ public class Composite : ActivityBase
protected static Inline From(Func> activity, MemoryBlockReference? output = default) => new(activity, output);
protected static Inline From(Func activity, MemoryBlockReference? output = default) => new(activity, output);
protected static Inline From(Func activity, MemoryBlockReference? output = default) => new(activity, output);
+
+ private async ValueTask OnCompleteCompositeSignal(CompleteCompositeSignal signal, SignalContext context)
+ {
+ await context.ReceiverActivityExecutionContext.CompleteActivityAsync(signal.Result);
+ context.StopPropagation();
+ }
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Signals/CompleteCompositeSignal.cs b/src/modules/Elsa.Workflows.Core/Signals/CompleteCompositeSignal.cs
new file mode 100644
index 000000000..6bc0f6835
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Core/Signals/CompleteCompositeSignal.cs
@@ -0,0 +1,6 @@
+namespace Elsa.Workflows.Core.Signals;
+
+///
+/// Sent by child activities to notify their composite root that it should complete.
+///
+public record CompleteCompositeSignal(object? Result = default);
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Management/Implementations/ActivityDescriber.cs b/src/modules/Elsa.Workflows.Management/Implementations/ActivityDescriber.cs
index a3773dd9a..cc0945f89 100644
--- a/src/modules/Elsa.Workflows.Management/Implementations/ActivityDescriber.cs
+++ b/src/modules/Elsa.Workflows.Management/Implementations/ActivityDescriber.cs
@@ -46,7 +46,8 @@ public class ActivityDescriber : IActivityDescriber
from prop in activityType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where typeof(IActivity).IsAssignableFrom(prop.PropertyType) || typeof(IEnumerable).IsAssignableFrom(prop.PropertyType)
let portAttr = prop.GetCustomAttribute()
- where portAttr != null
+ let portBrowsableAttr = prop.GetCustomAttribute()
+ where portAttr != null && (portBrowsableAttr == null || portBrowsableAttr.Browsable)
select new Port
{
Name = portAttr.Name ?? prop.Name,
@@ -62,25 +63,6 @@ public class ActivityDescriber : IActivityDescriber
DisplayName = x
}).ToDictionary(x => x.Name) ?? new Dictionary();
- if (flowNodeAttr != null)
- {
- var portProperties = activityType.GetProperties().Where(p => typeof(IActivity).IsAssignableFrom(p.PropertyType) && p.GetCustomAttribute() != null).ToList();
-
- foreach (var portProperty in portProperties)
- {
- var portAttr = portProperty.GetCustomAttribute();
-
- var port = new Port
- {
- Mode = PortMode.Port,
- Name = portAttr?.Name ?? portProperty.Name,
- DisplayName = portAttr?.DisplayName ?? portProperty.Name
- };
-
- flowPorts[port.Name] = port;
- }
- }
-
var allPorts = embeddedPorts.Concat(flowPorts.Values);
var properties = activityType.GetProperties();
var inputProperties = properties.Where(x => typeof(Input).IsAssignableFrom(x.PropertyType) || x.GetCustomAttribute() != null).ToList();
diff --git a/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/GetAge.cs b/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/GetAge.cs
new file mode 100644
index 000000000..734f40785
--- /dev/null
+++ b/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/GetAge.cs
@@ -0,0 +1,22 @@
+using Elsa.Workflows.Core;
+using Elsa.Workflows.Core.Activities;
+using Elsa.Workflows.Core.Activities.Flowchart.Attributes;
+using Elsa.Workflows.Core.Activities.Flowchart.Models;
+using Elsa.Workflows.Core.Signals;
+
+namespace Elsa.Samples.TelnyxIntegration;
+
+[FlowNode("Over 18", "Under 18")]
+public class GetAge : Composite
+{
+ public GetAge()
+ {
+ Root = new Inline(async context =>
+ {
+ var random = new Random();
+ var n = random.Next(2);
+ var outcome = n == 0 ? "Under 18" : "Over 18";
+ await context.SendSignalAsync(new CompleteCompositeSignal(new Outcomes(outcome)));
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/Program.cs b/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/Program.cs
index bfc6b7344..6c9ed1342 100644
--- a/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/Program.cs
+++ b/src/samples/aspnet/Elsa.Samples.TelnyxIntegration/Program.cs
@@ -58,6 +58,7 @@ services
.AddActivity()
.AddActivity()
.AddActivity()
+ .AddActivitiesFrom()
)
.Use(identity =>
{