diff --git a/src/clients/Elsa.Api.Client/Abstractions/ActivityTypeResolverBase.cs b/src/clients/Elsa.Api.Client/Abstractions/ActivityTypeResolverBase.cs deleted file mode 100644 index 6655df927..000000000 --- a/src/clients/Elsa.Api.Client/Abstractions/ActivityTypeResolverBase.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Elsa.Api.Client.Activities; -using Elsa.Api.Client.Contracts; - -namespace Elsa.Api.Client.Abstractions; - -/// -/// Provides a base class for implementations. -/// -public abstract class ActivityTypeResolverBase : IActivityTypeResolver -{ - /// - public virtual double Priority => 0; - - /// - /// Returns a value indicating whether this provider supports the specified activity type. - /// - /// The . - /// A value indicating whether this provider supports the specified activity type. - protected virtual bool GetSupportsType(ActivityTypeResolverContext context) => false; - - /// - /// Resolves the activity type. - /// - /// - /// - protected virtual Type ResolveType(ActivityTypeResolverContext context) => typeof(Activity); - - bool IActivityTypeResolver.GetSupportsType(ActivityTypeResolverContext context) => GetSupportsType(context); - Type IActivityTypeResolver.ResolveType(ActivityTypeResolverContext context) => ResolveType(context); -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Activities/Activity.cs b/src/clients/Elsa.Api.Client/Activities/Activity.cs deleted file mode 100644 index 8f04426eb..000000000 --- a/src/clients/Elsa.Api.Client/Activities/Activity.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Elsa.Api.Client.Extensions; - -namespace Elsa.Api.Client.Activities; - -/// -/// Represents an activity. -/// -public class Activity : Dictionary -{ - /// - /// Gets or sets the ID of this activity. - /// - public string Id - { - get => this.TryGetValue("id")!; - set => this["id"] = value; - } - - /// - /// Gets or sets the name of this activity. - /// - public string? Name - { - get => this.TryGetValue("name")!; - set => this["name"] = value!; - } - - /// - /// Gets or sets the type of this activity. - /// - public string Type - { - get => this.TryGetValue("type")!; - set => this["type"] = value; - } - - /// - /// Gets or sets the version of this activity. - /// - public int Version - { - get => this.TryGetValue("version"); - set => this["version"] = value; - } - - /// - /// Gets or sets the metadata of this activity. - /// - public IDictionary Metadata - { - get => this.TryGetValue>("metadata", () => new Dictionary())!; - set => this["metadata"] = value; - } - - /// - /// Gets or sets custom properties of this activity. - /// - public IDictionary CustomProperties - { - get => this.TryGetValue>("customProperties", () => new Dictionary())!; - set => this["customProperties"] = value; - } -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Activities/FlowSwitch.cs b/src/clients/Elsa.Api.Client/Activities/FlowSwitch.cs deleted file mode 100644 index f9d89c58a..000000000 --- a/src/clients/Elsa.Api.Client/Activities/FlowSwitch.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Elsa.Api.Client.Extensions; -using Elsa.Api.Client.Shared.Models; - -namespace Elsa.Api.Client.Activities; - -/// -/// Represents a flow switch activity. -/// -public class FlowSwitch : Activity -{ - /// - /// Gets or sets the cases. - /// - public ICollection? Cases - { - get => this.TryGetValue>("cases"); - set => this["cases"] = value!; - } -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Activities/Flowchart.cs b/src/clients/Elsa.Api.Client/Activities/Flowchart.cs deleted file mode 100644 index e474e09b4..000000000 --- a/src/clients/Elsa.Api.Client/Activities/Flowchart.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Elsa.Api.Client.Extensions; -using Elsa.Api.Client.Shared.Models; - -namespace Elsa.Api.Client.Activities; - -/// -/// Represents a flowchart activity. -/// -public class Flowchart : Container -{ - /// - /// Gets or sets the connections between activities. - /// - public ICollection Connections - { - get => this.TryGetValue>("connections", () => new List())!; - set => this["connections"] = value; - } -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Activities/Trigger.cs b/src/clients/Elsa.Api.Client/Activities/Trigger.cs deleted file mode 100644 index b1732ab01..000000000 --- a/src/clients/Elsa.Api.Client/Activities/Trigger.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Elsa.Api.Client.Activities; - -/// -/// Represents a trigger. -/// -public class Trigger : Activity -{ - -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/ActivityProviders/DefaultActivityTypeResolver.cs b/src/clients/Elsa.Api.Client/ActivityProviders/DefaultActivityTypeResolver.cs deleted file mode 100644 index 3f8f3c0cc..000000000 --- a/src/clients/Elsa.Api.Client/ActivityProviders/DefaultActivityTypeResolver.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Elsa.Api.Client.Abstractions; -using Elsa.Api.Client.Activities; -using Elsa.Api.Client.Contracts; - -namespace Elsa.Api.Client.ActivityProviders; - -/// -/// Provides a default implementation of that always resolves the type. -/// -public class DefaultActivityTypeResolver : ActivityTypeResolverBase -{ - /// - public override double Priority => -1; - - /// - protected override bool GetSupportsType(ActivityTypeResolverContext context) => true; - - /// - protected override Type ResolveType(ActivityTypeResolverContext context) => typeof(Activity); -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/ActivityProviders/FlowSwitchTypeResolver.cs b/src/clients/Elsa.Api.Client/ActivityProviders/FlowSwitchTypeResolver.cs deleted file mode 100644 index 862360662..000000000 --- a/src/clients/Elsa.Api.Client/ActivityProviders/FlowSwitchTypeResolver.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Elsa.Api.Client.Abstractions; -using Elsa.Api.Client.Activities; -using Elsa.Api.Client.Contracts; - -namespace Elsa.Api.Client.ActivityProviders; - -/// -/// Constructs a activity. -/// -public class FlowSwitchTypeResolver : ActivityTypeResolverBase -{ - /// - protected override bool GetSupportsType(ActivityTypeResolverContext context) => context.ActivityTypeName == "Elsa.FlowSwitch"; - - /// - protected override Type ResolveType(ActivityTypeResolverContext context) => typeof(FlowSwitch); -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/ActivityProviders/FlowchartTypeResolver.cs b/src/clients/Elsa.Api.Client/ActivityProviders/FlowchartTypeResolver.cs deleted file mode 100644 index 5fffbeba9..000000000 --- a/src/clients/Elsa.Api.Client/ActivityProviders/FlowchartTypeResolver.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Elsa.Api.Client.Abstractions; -using Elsa.Api.Client.Activities; -using Elsa.Api.Client.Contracts; - -namespace Elsa.Api.Client.ActivityProviders; - -/// -/// Constructs a activity. -/// -public class FlowchartTypeResolver : ActivityTypeResolverBase -{ - /// - protected override bool GetSupportsType(ActivityTypeResolverContext context) => context.ActivityTypeName == "Elsa.Flowchart"; - - /// - protected override Type ResolveType(ActivityTypeResolverContext context) => typeof(Flowchart); -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Contracts/IActivityTypeResolver.cs b/src/clients/Elsa.Api.Client/Contracts/IActivityTypeResolver.cs deleted file mode 100644 index a4d0f79ee..000000000 --- a/src/clients/Elsa.Api.Client/Contracts/IActivityTypeResolver.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Elsa.Api.Client.Activities; - -namespace Elsa.Api.Client.Contracts; - -/// -/// Resolves an activity type. -/// -public interface IActivityTypeResolver -{ - /// - /// Gets the priority of this activity provider. Activity providers with a higher priority are considered first. - /// - double Priority { get; } - - /// - /// Returns a value indicating whether this activity provider supports the specified activity type. - /// - /// The . - /// A value indicating whether this activity provider supports the specified activity type. - bool GetSupportsType(ActivityTypeResolverContext context); - - /// - /// Creates an instance of for the specified activity type. - /// - /// The . - /// The resolved type. - Type ResolveType(ActivityTypeResolverContext context); -} - -/// -/// Provides context for an . -/// -/// The activity type. -public record ActivityTypeResolverContext(string ActivityTypeName); \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Contracts/IActivityTypeService.cs b/src/clients/Elsa.Api.Client/Contracts/IActivityTypeService.cs deleted file mode 100644 index af58d3cd1..000000000 --- a/src/clients/Elsa.Api.Client/Contracts/IActivityTypeService.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Elsa.Api.Client.Contracts; - -/// -/// Resolves the .NET type of an activity type name. -/// -public interface IActivityTypeService -{ - /// - /// Resolves the .NET type of the specified activity type name. - /// - /// The activity type name. - /// Returns the .NET type of the specified activity type name. - Type ResolveType(string activityTypeName); -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Converters/ActivityJsonConverter.cs b/src/clients/Elsa.Api.Client/Converters/ActivityJsonConverter.cs deleted file mode 100644 index 6a1bd0ae0..000000000 --- a/src/clients/Elsa.Api.Client/Converters/ActivityJsonConverter.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; -using Elsa.Api.Client.Activities; -using Elsa.Api.Client.Contracts; - -namespace Elsa.Api.Client.Converters; - -/// -/// A JSON converter that serializes . -/// -public class ActivityJsonConverter : JsonConverter -{ - private readonly IActivityTypeService _activityTypeService; - - /// - public ActivityJsonConverter(IActivityTypeService activityTypeService) - { - _activityTypeService = activityTypeService; - } - - /// - public override Activity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (!JsonDocument.TryParseValue(ref reader, out var doc)) - throw new JsonException("Failed to parse JsonDocument"); - - var activityRoot = doc.RootElement; - var activityTypeName = activityRoot.GetProperty("type").GetString()!; - var activityType = _activityTypeService.ResolveType(activityTypeName); - var newOptions = new JsonSerializerOptions(); - var activity = (Activity)JsonSerializer.Deserialize(activityRoot.GetRawText(), activityType, newOptions)!; - - return activity; - } - - /// - public override void Write(Utf8JsonWriter writer, Activity value, JsonSerializerOptions options) - { - var newOptions = new JsonSerializerOptions(options) - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; - - writer.WriteStartObject(); - - foreach (var prop in value.Where(kvp => kvp.Value != null)) - { - writer.WritePropertyName(prop.Key); - JsonSerializer.Serialize(writer, prop.Value, prop.Value.GetType(), newOptions); - } - - writer.WriteEndObject(); - } -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Converters/ActivityJsonConverterFactory.cs b/src/clients/Elsa.Api.Client/Converters/ActivityJsonConverterFactory.cs deleted file mode 100644 index 95dcad2b9..000000000 --- a/src/clients/Elsa.Api.Client/Converters/ActivityJsonConverterFactory.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; -using Elsa.Api.Client.Activities; -using Microsoft.Extensions.DependencyInjection; - -namespace Elsa.Api.Client.Converters; - -/// -/// Creates instances of . -/// -public class ActivityJsonConverterFactory : JsonConverterFactory -{ - private readonly IServiceProvider _serviceProvider; - - /// - public ActivityJsonConverterFactory(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - // Notice that this factory only creates converters when the type to convert is IActivity. - // The ActivityJsonConverter will create concrete activity objects, which then uses regular serialization - /// - public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Activity); - - /// - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => ActivatorUtilities.CreateInstance(_serviceProvider); -} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs b/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs index 28ae5090f..48f2096a8 100644 --- a/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs +++ b/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs @@ -1,108 +1,114 @@ -using Elsa.Api.Client.Activities; +using System.Diagnostics; +using System.Text.Json.Nodes; using Elsa.Api.Client.Shared.Models; namespace Elsa.Api.Client.Extensions; /// -/// Provides extension methods for . +/// Provides extension methods for . /// public static class ActivityExtensions { /// - /// Sets the designer metadata for the specified activity. + /// Gets the type name of the specified activity. /// - public static void SetDesignerMetadata(this Activity activity, ActivityDesignerMetadata designerMetadata) - { - var metadata = activity.Metadata; - metadata["designer"] = designerMetadata; - activity.Metadata = metadata; - } + public static string GetTypeName(this JsonObject activity) => activity.GetProperty("type")!; + + /// + /// Gets the ID of the specified activity. + /// + public static string GetId(this JsonObject activity) => activity.GetProperty("id")!; + + /// + /// Sets the ID of the specified activity. + /// + public static void SetId(this JsonObject activity, string value) => activity.SetProperty(JsonValue.Create(value), "id"); + + /// + /// Gets the name of the specified activity. + /// + public static string? GetName(this JsonObject activity) => activity.GetProperty("name"); + + /// + /// Sets the name of the specified activity. + /// + public static void SetName(this JsonObject activity, string? value) => activity.SetProperty(JsonValue.Create(value), "name"); /// /// Gets the designer metadata for the specified activity. /// - public static ActivityDesignerMetadata GetDesignerMetadata(this Activity activity) - { - var metadata = activity.Metadata; - var designerMetadata = metadata.TryGetValue("designer", () => new ActivityDesignerMetadata())!; - metadata["designer"] = designerMetadata; - activity.Metadata = metadata; - return designerMetadata; - } - + public static JsonObject? GetMetadata(this JsonObject activity) => activity.GetProperty("metadata")?.AsObject(); + + /// + /// Sets the designer metadata for the specified activity. + /// + public static void SetDesignerMetadata(this JsonObject activity, ActivityDesignerMetadata designerMetadata) => activity.SetProperty(designerMetadata.SerializeToNode(), "metadata", "designer"); + + /// + /// Gets the designer metadata for the specified activity. + /// + public static ActivityDesignerMetadata GetDesignerMetadata(this JsonObject activity) => activity.GetProperty("metadata", "designer") ?? new ActivityDesignerMetadata(); + /// /// Gets the display text for the specified activity. /// - public static string? GetDisplayText(this Activity activity) - { - var metadata = activity.Metadata; - return metadata.TryGetValue("displayText"); - } - + public static string? GetDisplayText(this JsonObject activity) => activity.GetProperty("metadata", "displayText")?.GetValue(); + /// /// Sets the display text for the specified activity. /// - public static void SetDisplayText(this Activity activity, string value) + public static void SetDisplayText(this JsonObject activity, string? value) { - var metadata = activity.Metadata; - metadata["displayText"] = value; - activity.Metadata = metadata; + activity.SetProperty(JsonValue.Create(value), "metadata", "displayText"); } - + /// /// Gets the description for the specified activity. /// - public static string? GetDescription(this Activity activity) - { - var metadata = activity.Metadata; - return metadata.TryGetValue("description"); - } - + public static string? GetDescription(this JsonObject activity) => activity.GetProperty("metadata", "description")?.GetValue(); + /// /// Sets the description for the specified activity. /// - public static void SetDescription(this Activity activity, string value) - { - var metadata = activity.Metadata; - metadata["description"] = value; - activity.Metadata = metadata; - } - + public static void SetDescription(this JsonObject activity, string value) => activity.SetProperty(JsonValue.Create(value), "metadata", "description"); + /// /// Gets a value indicating whether the description for the specified activity should be shown. /// - public static bool? GetShowDescription(this Activity activity) - { - var metadata = activity.Metadata; - return metadata.TryGetValue("showDescription"); - } - + public static bool? GetShowDescription(this JsonObject activity) => activity.GetProperty("metadata", "showDescription"); + /// /// Sets a value indicating whether the description for the specified activity should be shown. /// - public static void SetShowDescription(this Activity activity, bool value) - { - var metadata = activity.Metadata; - metadata["showDescription"] = value; - activity.Metadata = metadata; - } - + public static void SetShowDescription(this JsonObject activity, bool value) => activity.SetProperty(JsonValue.Create(value), "metadata", "showDescription"); + /// /// Gets a value indicating whether the specified activity can trigger the workflow. /// - public static bool? GetCanStartWorkflow(this Activity activity) - { - var properties = activity.CustomProperties; - return properties.TryGetValue("canStartWorkflow"); - } - + public static bool? GetCanStartWorkflow(this JsonObject activity) => activity.GetProperty("customProperties", "canStartWorkflow"); + /// /// Sets a value indicating whether the specified activity can trigger the workflow. /// - public static void SetCanStartWorkflow(this Activity activity, bool value) - { - var properties = activity.CustomProperties; - properties["canStartWorkflow"] = value; - activity.CustomProperties = properties; - } + public static void SetCanStartWorkflow(this JsonObject activity, bool value) => activity.SetProperty(JsonValue.Create(value), "customProperties", "canStartWorkflow"); + + /// + /// Gets the activities in the specified flowchart. + /// + public static IEnumerable GetActivities(this JsonObject flowchart) => flowchart.GetProperty("activities")?.AsArray().AsEnumerable().Cast() ?? Array.Empty(); + + /// + /// Sets the activities in the specified flowchart. + /// + public static void SetActivities(this JsonObject flowchart, JsonArray activities) => flowchart.SetProperty(activities, "activities"); + + /// + /// Gets the connections in the specified flowchart. + /// + public static IEnumerable GetConnections(this JsonObject flowchart) => flowchart.GetProperty>("connections") ?? new List(); + + /// + /// Sets the connections in the specified flowchart. + /// + public static void SetConnections(this JsonObject flowchart, IEnumerable connections) => flowchart.SetProperty(JsonValue.Create(connections), "connections"); } \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs b/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs index 53dfa149c..91a96f113 100644 --- a/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs +++ b/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs @@ -1,6 +1,5 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Elsa.Api.Client.ActivityProviders; using Elsa.Api.Client.Contracts; using Elsa.Api.Client.Converters; using Elsa.Api.Client.Options; @@ -49,10 +48,6 @@ public static class DependencyInjectionExtensions /// public static IServiceCollection AddActivityTypeService(this IServiceCollection services) { - services.AddSingleton(); - services.AddActivityTypeResolver(); - services.AddActivityTypeResolver(); - services.AddActivityTypeResolver(); return services; } @@ -67,14 +62,6 @@ public static class DependencyInjectionExtensions services.AddRefitClient(settings) .ConfigureHttpClient(ConfigureElsaApiHttpClient); } - - /// - /// Adds an activity type resolver to the service collection. - /// - public static IServiceCollection AddActivityTypeResolver(this IServiceCollection services) where T : class, IActivityTypeResolver - { - return services.AddSingleton(); - } private static void ConfigureElsaApiHttpClient(IServiceProvider serviceProvider, HttpClient httpClient) { @@ -91,7 +78,6 @@ public static class DependencyInjectionExtensions serializerOptions.Converters.Add(new JsonStringEnumConverter()); serializerOptions.Converters.Add(new VersionOptionsJsonConverter()); - serializerOptions.Converters.Add(new ActivityJsonConverterFactory(serviceProvider)); serializerOptions.Converters.Add(new ExpressionJsonConverterFactory()); var settings = new RefitSettings diff --git a/src/clients/Elsa.Api.Client/Extensions/JsonObjectExtensions.cs b/src/clients/Elsa.Api.Client/Extensions/JsonObjectExtensions.cs new file mode 100644 index 000000000..b3be9694f --- /dev/null +++ b/src/clients/Elsa.Api.Client/Extensions/JsonObjectExtensions.cs @@ -0,0 +1,186 @@ +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace Elsa.Api.Client.Extensions; + +/// +/// Provides extension methods for . +/// +public static class JsonObjectExtensions +{ + /// + /// Serializes the specified value to a . + /// + /// The value to serialize. + /// The to use. + /// A representing the specified value. + public static JsonNode SerializeToNode(this object value, JsonSerializerOptions? options = default) + { + options ??= new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + + return JsonSerializer.SerializeToNode(value, options)!; + } + + /// + /// Serializes the specified value to a . + /// + /// The value to serialize. + /// The to use. + /// A representing the specified value. + public static JsonArray SerializeToArray(this object value, JsonSerializerOptions? options = default) + { + options ??= new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + + return JsonSerializer.SerializeToNode(value, options)!.AsArray(); + } + + /// + /// Serializes the specified value to a . + /// + /// The value to serialize. + /// The to use. + /// A representing the specified value. + public static JsonArray SerializeToArray(this IEnumerable value, JsonSerializerOptions? options = default) + { + options ??= new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + + return JsonSerializer.SerializeToNode(value, options)!.AsArray(); + } + + /// + /// Deserializes the specified to the specified type. + /// + /// The to deserialize. + /// The to use. + /// The type to deserialize to. + /// The deserialized value. + public static T Deserialize(this JsonNode value, JsonSerializerOptions? options = default) + { + options ??= new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + + if (value is JsonObject jsonObject) + return JsonSerializer.Deserialize(jsonObject, options)!; + + if (value is JsonArray jsonArray) + return JsonSerializer.Deserialize(jsonArray, options)!; + + if (value is JsonValue jsonValue) + return jsonValue.GetValue(); + + throw new NotSupportedException($"Cannot deserialize {value.GetType()} to {typeof(T)}."); + } + + /// + /// Sets the property value of the specified model. + /// + /// The model to set the property value on. + /// The value to set. + /// The path to the property. + public static void SetProperty(this JsonObject model, JsonNode? value, params string[] path) + { + model = GetPropertyContainer(model, path); + model[path.Last()] = value?.SerializeToNode(); + } + + /// + /// Sets the property value of the specified model. + /// + /// The model to set the property value on. + /// The value to set. + /// The path to the property. + public static void SetProperty(this JsonObject model, JsonArray? value, params string[] path) + { + model = GetPropertyContainer(model, path); + model[path.Last()] = value?.SerializeToNode(); + } + + /// + /// Sets the property value of the specified model. + /// + /// The model to set the property value on. + /// The value to set. + /// The path to the property. + public static void SetProperty(this JsonObject model, IEnumerable value, params string[] path) + { + model = GetPropertyContainer(model, path); + model[path.Last()] = new JsonArray(value.Select(x => x.SerializeToNode()).ToArray()); + } + + /// + /// Gets the property value of the specified model. + /// + /// The model to get the property value from. + /// The path to the property. + /// The property value. + public static JsonNode? GetProperty(this JsonObject model, params string[] path) + { + var currentModel = model; + + foreach (var prop in path.SkipLast(1)) + { + if (currentModel[prop] is not JsonObject value) + return default; + + currentModel = value; + } + + return currentModel[path.Last()]; + } + + /// + /// Gets the property value of the specified model. + /// + /// The model to get the property value from. + /// The path to the property. + /// The type to deserialize to. + /// The property value. + public static T? GetProperty(this JsonObject model, params string[] path) + { + var property = GetProperty(model, path); + return property != null ? property.Deserialize() : default; + } + + /// + /// Gets the property value of the specified model. + /// + /// The model to get the property value from. + /// The to use when deserializing. + /// The path to the property. + /// The type to deserialize to. + /// The property value. + public static T? GetProperty(this JsonObject model, JsonSerializerOptions options, params string[] path) + { + var property = GetProperty(model, path); + return property != null ? property.Deserialize(options) : default; + } + + /// + /// Returns the property container of the specified model. + /// + /// The model to set the property value on. + /// The path to the property. + private static JsonObject GetPropertyContainer(this JsonObject model, params string[] path) + { + foreach (var prop in path.SkipLast(1)) + { + var property = model[prop] as JsonObject ?? new JsonObject(); + model[prop] = property; + model = property; + } + + return model; + } + +} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Extensions/ObjectConverter.cs b/src/clients/Elsa.Api.Client/Extensions/ObjectConverter.cs index 81ba16c24..3da14215c 100644 --- a/src/clients/Elsa.Api.Client/Extensions/ObjectConverter.cs +++ b/src/clients/Elsa.Api.Client/Extensions/ObjectConverter.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Dynamic; using System.Globalization; using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.Json.Serialization; namespace Elsa.Api.Client.Extensions; @@ -52,17 +53,20 @@ public static class ObjectConverter var underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType; var underlyingSourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType; - if (value is JsonElement jsonNumber && jsonNumber.ValueKind == JsonValueKind.Number && underlyingTargetType == typeof(string)) + if (value is JsonElement { ValueKind: JsonValueKind.Number } jsonNumber && underlyingTargetType == typeof(string)) return jsonNumber.ToString().ConvertTo(underlyingTargetType); - if (value is JsonElement jsonObject) + if (value is JsonElement jsonElement) { - if (jsonObject.ValueKind == JsonValueKind.String && underlyingTargetType != typeof(string)) - return jsonObject.GetString().ConvertTo(underlyingTargetType); + if (jsonElement.ValueKind == JsonValueKind.String && underlyingTargetType != typeof(string)) + return jsonElement.GetString().ConvertTo(underlyingTargetType); - return jsonObject.Deserialize(targetType, options); + return jsonElement.Deserialize(targetType, options); } + if (value is JsonNode jsonNode) + return jsonNode.Deserialize(targetType, options); + if (underlyingSourceType == typeof(string) && !underlyingTargetType.IsPrimitive && underlyingTargetType != typeof(object)) { var stringValue = (string)value; @@ -116,7 +120,7 @@ public static class ObjectConverter if (targetTypeConverter.CanConvertFrom(underlyingSourceType)) return targetTypeConverter.IsValid(value) - ? targetTypeConverter.ConvertFrom(null, CultureInfo.InvariantCulture, value) + ? targetTypeConverter.ConvertFrom(null!, CultureInfo.InvariantCulture, value) : targetType.GetDefaultValue(); var sourceTypeConverter = TypeDescriptor.GetConverter(underlyingSourceType); diff --git a/src/clients/Elsa.Api.Client/Resources/StorageDrivers/Models/StorageDriverDescriptor.cs b/src/clients/Elsa.Api.Client/Resources/StorageDrivers/Models/StorageDriverDescriptor.cs index 0298909a8..e0bab6929 100644 --- a/src/clients/Elsa.Api.Client/Resources/StorageDrivers/Models/StorageDriverDescriptor.cs +++ b/src/clients/Elsa.Api.Client/Resources/StorageDrivers/Models/StorageDriverDescriptor.cs @@ -1,3 +1,8 @@ namespace Elsa.Api.Client.Resources.StorageDrivers.Models; +/// +/// Represents a storage driver descriptor. +/// +/// The type name of the storage driver. +/// The display name of the storage driver. public record StorageDriverDescriptor(string TypeName, string DisplayName); \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinition.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinition.cs index 13aff1255..d7efeb92c 100644 --- a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinition.cs +++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinition.cs @@ -1,4 +1,7 @@ -using Elsa.Api.Client.Activities; +//using Elsa.Api.Client.Activities; + +using System.Text.Json; +using System.Text.Json.Nodes; using Elsa.Api.Client.Shared.Models; namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Models; @@ -76,7 +79,7 @@ public class WorkflowDefinition : VersionedEntity /// /// The root activity of the workflow. /// - public Activity Root { get; set; } = default!; + public JsonObject Root { get; set; } = default!; /// /// An option to use the workflow as a readonly workflow. diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinitionModel.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinitionModel.cs index 5b1fd2a01..c60a0f3ee 100644 --- a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinitionModel.cs +++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinitionModel.cs @@ -1,4 +1,6 @@ -using Elsa.Api.Client.Activities; +using System.Text.Json; +using System.Text.Json.Nodes; +//using Elsa.Api.Client.Activities; using JetBrains.Annotations; namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Models; @@ -9,25 +11,88 @@ namespace Elsa.Api.Client.Resources.WorkflowDefinitions.Models; [PublicAPI] public class WorkflowDefinitionModel { + /// + /// Gets or sets the version ID of the workflow definition. + /// public string Id { get; set; } = default!; + + /// + /// Gets or sets the definition ID of the workflow definition. + /// public string DefinitionId { get; set; } = default!; + + /// + /// Gets or sets the name of the workflow definition. + /// public string? Name { get; set; } + + /// + /// Gets or sets the description of the workflow definition. + /// public string? Description { get; set; } + + /// + /// Gets or sets the time at which the workflow definition was created. + /// public DateTimeOffset CreatedAt { get; set; } + + /// + /// Gets or sets the version of the workflow definition. + /// public int Version { get; set; } + + /// + /// Gets or sets the version of the tool that created the workflow definition. + /// public Version? ToolVersion { get; set; } + + /// + /// Gets or sets the variables of the workflow definition. + /// public ICollection? Variables { get; set; } + + /// + /// Gets or sets the inputs of the workflow definition. + /// public ICollection? Inputs { get; set; } + + /// + /// Gets or sets the outputs of the workflow definition. + /// public ICollection? Outputs { get; set; } + + /// + /// Gets or sets the outcomes of the workflow definition. + /// public ICollection? Outcomes { get; set; } + + /// + /// Gets or sets the custom properties associated with the workflow definition. + /// public IDictionary? CustomProperties { get; set; } + + /// + /// Gets or sets whether the workflow definition is read-only. + /// public bool IsReadonly { get; set; } + + /// + /// Gets or sets whether this is the latest version of the workflow definition. + /// public bool IsLatest { get; set; } + + /// + /// Gets or sets whether this is the published version of the workflow definition. + /// public bool IsPublished { get; set; } - /// The type of IWorkflowActivationStrategy to apply when new instances are requested to be created. + /// + /// Gets or sets the of the workflow definition. + /// public WorkflowOptions? Options { get; set; } - /// - public Activity? Root { get; set; } + /// + /// Gets or sets the root activity of the workflow definition. + /// + public JsonObject? Root { get; set; } } \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Services/DefaultActivityTypeService.cs b/src/clients/Elsa.Api.Client/Services/DefaultActivityTypeService.cs index e5ec39f3b..c9ea2fbaf 100644 --- a/src/clients/Elsa.Api.Client/Services/DefaultActivityTypeService.cs +++ b/src/clients/Elsa.Api.Client/Services/DefaultActivityTypeService.cs @@ -1,35 +1,35 @@ -using Elsa.Api.Client.Activities; -using Elsa.Api.Client.Contracts; - -namespace Elsa.Api.Client.Services; - -/// -/// Provides a default implementation of that creates a . -/// -public class DefaultActivityTypeService : IActivityTypeService -{ - private readonly IEnumerable _activityProviders; - - /// - /// Initializes a new instance of the class. - /// - /// The s. - public DefaultActivityTypeService(IEnumerable activityProviders) - { - _activityProviders = activityProviders.OrderByDescending(x => x.Priority); - } - - /// - public Type ResolveType(string activityType) - { - var context = new ActivityTypeResolverContext(activityType); - var activityProvider = GetActivityProvider(context); - - if (activityProvider == null) - throw new Exception($"No activity provider found for activity type '{activityType}'."); - - return activityProvider.ResolveType(context); - } - - private IActivityTypeResolver? GetActivityProvider(ActivityTypeResolverContext context) => _activityProviders.FirstOrDefault(provider => provider.GetSupportsType(context)); -} \ No newline at end of file +// using Elsa.Api.Client.Activities; +// using Elsa.Api.Client.Contracts; +// +// namespace Elsa.Api.Client.Services; +// +// /// +// /// Provides a default implementation of that creates a . +// /// +// public class DefaultActivityTypeService : IActivityTypeService +// { +// private readonly IEnumerable _activityProviders; +// +// /// +// /// Initializes a new instance of the class. +// /// +// /// The s. +// public DefaultActivityTypeService(IEnumerable activityProviders) +// { +// _activityProviders = activityProviders.OrderByDescending(x => x.Priority); +// } +// +// /// +// public Type ResolveType(string activityType) +// { +// var context = new ActivityTypeResolverContext(activityType); +// var activityProvider = GetActivityProvider(context); +// +// if (activityProvider == null) +// throw new Exception($"No activity provider found for activity type '{activityType}'."); +// +// return activityProvider.ResolveType(context); +// } +// +// private IActivityTypeResolver? GetActivityProvider(ActivityTypeResolverContext context) => _activityProviders.FirstOrDefault(provider => provider.GetSupportsType(context)); +// } \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Shared/Models/ActivityDesignerMetadata.cs b/src/clients/Elsa.Api.Client/Shared/Models/ActivityDesignerMetadata.cs index f84c005e1..24e3f6d62 100644 --- a/src/clients/Elsa.Api.Client/Shared/Models/ActivityDesignerMetadata.cs +++ b/src/clients/Elsa.Api.Client/Shared/Models/ActivityDesignerMetadata.cs @@ -41,10 +41,10 @@ public class ActivityDesignerMetadata /// /// Gets or sets the position of the activity. /// - public Position Position { get; set; } = default!; + public Position Position { get; set; } = new(); /// /// Gets or sets the size of the activity. /// - public Size Size { get; set; } = default!; + public Size Size { get; set; } = new(); } \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Shared/Models/Container.cs b/src/clients/Elsa.Api.Client/Shared/Models/Container.cs index 0df8541af..e173976d9 100644 --- a/src/clients/Elsa.Api.Client/Shared/Models/Container.cs +++ b/src/clients/Elsa.Api.Client/Shared/Models/Container.cs @@ -1,29 +1,29 @@ -using Elsa.Api.Client.Activities; -using Elsa.Api.Client.Extensions; -using Elsa.Api.Client.Resources.WorkflowDefinitions.Models; - -namespace Elsa.Api.Client.Shared.Models; - -/// -/// Represents a container activity. -/// -public class Container : Activity -{ - /// - /// Gets or sets the activities contained in this container. - /// - public ICollection Activities - { - get => this.TryGetValue>("activities", () => new List())!; - set => this["activities"] = value; - } - - /// - /// Gets or sets the variables in this container. - /// - public ICollection Variables - { - get => this.TryGetValue>("variables", () => new List())!; - set => this["variables"] = value; - } -} \ No newline at end of file +// using Elsa.Api.Client.Activities; +// using Elsa.Api.Client.Extensions; +// using Elsa.Api.Client.Resources.WorkflowDefinitions.Models; +// +// namespace Elsa.Api.Client.Shared.Models; +// +// /// +// /// Represents a container activity. +// /// +// public class Container : Activity +// { +// /// +// /// Gets or sets the activities contained in this container. +// /// +// public ICollection Activities +// { +// get => this.TryGetValue>("activities", () => new List())!; +// set => this["activities"] = value; +// } +// +// /// +// /// Gets or sets the variables in this container. +// /// +// public ICollection Variables +// { +// get => this.TryGetValue>("variables", () => new List())!; +// set => this["variables"] = value; +// } +// } \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Shared/Models/HttpStatusCodeCase.cs b/src/clients/Elsa.Api.Client/Shared/Models/HttpStatusCodeCase.cs index d88e22566..ed8352e1e 100644 --- a/src/clients/Elsa.Api.Client/Shared/Models/HttpStatusCodeCase.cs +++ b/src/clients/Elsa.Api.Client/Shared/Models/HttpStatusCodeCase.cs @@ -1,4 +1,4 @@ -using Elsa.Api.Client.Activities; +using System.Text.Json.Nodes; namespace Elsa.Api.Client.Shared.Models; @@ -15,5 +15,5 @@ public class HttpStatusCodeCase /// /// The activity to execute when the HTTP status code matches. /// - public Activity? Activity { get; set; } + public JsonObject? Activity { get; set; } } \ No newline at end of file