diff --git a/src/clients/Elsa.Api.Client/Extensions/DictionaryExtensions.cs b/src/clients/Elsa.Api.Client/Extensions/DictionaryExtensions.cs index e7a3b8f74..9fea97360 100644 --- a/src/clients/Elsa.Api.Client/Extensions/DictionaryExtensions.cs +++ b/src/clients/Elsa.Api.Client/Extensions/DictionaryExtensions.cs @@ -12,7 +12,9 @@ public static class DictionaryExtensions /// public static T? TryGetValue(this IDictionary dictionary, string key, Func? defaultValue = default, JsonSerializerOptions? serializerOptions = default) { - if (dictionary.TryGetValue(key, out var value) && value is not JsonElement { ValueKind: JsonValueKind.Undefined }) + var caseInsensitiveDictionary = new Dictionary(dictionary, StringComparer.OrdinalIgnoreCase); + + if (caseInsensitiveDictionary.TryGetValue(key, out var value) && value is not JsonElement { ValueKind: JsonValueKind.Undefined }) { var convertedValue = value.ConvertTo(new ObjectConverterOptions(serializerOptions)); @@ -33,7 +35,9 @@ public static class DictionaryExtensions /// public static object? TryGetValue(this IDictionary dictionary, string key, Func? defaultValue = default) { - if (dictionary.TryGetValue(key, out var value) && value is not JsonElement { ValueKind: JsonValueKind.Undefined }) + var caseInsensitiveDictionary = new Dictionary(dictionary, StringComparer.OrdinalIgnoreCase); + + if (caseInsensitiveDictionary.TryGetValue(key, out var value) && value is not JsonElement { ValueKind: JsonValueKind.Undefined }) return value; if (defaultValue == null) diff --git a/src/designer/designer_packages/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx b/src/designer/designer_packages/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx index b39f51ae5..91c9531ee 100644 --- a/src/designer/designer_packages/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx +++ b/src/designer/designer_packages/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx @@ -53,7 +53,7 @@ export class DefaultActivityTemplate { const activity: Activity = nodeMap[activityId]; const ports = portProvider.getOutboundPorts({activityDescriptor, activity}); const embeddedPorts = ports.filter(x => x.type == PortType.Embedded && x.isBrowsable !== false); - const canStartWorkflow = activity?.customProperties?.CanStartWorkflow ?? activity?.canStartWorkflow ?? false; + const canStartWorkflow: boolean = activity?.customProperties?.canStartWorkflow ?? activity?.customProperties?.CanStartWorkflow ?? activity?.canStartWorkflow ?? false; const icon = this.icon; const hasIcon = !!icon; const textColor = canStartWorkflow ? 'tw-text-white' : 'tw-text-gray-700'; diff --git a/src/designer/designer_packages/elsa-workflows-designer/src/modules/workflow-definitions/components/activity-properties/activity-properties-editor.tsx b/src/designer/designer_packages/elsa-workflows-designer/src/modules/workflow-definitions/components/activity-properties/activity-properties-editor.tsx index fb8872ca2..0546169a2 100644 --- a/src/designer/designer_packages/elsa-workflows-designer/src/modules/workflow-definitions/components/activity-properties/activity-properties-editor.tsx +++ b/src/designer/designer_packages/elsa-workflows-designer/src/modules/workflow-definitions/components/activity-properties/activity-properties-editor.tsx @@ -218,7 +218,7 @@ export class ActivityPropertiesEditor { const activity: Activity = this.activity; const inputElement = e.target as HTMLInputElement; - activity.customProperties.CanStartWorkflow = inputElement.checked; + activity.customProperties.canStartWorkflow = inputElement.checked; this.updateActivity(); } @@ -299,7 +299,7 @@ export class ActivityPropertiesEditor { const {activity} = this.renderContext; const activityId = activity.id; const displayText: string = activity.metadata?.displayText ?? ''; - const canStartWorkflow: boolean = activity.customProperties?.CanStartWorkflow ?? activity.canStartWorkflow ?? false; + const canStartWorkflow: boolean = activity.customProperties?.canStartWorkflow ?? activity?.customProperties?.CanStartWorkflow ?? activity.canStartWorkflow ?? false; const key = `${activityId}`; return
diff --git a/src/modules/Elsa.Workflows.Core/Extensions/ActivityPropertyExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/ActivityPropertyExtensions.cs index bb10d2536..c085429bd 100644 --- a/src/modules/Elsa.Workflows.Core/Extensions/ActivityPropertyExtensions.cs +++ b/src/modules/Elsa.Workflows.Core/Extensions/ActivityPropertyExtensions.cs @@ -8,9 +8,9 @@ namespace Elsa.Extensions; /// public static class ActivityPropertyExtensions { - private const string CanStartWorkflowPropertyName = "CanStartWorkflow"; - private const string RunAsynchronouslyPropertyName = "RunAsynchronously"; - private const string SourcePropertyName = "Source"; + private static readonly string[] CanStartWorkflowPropertyName = {"canStartWorkflow", "CanStartWorkflow", }; + private static readonly string[] RunAsynchronouslyPropertyName = {"runAsynchronously", "RunAsynchronously" }; + private static readonly string[] SourcePropertyName = {"source", "Source"}; /// /// Gets a flag indicating whether this activity can be used for starting a workflow. @@ -21,7 +21,7 @@ public static class ActivityPropertyExtensions /// /// Sets a flag indicating whether this activity can be used for starting a workflow. /// - public static void SetCanStartWorkflow(this IActivity activity, bool value) => activity.CustomProperties[CanStartWorkflowPropertyName] = value; + public static void SetCanStartWorkflow(this IActivity activity, bool value) => activity.CustomProperties[CanStartWorkflowPropertyName[0]] = value; /// /// Gets a flag indicating if this activity should execute synchronously or asynchronously. @@ -35,7 +35,7 @@ public static class ActivityPropertyExtensions /// By default, activities with an of , or /// will execute synchronously, while activities of the kind will execute asynchronously. /// - public static void SetRunAsynchronously(this IActivity activity, bool value) => activity.CustomProperties[RunAsynchronouslyPropertyName] = value; + public static void SetRunAsynchronously(this IActivity activity, bool value) => activity.CustomProperties[RunAsynchronouslyPropertyName[0]] = value; /// /// Gets the source file and line number where this activity was instantiated, if any. @@ -45,7 +45,7 @@ public static class ActivityPropertyExtensions /// /// Sets the source file and line number where this activity was instantiated, if any. /// - public static void SetSource(this IActivity activity, string value) => activity.CustomProperties[SourcePropertyName] = value; + public static void SetSource(this IActivity activity, string value) => activity.CustomProperties[SourcePropertyName[0]] = value; /// /// Sets the source file and line number where this activity was instantiated, if any. diff --git a/src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs index 55f1cac5b..3698b239c 100644 --- a/src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs +++ b/src/modules/Elsa.Workflows.Core/Extensions/DictionaryExtensions.cs @@ -6,6 +6,7 @@ namespace Elsa.Extensions; public static class DictionaryExtensions { public static bool TryGetValue(this IDictionary dictionary, string key, out T value) => dictionary.TryGetValue(key, out value); + public static bool TryGetValue(this IDictionary dictionary, IEnumerable keys, out T value) => dictionary.TryGetValue(keys, out value); public static bool TryGetValue(this IDictionary dictionary, string key, out T value) => dictionary.TryGetValue(key, out value); public static bool TryGetValue(this IDictionary dictionary, TKey key, out T value) @@ -19,6 +20,21 @@ public static class DictionaryExtensions value = ConvertValue(item); return true; } + + public static bool TryGetValue(this IDictionary dictionary, IEnumerable keys, out T value) + { + foreach (var key in keys) + { + if (dictionary.TryGetValue(key, out var item)) + { + value = ConvertValue(item); + return true; + } + } + + value = default!; + return false; + } public static T? GetValue(this IDictionary dictionary, TKey key) => ConvertValue(dictionary[key]); public static T? GetValue(this IDictionary dictionary, string key) => ConvertValue(dictionary[key]); @@ -26,6 +42,7 @@ public static class DictionaryExtensions public static T? GetValueOrDefault(this IDictionary dictionary, TKey key, Func defaultValueFactory) => TryGetValue(dictionary, key, out var value) ? value : defaultValueFactory(); public static T? GetValueOrDefault(this IDictionary dictionary, TKey key) => GetValueOrDefault(dictionary, key, () => default); public static T? GetValueOrDefault(this IDictionary dictionary, string key, Func defaultValueFactory) => TryGetValue(dictionary, key, out var value) ? value : defaultValueFactory(); + public static T? GetValueOrDefault(this IDictionary dictionary, IEnumerable keys, Func defaultValueFactory) => TryGetValue(dictionary, keys, out var value) ? value : defaultValueFactory(); public static T? GetValueOrDefault(this IDictionary dictionary, string key) => GetValueOrDefault(dictionary, key, () => default); public static object? GetValueOrDefault(this IDictionary dictionary, string key) => GetValueOrDefault(dictionary, key, () => default); diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs index 0b5bd9201..02c19bba4 100644 --- a/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs +++ b/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs @@ -16,21 +16,29 @@ public class ActivityFactory : IActivityFactory var canStartWorkflow = GetBoolean(context.Element, "canStartWorkflow"); var runAsynchronously = GetBoolean(context.Element, "runAsynchronously"); var activity = (IActivity)context.Element.Deserialize(type, context.SerializerOptions)!; - + activity.SetCanStartWorkflow(canStartWorkflow); activity.SetRunAsynchronously(runAsynchronously); - + return activity; } - + private static bool GetBoolean(JsonElement element, string propertyName) { - if (element.TryGetProperty("customProperties", out var customPropertyElement)) + var propertyNames = new[] { propertyName.Camelize(), propertyName.Pascalize() }; + + foreach (var name in propertyNames) { - if(customPropertyElement.TryGetProperty(propertyName.Pascalize(), out var canStartWorkflowElement)) - return canStartWorkflowElement.GetBoolean(); + if (element.TryGetProperty("customProperties", out var customPropertyElement)) + { + if (customPropertyElement.TryGetProperty(name, out var canStartWorkflowElement)) + return canStartWorkflowElement.GetBoolean(); + } + + if (element.TryGetProperty(propertyName.Camelize(), out var property) && property.GetBoolean()) + return true; } - - return element.TryGetProperty(propertyName.Camelize(), out var property) && property.GetBoolean(); + + return false; } } \ No newline at end of file