Implement activity picker filtering

This commit is contained in:
Sipke Schoorstra 2020-11-14 21:58:48 +01:00
parent f652f1717a
commit 6bddf50d77
44 changed files with 175 additions and 102 deletions

View file

@ -9,6 +9,7 @@ indent_size=4
# ReSharper properties # ReSharper properties
resharper_csharp_max_line_length=240 resharper_csharp_max_line_length=240
resharper_keep_user_linebreaks=true resharper_keep_user_linebreaks=true
resharper_space_within_single_line_array_initializer_braces=true
# Microsoft .NET properties # Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers=false csharp_new_line_before_members_in_object_initializers=false

View file

@ -12,10 +12,9 @@ namespace Elsa.Activities.Console
/// <summary> /// <summary>
/// Reads input from the console. /// Reads input from the console.
/// </summary> /// </summary>
[ActivityDefinition( [Action(
Category = "Console", Category = "Console",
Description = "Read text from standard in.", Description = "Read text from standard in.",
Icon = "fas fa-terminal",
Outcomes = new[] { OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Done }
)] )]
public class ReadLine : Activity public class ReadLine : Activity
@ -44,7 +43,7 @@ namespace Elsa.Activities.Console
protected override IActivityExecutionResult OnResume(ActivityExecutionContext context) protected override IActivityExecutionResult OnResume(ActivityExecutionContext context)
{ {
var receivedInput = (string)context.Input!; var receivedInput = (string) context.Input!;
return Execute(receivedInput); return Execute(receivedInput);
} }

View file

@ -12,10 +12,9 @@ namespace Elsa.Activities.Console
/// <summary> /// <summary>
/// Writes a text string to the console. /// Writes a text string to the console.
/// </summary> /// </summary>
[ActivityDefinition( [Action(
Category = "Console", Category = "Console",
Description = "Write text to standard out.", Description = "Write text to standard out.",
Icon = "fas fa-terminal",
Outcomes = new[] { OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Done }
)] )]
public class WriteLine : Activity public class WriteLine : Activity

View file

@ -9,10 +9,11 @@ using Elsa.Services.Models;
namespace Elsa.Activities.Dropbox.Activities namespace Elsa.Activities.Dropbox.Activities
{ {
[ActivityDefinition( [Action(
Category = "Dropbox", Category = "Dropbox",
Description = "Saves a given file or byte array to a folder in Dropbox", Description = "Saves a given file or byte array to a folder in Dropbox",
Icon = "fab fa-dropbox")] Outcomes = new[] { OutcomeNames.Done }
)]
public class SaveToDropbox : Activity public class SaveToDropbox : Activity
{ {
private readonly IFilesApi _filesApi; private readonly IFilesApi _filesApi;

View file

@ -11,7 +11,7 @@ using MimeKit.Text;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.Email namespace Elsa.Activities.Email
{ {
[ActivityDefinition(Category = "Email", Description = "Send an email message.")] [Action(Category = "Email", Description = "Send an email message.")]
public class SendEmail : Activity public class SendEmail : Activity
{ {
private readonly ISmtpService _smtpService; private readonly ISmtpService _smtpService;

View file

@ -15,11 +15,10 @@ using Microsoft.AspNetCore.Http;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.Http namespace Elsa.Activities.Http
{ {
[ActivityDefinition( [Trigger(
Category = "HTTP", Category = "HTTP",
DisplayName = "Receive HTTP Request", DisplayName = "Receive HTTP Request",
Description = "Receive an incoming HTTP request.", Description = "Receive an incoming HTTP request.",
RuntimeDescription = "x => !!x.state.path ? `Handle <strong>${ x.state.method } ${ x.state.path }</strong>.` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Done }
)] )]
public class ReceiveHttpRequest : Activity public class ReceiveHttpRequest : Activity

View file

@ -10,7 +10,7 @@ using Microsoft.Extensions.Localization;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.Http namespace Elsa.Activities.Http
{ {
[ActivityDefinition( [Action(
Category = "HTTP", Category = "HTTP",
DisplayName = "Redirect", DisplayName = "Redirect",
Description = "Write an HTTP redirect response.", Description = "Write an HTTP redirect response.",

View file

@ -19,15 +19,11 @@ using HttpRequestHeaders = Elsa.Activities.Http.Models.HttpRequestHeaders;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.Http namespace Elsa.Activities.Http
{ {
[ActivityDefinition( [Action(
Category = "HTTP", Category = "HTTP",
DisplayName = "Send HTTP Request", DisplayName = "Send HTTP Request",
Description = "Send an HTTP request.", Description = "Send an HTTP request.",
Outcomes = new[] Outcomes = new[] { OutcomeNames.Done }
{
OutcomeNames.Done,
"x => !!x.state.supportedStatusCodes ? ['UnSupportedStatusCode', ...x.state.supportedStatusCodes] : ['UnSupportedStatusCode']"
}
)] )]
public class SendHttpRequest : Activity public class SendHttpRequest : Activity
{ {

View file

@ -13,7 +13,7 @@ using Microsoft.Extensions.Localization;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.Http namespace Elsa.Activities.Http
{ {
[ActivityDefinition( [Action(
Category = "HTTP", Category = "HTTP",
DisplayName = "Write HTTP Response", DisplayName = "Write HTTP Response",
Description = "Write an HTTP response.", Description = "Write an HTTP response.",

View file

@ -10,7 +10,7 @@ using Microsoft.Extensions.Options;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.MassTransit namespace Elsa.Activities.MassTransit
{ {
[ActivityDefinition( [Action(
Category = "MassTransit", Category = "MassTransit",
DisplayName = "Cancel scheduled MassTransit Message", DisplayName = "Cancel scheduled MassTransit Message",
Description = "Cancel a scheduled message via MassTransit." Description = "Cancel a scheduled message via MassTransit."

View file

@ -8,7 +8,7 @@ using MassTransit;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.MassTransit namespace Elsa.Activities.MassTransit
{ {
[ActivityDefinition( [Action(
Category = "MassTransit", Category = "MassTransit",
DisplayName = "Publish MassTransit Message", DisplayName = "Publish MassTransit Message",
Description = "Publish an event via MassTransit." Description = "Publish an event via MassTransit."

View file

@ -7,7 +7,7 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.MassTransit namespace Elsa.Activities.MassTransit
{ {
[ActivityDefinition( [Trigger(
Category = "MassTransit", Category = "MassTransit",
DisplayName = "Receive MassTransit Message", DisplayName = "Receive MassTransit Message",
Description = "Receive a message via MassTransit." Description = "Receive a message via MassTransit."

View file

@ -13,7 +13,7 @@ using NodaTime;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.MassTransit namespace Elsa.Activities.MassTransit
{ {
[ActivityDefinition( [Action(
Category = "MassTransit", Category = "MassTransit",
DisplayName = "Schedule MassTransit Message", DisplayName = "Schedule MassTransit Message",
Description = "Schedule a message via MassTransit." Description = "Schedule a message via MassTransit."

View file

@ -9,7 +9,7 @@ using MassTransit;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.MassTransit namespace Elsa.Activities.MassTransit
{ {
[ActivityDefinition( [Action(
Category = "MassTransit", Category = "MassTransit",
DisplayName = "Send MassTransit Message", DisplayName = "Send MassTransit Message",
Description = "Send a message via MassTransit." Description = "Send a message via MassTransit."

View file

@ -6,18 +6,17 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.Timers namespace Elsa.Activities.Timers
{ {
[ActivityDefinition( [Trigger(
Category = "Timers", Category = "Timers",
Description = "Triggers periodically based on a specified CRON expression.", Description = "Triggers periodically based on a specified CRON expression.",
RuntimeDescription = "x => !!x.state.cronExpression ? `<strong>${ x.state.cronExpression.expression }</strong>.` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Done }
)] )]
public class CronEvent : Activity public class CronEvent : Activity
{ {
[ActivityProperty(Hint = "Specify a CRON expression. See https://crontab.guru/ for help.")] [ActivityProperty(Hint = "Specify a CRON expression. See https://crontab.guru/ for help.")]
public string CronExpression { get; set; } = "* * * * *"; public string CronExpression { get; set; } = "* * * * *";
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) => context.WorkflowExecutionContext.IsFirstPass ? (IActivityExecutionResult)Done() : Suspend(); protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) => context.WorkflowExecutionContext.IsFirstPass ? (IActivityExecutionResult) Done() : Suspend();
protected override IActivityExecutionResult OnResume() => Done(); protected override IActivityExecutionResult OnResume() => Done();
} }
} }

View file

@ -10,7 +10,7 @@ namespace Elsa.Activities.Timers
/// <summary> /// <summary>
/// Triggers at a specific instant in the future. /// Triggers at a specific instant in the future.
/// </summary> /// </summary>
[ActivityDefinition( [Trigger(
Category = "Timers", Category = "Timers",
Description = "Triggers at a specified moment in time." Description = "Triggers at a specified moment in time."
)] )]

View file

@ -7,7 +7,7 @@ using NodaTime;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.Timers namespace Elsa.Activities.Timers
{ {
[ActivityDefinition(Category = "Timers", Description = "Triggers at a specified interval.")] [Trigger(Category = "Timers", Description = "Triggers at a specified interval.")]
public class TimerEvent : Activity public class TimerEvent : Activity
{ {
[ActivityProperty(Hint = "An expression that evaluates to a Duration value.")] [ActivityProperty(Hint = "An expression that evaluates to a Duration value.")]

View file

@ -13,7 +13,7 @@ namespace Elsa.Activities.UserTask.Activities
/// <summary> /// <summary>
/// Stores a set of possible user actions and halts the workflow until one of the actions has been performed. /// Stores a set of possible user actions and halts the workflow until one of the actions has been performed.
/// </summary> /// </summary>
[ActivityDefinition( [Trigger(
Category = "User Tasks", Category = "User Tasks",
Description = "Triggers when a user action is received.", Description = "Triggers when a user action is received.",
Outcomes = new[] { OutcomeNames.Done, "x => x.state.actions" } Outcomes = new[] { OutcomeNames.Done, "x => x.state.actions" }

View file

@ -8,10 +8,9 @@ namespace Elsa.Client.Models
[DataMember(Order = 1)] public string Type { get; set; } = default!; [DataMember(Order = 1)] public string Type { get; set; } = default!;
[DataMember(Order = 2)] public string DisplayName { get; set; } = default!; [DataMember(Order = 2)] public string DisplayName { get; set; } = default!;
[DataMember(Order = 3)] public string? Description { get; set; } [DataMember(Order = 3)] public string? Description { get; set; }
[DataMember(Order = 4)] public string? RuntimeDescription { get; set; } [DataMember(Order = 4)] public string Category { get; set; } = default!;
[DataMember(Order = 5)] public string Category { get; set; } = default!; [DataMember(Order = 5)] public ActivityTraits Traits { get; set; }
[DataMember(Order = 6)] public string? Icon { get; set; } [DataMember(Order = 6)] public string[] Outcomes { get; set; } = new string[0];
[DataMember(Order = 7)] public string[] Outcomes { get; set; } = new string[0]; [DataMember(Order = 7)] public ActivityPropertyDescriptor[] Properties { get; set; } = new ActivityPropertyDescriptor[0];
[DataMember(Order = 8)] public ActivityPropertyDescriptor[] Properties { get; set; } = new ActivityPropertyDescriptor[0];
} }
} }

View file

@ -0,0 +1,12 @@
using System;
namespace Elsa.Client.Models
{
[Flags]
public enum ActivityTraits
{
Action = 1,
Trigger = 2,
Job = 4
}
}

View file

@ -0,0 +1,14 @@
using System;
using Elsa.Metadata;
namespace Elsa.Attributes
{
[AttributeUsage(AttributeTargets.Class)]
public sealed class ActionAttribute : ActivityAttribute
{
public ActionAttribute()
{
Traits = ActivityTraits.Action;
}
}
}

View file

@ -1,16 +1,16 @@
using System; using System;
using Elsa.Metadata;
namespace Elsa.Attributes namespace Elsa.Attributes
{ {
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
public class ActivityDefinitionAttribute : Attribute public class ActivityAttribute : Attribute
{ {
public string? Type { get; set; } public string? Type { get; set; }
public string? DisplayName { get; set; } public string? DisplayName { get; set; }
public string? Description { get; set; } public string? Description { get; set; }
public string? RuntimeDescription { get; set; }
public string? Category { get; set; } public string? Category { get; set; }
public string? Icon { get; set; } public ActivityTraits Traits { get; set; } = ActivityTraits.Action;
public string[]? Outcomes { get; set; } public string[]? Outcomes { get; set; }
} }
} }

View file

@ -0,0 +1,14 @@
using System;
using Elsa.Metadata;
namespace Elsa.Attributes
{
[AttributeUsage(AttributeTargets.Class)]
public sealed class TriggerAttribute : ActivityAttribute
{
public TriggerAttribute()
{
Traits = ActivityTraits.Trigger;
}
}
}

View file

@ -7,6 +7,7 @@ namespace Elsa.Metadata
Type = "Activity"; Type = "Activity";
Properties = new ActivityPropertyDescriptor[0]; Properties = new ActivityPropertyDescriptor[0];
Category = "Miscellaneous"; Category = "Miscellaneous";
Traits = ActivityTraits.Action;
DisplayName = "Activity"; DisplayName = "Activity";
Properties = new ActivityPropertyDescriptor[0]; Properties = new ActivityPropertyDescriptor[0];
Outcomes = new string[0]; Outcomes = new string[0];
@ -15,9 +16,8 @@ namespace Elsa.Metadata
public string Type { get; set; } public string Type { get; set; }
public string DisplayName { get; set; } public string DisplayName { get; set; }
public string? Description { get; set; } public string? Description { get; set; }
public string? RuntimeDescription { get; set; }
public string Category { get; set; } public string Category { get; set; }
public string? Icon { get; set; } public ActivityTraits Traits { get; set; }
public string[] Outcomes { get; set; } public string[] Outcomes { get; set; }
public ActivityPropertyDescriptor[] Properties { get; set; } public ActivityPropertyDescriptor[] Properties { get; set; }
} }

View file

@ -0,0 +1,12 @@
using System;
namespace Elsa.Metadata
{
[Flags]
public enum ActivityTraits
{
Action = 1,
Trigger = 2,
Job = 4
}
}

View file

@ -6,10 +6,9 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.ControlFlow namespace Elsa.Activities.ControlFlow
{ {
[ActivityDefinition( [Activity(
Category = "Workflows", Category = "Workflows",
Description = "Removes any blocking activities and sets the status of the workflow to Completed.", Description = "Removes any blocking activities and sets the status of the workflow to Completed."
Icon = "fas fa-flag-checkered"
)] )]
public class Finish : Activity public class Finish : Activity
{ {

View file

@ -7,10 +7,9 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.ControlFlow namespace Elsa.Activities.ControlFlow
{ {
[ActivityDefinition( [Activity(
Category = "Control Flow", Category = "Control Flow",
Description = "Iterate between two numbers.", Description = "Iterate between two numbers.",
Icon = "far fa-circle",
Outcomes = new[] { OutcomeNames.Iterate, OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Iterate, OutcomeNames.Done }
)] )]
public class For : Activity public class For : Activity

View file

@ -9,10 +9,9 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.ControlFlow namespace Elsa.Activities.ControlFlow
{ {
[ActivityDefinition( [Activity(
Category = "Control Flow", Category = "Control Flow",
Description = "Iterate over a collection.", Description = "Iterate over a collection.",
Icon = "far fa-circle",
Outcomes = new[] { OutcomeNames.Iterate, OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Iterate, OutcomeNames.Done }
)] )]
public class ForEach : Activity public class ForEach : Activity

View file

@ -6,10 +6,9 @@ using Elsa.Services;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.ControlFlow namespace Elsa.Activities.ControlFlow
{ {
[ActivityDefinition( [Activity(
Category = "Control Flow", Category = "Control Flow",
Description = "Fork workflow execution into multiple branches.", Description = "Fork workflow execution into multiple branches.",
Icon = "fas fa-code-branch fa-rotate-180",
Outcomes = new[] { "x => x.state.branches" })] Outcomes = new[] { "x => x.state.branches" })]
public class Fork : Activity public class Fork : Activity
{ {

View file

@ -6,11 +6,10 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.ControlFlow namespace Elsa.Activities.ControlFlow
{ {
[ActivityDefinition( [Activity(
DisplayName = "If/Else", DisplayName = "If/Else",
Category = "Control Flow", Category = "Control Flow",
Description = "Evaluate a Boolean expression and continue execution depending on the result.", Description = "Evaluate a Boolean expression and continue execution depending on the result.",
RuntimeDescription = "x => !!x.state.expression ? `Evaluate <strong>${ x.state.expression.expression }</strong> and continue execution depending on the result.` : x.definition.description",
Outcomes = new[] { True, False, OutcomeNames.Done } Outcomes = new[] { True, False, OutcomeNames.Done }
)] )]
public class IfElse : Activity public class IfElse : Activity

View file

@ -13,11 +13,9 @@ using MediatR;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.ControlFlow namespace Elsa.Activities.ControlFlow
{ {
[ActivityDefinition( [Activity(
Category = "Control Flow", Category = "Control Flow",
Description = "Merge workflow execution back into a single branch.", Description = "Merge workflow execution back into a single branch.",
Icon = "fas fa-code-branch",
RuntimeDescription = "x => !!x.state.joinMode ? `Merge workflow execution back into a single branch using mode <strong>${ x.state.joinMode }</strong>` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Done }
)] )]
public class Join : Activity, INotificationHandler<ActivityExecuted> public class Join : Activity, INotificationHandler<ActivityExecuted>

View file

@ -9,10 +9,9 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.ControlFlow namespace Elsa.Activities.ControlFlow
{ {
[ActivityDefinition( [Activity(
Category = "Control Flow", Category = "Control Flow",
Description = "Iterate over a collection in parallel.", Description = "Iterate over a collection in parallel.",
Icon = "far fa-circle",
Outcomes = new[] { OutcomeNames.Iterate, OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Iterate, OutcomeNames.Done }
)] )]
public class ParallelForEach : Activity public class ParallelForEach : Activity

View file

@ -8,12 +8,9 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.ControlFlow namespace Elsa.Activities.ControlFlow
{ {
[ActivityDefinition( [Activity(
Category = "Control Flow", Category = "Control Flow",
Description = "Switch execution based on a given expression.", Description = "Switch execution based on a given expression."
Icon = "far fa-list-alt",
RuntimeDescription = "x => !!x.state.expression ? `Switch execution based on <strong>${ x.state.expression.expression }</strong>.` : x.definition.description",
Outcomes = new[] { "x => x.state.cases.map(c => c.toString())" }
)] )]
public class Switch : Activity public class Switch : Activity
{ {

View file

@ -6,10 +6,9 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.ControlFlow namespace Elsa.Activities.ControlFlow
{ {
[ActivityDefinition( [Activity(
Category = "Control Flow", Category = "Control Flow",
Description = "Execute while a given condition is true.", Description = "Execute while a given condition is true.",
Icon = "far fa-circle",
Outcomes = new[] { OutcomeNames.Iterate, OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Iterate, OutcomeNames.Done }
)] )]
public class While : Activity public class While : Activity

View file

@ -8,10 +8,10 @@ namespace Elsa.Activities.Primitives
/// <summary> /// <summary>
/// Sets the CorrelationId of the workflow to a given value. /// Sets the CorrelationId of the workflow to a given value.
/// </summary> /// </summary>
[ActivityDefinition( [Activity(
Category = "Workflows", Category = "Workflows",
Description = "Set the CorrelationId of the workflow to a given value.", Description = "Set the CorrelationId of the workflow to a given value.",
Icon = "fas fa-link" Outcomes = new[] { OutcomeNames.Done }
)] )]
public class Correlate : Activity public class Correlate : Activity
{ {

View file

@ -6,11 +6,10 @@ using Elsa.Services.Models;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.Primitives namespace Elsa.Activities.Primitives
{ {
[ActivityDefinition( [Activity(
DisplayName = "Set Variable", DisplayName = "Set Variable",
Description = "Set variable on the workflow.", Description = "Set variable on the workflow.",
Category = "Primitives", Category = "Primitives",
RuntimeDescription = "x => !!x.state.variableName ? `<strong>${x.state.variableName}</strong> = <strong>${x.state.valueExpression.expression}</strong><br/>${x.state.valueExpression.syntax}` : x.definition.description",
Outcomes = new[] { OutcomeNames.Done } Outcomes = new[] { OutcomeNames.Done }
)] )]
public class SetVariable : Activity public class SetVariable : Activity

View file

@ -11,10 +11,10 @@ namespace Elsa.Activities.Signaling
/// <summary> /// <summary>
/// Suspends workflow execution until the specified signal is received. /// Suspends workflow execution until the specified signal is received.
/// </summary> /// </summary>
[ActivityDefinition( [Trigger(
Category = "Workflows", Category = "Workflows",
Description = "Halt workflow execution until the specified signal is received.", Description = "Suspend workflow execution until the specified signal is received.",
Icon = "fas fa-traffic-light" Outcomes = new[] { OutcomeNames.Done }
)] )]
public class ReceiveSignal : Activity public class ReceiveSignal : Activity
{ {
@ -25,7 +25,7 @@ namespace Elsa.Activities.Signaling
{ {
if (context.Input is Signal triggeredSignal) if (context.Input is Signal triggeredSignal)
return string.Equals(triggeredSignal.SignalName, Signal, StringComparison.OrdinalIgnoreCase); return string.Equals(triggeredSignal.SignalName, Signal, StringComparison.OrdinalIgnoreCase);
return false; return false;
} }

View file

@ -12,10 +12,10 @@ namespace Elsa.Activities.Signaling
/// <summary> /// <summary>
/// Triggers the specified signal. /// Triggers the specified signal.
/// </summary> /// </summary>
[ActivityDefinition( [Action(
Category = "Workflows", Category = "Workflows",
Description = "Sends the specified signal.", Description = "Sends the specified signal.",
Icon = "fas fa-broadcast-tower" Outcomes = new[] { OutcomeNames.Done }
)] )]
public class SendSignal : Activity public class SendSignal : Activity
{ {

View file

@ -11,7 +11,7 @@ using Open.Linq.AsyncExtensions;
// ReSharper disable once CheckNamespace // ReSharper disable once CheckNamespace
namespace Elsa.Activities.Workflows namespace Elsa.Activities.Workflows
{ {
[ActivityDefinition( [Activity(
Category = "Workflows", Category = "Workflows",
Description = "Runs a child workflow." Description = "Runs a child workflow."
)] )]

View file

@ -21,18 +21,17 @@ namespace Elsa.Metadata
public ActivityDescriptor Describe(Type activityType) public ActivityDescriptor Describe(Type activityType)
{ {
var activityDefinitionAttribute = activityType.GetCustomAttribute<ActivityDefinitionAttribute>(); var activityAttribute = activityType.GetCustomAttribute<ActivityAttribute>();
var typeName = activityDefinitionAttribute?.Type ?? activityType.Name; var typeName = activityAttribute?.Type ?? activityType.Name;
var displayName = var displayName =
activityDefinitionAttribute?.DisplayName ?? activityAttribute?.DisplayName ??
activityType.Name.Humanize(LetterCasing.Title); activityType.Name.Humanize(LetterCasing.Title);
var description = activityDefinitionAttribute?.Description; var description = activityAttribute?.Description;
var runtimeDescription = activityDefinitionAttribute?.RuntimeDescription; var category = activityAttribute?.Category ?? "Miscellaneous";
var category = activityDefinitionAttribute?.Category ?? "Miscellaneous"; var traits = activityAttribute?.Traits ?? ActivityTraits.Action;
var icon = activityDefinitionAttribute?.Icon; var outcomes = activityAttribute?.Outcomes ?? new[] { OutcomeNames.Done };
var outcomes = activityDefinitionAttribute?.Outcomes ?? new[] { OutcomeNames.Done };
var properties = DescribeProperties(activityType); var properties = DescribeProperties(activityType);
return new ActivityDescriptor return new ActivityDescriptor
@ -40,9 +39,8 @@ namespace Elsa.Metadata
Type = typeName.Pascalize(), Type = typeName.Pascalize(),
DisplayName = displayName, DisplayName = displayName,
Description = description, Description = description,
RuntimeDescription = runtimeDescription,
Category = category, Category = category,
Icon = icon, Traits = traits,
Properties = properties.ToArray(), Properties = properties.ToArray(),
Outcomes = outcomes Outcomes = outcomes
}; };

View file

@ -6,7 +6,7 @@ namespace ElsaDashboard.Application.Server
{ {
public class Program public class Program
{ {
public static bool UseBlazorServer = false; public static bool UseBlazorServer = true;
public static bool UseBlazorWebAssembly => !UseBlazorServer; public static bool UseBlazorWebAssembly => !UseBlazorServer;
public static RenderMode RenderMode => UseBlazorServer ? RenderMode.ServerPrerendered: RenderMode.WebAssemblyPrerendered; public static RenderMode RenderMode => UseBlazorServer ? RenderMode.ServerPrerendered: RenderMode.WebAssemblyPrerendered;

View file

@ -9,26 +9,20 @@
<line x1="21" y1="21" x2="15" y2="15"/> <line x1="21" y1="21" x2="15" y2="15"/>
</svg> </svg>
</div> </div>
<input class="form-input block w-full pl-10 sm:text-sm sm:leading-5"placeholder="Search activities"> <input type="text" @bind="ActivitySearchText" @bind:event="oninput" class="form-input block w-full pl-10 sm:text-sm sm:leading-5" placeholder="Search activities">
</div> </div>
</div> </div>
<div class="border-b border-gray-200"> <div class="border-b border-gray-200">
<div class="px-6"> <div class="px-6">
<nav class="-mb-px flex space-x-6" x-descriptions="Tab component"> <nav class="-mb-px flex space-x-6" x-descriptions="Tab component">
<a href="#" @foreach (var activityTypeFilter in ActivityTraitFilters)
class="whitespace-no-wrap pb-4 px-1 border-b-2 border-blue-500 font-medium text-sm leading-5 text-blue-600 focus:outline-none focus:text-blue-800 focus:border-blue-700" {
aria-current="page"> var activeClass = activityTypeFilter == SelectedActivityTraitFilter ? "border-blue-500 text-blue-600 focus:text-blue-800 focus:border-blue-700" : "border-transparent text-gray-500 focus:text-gray-700 focus:border-gray-300";
All <a href="#" @onclick:preventDefault @onclick="@(() => OnActivityTypeFilterClick(activityTypeFilter))" class="whitespace-no-wrap pb-4 px-1 border-b-2 font-medium text-sm leading-5 focus:outline-none @activeClass" aria-current="page">
</a> @activityTypeFilter.ToString()
<a href="#" </a>
class="whitespace-no-wrap pb-4 px-1 border-b-2 border-transparent font-medium text-sm leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300"> }
Actions
</a>
<a href="#"
class="whitespace-no-wrap pb-4 px-1 border-b-2 border-transparent font-medium text-sm leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300">
Triggers
</a>
</nav> </nav>
</div> </div>
</div> </div>

View file

@ -1,21 +1,61 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Elsa.Client.Models; using Elsa.Client.Models;
using ElsaDashboard.Shared.Rpc; using ElsaDashboard.Shared.Rpc;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
namespace ElsaDashboard.Application.Pages.Designer namespace ElsaDashboard.Application.Pages.Designer
{ {
partial class ActivityPicker partial class ActivityPicker
{ {
[Inject] private IActivityService ActivityService { get; set; } = default!; [Inject] private IActivityService ActivityService { get; set; } = default!;
private ICollection<IGrouping<string, ActivityDescriptor>> ActivityGroupings { get; set; } = new System.Collections.Generic.List<IGrouping<string, ActivityDescriptor>>(); private ActivityTraitFilter SelectedActivityTraitFilter { get; set; }
private string? ActivitySearchText { get; set; }
private ICollection<ActivityTraitFilter> ActivityTraitFilters => new[] { ActivityTraitFilter.All, ActivityTraitFilter.Actions, ActivityTraitFilter.Triggers };
private ICollection<ActivityDescriptor> Activities { get; set; } = new System.Collections.Generic.List<ActivityDescriptor>();
private ICollection<IGrouping<string, ActivityDescriptor>> ActivityGroupings =>
FilterBySearchText(
FilterByTrait(Activities, SelectedActivityTraitFilter),
ActivitySearchText)
.GroupBy(x => x.Category)
.ToList();
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
var response = (await ActivityService.GetActivitiesAsync()); var response = (await ActivityService.GetActivitiesAsync());
ActivityGroupings = response.Activities.GroupBy(x => x.Category).ToList(); Activities = response.Activities.ToList();
}
private void OnActivityTypeFilterClick(ActivityTraitFilter activityTraitFilter)
{
SelectedActivityTraitFilter = activityTraitFilter;
}
private static IEnumerable<ActivityDescriptor> FilterByTrait(IEnumerable<ActivityDescriptor> activities, ActivityTraitFilter filter) =>
filter switch
{
ActivityTraitFilter.Actions => activities.Where(x => (x.Traits & ActivityTraits.Action) == ActivityTraits.Action),
ActivityTraitFilter.Triggers => activities.Where(x => (x.Traits & ActivityTraits.Trigger) == ActivityTraits.Trigger),
ActivityTraitFilter.All => activities,
_ => activities
};
private static IEnumerable<ActivityDescriptor> FilterBySearchText(IEnumerable<ActivityDescriptor> activities, string? searchText)
{
if (string.IsNullOrWhiteSpace(searchText))
return activities;
return
from activity in activities
where
(activity.Description ?? "").Contains(searchText, StringComparison.InvariantCultureIgnoreCase) ||
(activity.DisplayName ?? "").Contains(searchText, StringComparison.InvariantCultureIgnoreCase) ||
activity.Type.Contains(searchText, StringComparison.InvariantCultureIgnoreCase)
select activity;
} }
} }
} }

View file

@ -0,0 +1,9 @@
namespace ElsaDashboard.Application.Pages.Designer
{
public enum ActivityTraitFilter
{
All,
Actions,
Triggers
}
}