From fac292a9e3249cf4211d42c982fc73b120456ad0 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Thu, 28 Dec 2023 19:41:55 +0100 Subject: [PATCH] Add UI hints to input fields in workflow core modules Changed a number of instances in both activities and UI Hints classes across multiple modules in the workflow core to utilize UIHints. The UI hint "DropDown" has been added to relevant input fields to improve the user interface. Special handling for Enum properties in the drop-down options provider has also been created. --- .../Elsa.Http/Activities/WriteHttpResponse.cs | 6 +++++- .../Flowchart/Activities/FlowDecision.cs | 3 ++- .../Flowchart/Activities/FlowSwitch.cs | 16 +++++++++++---- .../Elsa.Workflows.Core/Activities/Fork.cs | 6 +++++- .../Elsa.Workflows.Core/Activities/If.cs | 3 ++- .../Elsa.Workflows.Core/Activities/Switch.cs | 6 +++++- .../Dropdown/StaticDropDownOptionsProvider.cs | 20 +++++++++++++++++++ 7 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/modules/Elsa.Http/Activities/WriteHttpResponse.cs b/src/modules/Elsa.Http/Activities/WriteHttpResponse.cs index b2985bc23..154e07d74 100644 --- a/src/modules/Elsa.Http/Activities/WriteHttpResponse.cs +++ b/src/modules/Elsa.Http/Activities/WriteHttpResponse.cs @@ -27,7 +27,11 @@ public class WriteHttpResponse : Activity /// /// The status code to return. /// - [Input(DefaultValue = HttpStatusCode.OK, Description = "The status code to return.")] + [Input( + DefaultValue = HttpStatusCode.OK, + Description = "The status code to return.", + UIHint = InputUIHints.DropDown + )] public Input StatusCode { get; set; } = new(HttpStatusCode.OK); /// diff --git a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowDecision.cs b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowDecision.cs index cb3ee5392..b4b1a2fc8 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowDecision.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowDecision.cs @@ -4,6 +4,7 @@ using Elsa.Extensions; using Elsa.Workflows.Activities.Flowchart.Attributes; using Elsa.Workflows.Attributes; using Elsa.Workflows.Models; +using Elsa.Workflows.UIHints; using JetBrains.Annotations; namespace Elsa.Workflows.Activities.Flowchart.Activities; @@ -36,7 +37,7 @@ public class FlowDecision : Activity /// /// The condition to evaluate. /// - [Input(UIHint = "single-line")] + [Input(UIHint = InputUIHints.SingleLine)] public Input Condition { get; set; } = new(new Literal(false)); /// diff --git a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowSwitch.cs b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowSwitch.cs index 31f24b197..30b547c38 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowSwitch.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowSwitch.cs @@ -6,6 +6,7 @@ using Elsa.Workflows.Activities.Flowchart.Attributes; using Elsa.Workflows.Activities.Flowchart.Models; using Elsa.Workflows.Attributes; using Elsa.Workflows.Models; +using Elsa.Workflows.UIHints; using JetBrains.Annotations; namespace Elsa.Workflows.Activities.Flowchart.Activities; @@ -23,12 +24,19 @@ public class FlowSwitch : Activity { } - [Input(UIHint = "flow-switch-editor")] public ICollection Cases { get; set; } = new List(); + /// + /// The possible cases to evaluate. + /// + [Input(UIHint = "flow-switch-editor")] + public ICollection Cases { get; set; } = new List(); /// /// The switch mode determines whether the first match should be scheduled, or all matches. /// - [Input(Description = "The switch mode determines whether the first match should be scheduled, or all matches.")] + [Input( + Description = "The switch mode determines whether the first match should be scheduled, or all matches.", + UIHint = InputUIHints.DropDown + )] public Input Mode { get; set; } = new(SwitchMode.MatchFirst); /// @@ -37,8 +45,8 @@ public class FlowSwitch : Activity var matchingCases = (await FindMatchingCasesAsync(context.ExpressionExecutionContext)).ToList(); var hasAnyMatches = matchingCases.Any(); var mode = context.Get(Mode); - var results = mode == SwitchMode.MatchFirst ? hasAnyMatches ? new[] { matchingCases.First() } : Array.Empty() : matchingCases.ToArray(); - var outcomes = hasAnyMatches ? results.Select(r => r.Label).ToArray() : new[] { "Default" }; + var results = mode == SwitchMode.MatchFirst ? hasAnyMatches ? [matchingCases.First()] : Array.Empty() : matchingCases.ToArray(); + var outcomes = hasAnyMatches ? results.Select(r => r.Label).ToArray() : ["Default"]; await context.CompleteActivityAsync(new Outcomes(outcomes)); } diff --git a/src/modules/Elsa.Workflows.Core/Activities/Fork.cs b/src/modules/Elsa.Workflows.Core/Activities/Fork.cs index d497d84c5..5204e906c 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/Fork.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/Fork.cs @@ -5,6 +5,7 @@ using Elsa.Extensions; using Elsa.Workflows.Attributes; using Elsa.Workflows.Contracts; using Elsa.Workflows.Signals; +using Elsa.Workflows.UIHints; using JetBrains.Annotations; namespace Elsa.Workflows.Activities; @@ -27,7 +28,10 @@ public class Fork : Activity /// /// Controls when this activity yields control back to its parent activity. /// - [Input(Description = "Controls when this activity yields control back to its parent activity.")] + [Input( + Description = "Controls when this activity yields control back to its parent activity.", + UIHint = InputUIHints.DropDown + )] public ForkJoinMode JoinMode { get; set; } = ForkJoinMode.WaitAll; /// diff --git a/src/modules/Elsa.Workflows.Core/Activities/If.cs b/src/modules/Elsa.Workflows.Core/Activities/If.cs index 65b537a43..191fbabf0 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/If.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/If.cs @@ -4,6 +4,7 @@ using Elsa.Extensions; using Elsa.Workflows.Attributes; using Elsa.Workflows.Contracts; using Elsa.Workflows.Models; +using Elsa.Workflows.UIHints; using JetBrains.Annotations; namespace Elsa.Workflows.Activities; @@ -41,7 +42,7 @@ public class If : Activity /// /// The condition to evaluate. /// - [Input(UIHint = "single-line")] + [Input(UIHint = InputUIHints.SingleLine)] public Input Condition { get; set; } = new(new Literal(false)); /// diff --git a/src/modules/Elsa.Workflows.Core/Activities/Switch.cs b/src/modules/Elsa.Workflows.Core/Activities/Switch.cs index 0fd2edcc9..4fec0f2d9 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/Switch.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/Switch.cs @@ -6,6 +6,7 @@ using Elsa.Extensions; using Elsa.Workflows.Attributes; using Elsa.Workflows.Contracts; using Elsa.Workflows.Models; +using Elsa.Workflows.UIHints; using JetBrains.Annotations; namespace Elsa.Workflows.Activities; @@ -40,7 +41,10 @@ public class Switch : Activity /// /// The switch mode determines whether the first match should be scheduled, or all matches. /// - [Input(Description = "The switch mode determines whether the first match should be scheduled, or all matches.")] + [Input( + Description = "The switch mode determines whether the first match should be scheduled, or all matches.", + UIHint = InputUIHints.DropDown + )] public Input Mode { get; set; } = new(SwitchMode.MatchFirst); /// diff --git a/src/modules/Elsa.Workflows.Core/UIHints/Dropdown/StaticDropDownOptionsProvider.cs b/src/modules/Elsa.Workflows.Core/UIHints/Dropdown/StaticDropDownOptionsProvider.cs index 67a2910a0..3aada9e72 100644 --- a/src/modules/Elsa.Workflows.Core/UIHints/Dropdown/StaticDropDownOptionsProvider.cs +++ b/src/modules/Elsa.Workflows.Core/UIHints/Dropdown/StaticDropDownOptionsProvider.cs @@ -1,6 +1,7 @@ using System.Reflection; using Elsa.Workflows.Attributes; using Elsa.Workflows.Contracts; +using Elsa.Workflows.Models; namespace Elsa.Workflows.UIHints.Dropdown; @@ -17,8 +18,27 @@ public class StaticDropDownOptionsProvider : IPropertyUIHandler var dictionary = new Dictionary(); if (inputOptions == null) + { + // Is the property an enum? + var wrappedPropertyType = propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Input<>) + ? propertyInfo.PropertyType.GetGenericArguments()[0] + : propertyInfo.PropertyType; + + if (!wrappedPropertyType.IsEnum) + return new(dictionary); + + var enumValues = Enum.GetValues(wrappedPropertyType).Cast().ToList(); + var enumSelectListItems = enumValues.Select(x => new SelectListItem(x.ToString()!, x.ToString()!)).ToList(); + var enumProps = new DropDownProps + { + SelectList = new SelectList(enumSelectListItems) + }; + + dictionary[InputUIHints.DropDown] = enumProps; return new(dictionary); + } + var selectListItems = (inputOptions as ICollection)?.Select(x => new SelectListItem(x, x)).ToList(); if (selectListItems == null)