Add support for object literals to Outcome activity
This commit is contained in:
parent
c56f27c580
commit
a9e67b9b1c
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, h, Prop, State} from '@stencil/core';
|
||||
import {uniq} from 'lodash'
|
||||
import {JsonExpression, LiteralExpression, SelectList, SyntaxNames} from "../../models";
|
||||
import {ObjectExpression, SelectList, SyntaxNames} from "../../models";
|
||||
import {ActivityInputContext} from "../../services/activity-input-driver";
|
||||
import {getSelectListItems, getInputPropertyValue, parseJson} from "../../utils";
|
||||
import {ExpressionChangedArs} from "../shared/input-control-switch/input-control-switch";
|
||||
|
|
@ -24,6 +24,8 @@ export class CheckList {
|
|||
this.selectedValues = selectedValues;
|
||||
else if (typeof (selectedValues) == 'number')
|
||||
this.selectedValue = selectedValues;
|
||||
else if (typeof selectedValues == 'string')
|
||||
this.selectedValues = JSON.parse(selectedValues);
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
|
@ -34,7 +36,7 @@ export class CheckList {
|
|||
const displayName = inputDescriptor.displayName;
|
||||
const hint = inputDescriptor.description;
|
||||
const input = getInputPropertyValue(inputContext);
|
||||
const value = (input?.expression as JsonExpression)?.value; // TODO: The "value" field is currently hardcoded, but we should be able to be more flexible and potentially have different fields for a given syntax.
|
||||
const value = (input?.expression as ObjectExpression)?.value; // TODO: The "value" field is currently hardcoded, but we should be able to be more flexible and potentially have different fields for a given syntax.
|
||||
const syntax = input?.expression?.type ?? inputDescriptor.defaultSyntax;
|
||||
const selectList = this.selectList;
|
||||
|
||||
|
|
@ -70,7 +72,7 @@ export class CheckList {
|
|||
|
||||
private getSelectedValues = (selectList: SelectList): number | Array<string> => {
|
||||
const input = getInputPropertyValue(this.inputContext);
|
||||
const json = (input?.expression as JsonExpression)?.value;
|
||||
const json = (input?.expression as ObjectExpression)?.value;
|
||||
return selectList.isFlagsEnum ? parseInt(json) : parseJson(json) || [];
|
||||
};
|
||||
|
||||
|
|
@ -103,7 +105,7 @@ export class CheckList {
|
|||
json = JSON.stringify(newValue);
|
||||
}
|
||||
|
||||
this.inputContext.inputChanged(json, SyntaxNames.Json);
|
||||
this.inputContext.inputChanged(json, SyntaxNames.Object);
|
||||
}
|
||||
|
||||
private onExpressionChanged = (e: CustomEvent<ExpressionChangedArs>) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import {Component, Prop, h} from '@stencil/core';
|
||||
import {JsonExpression, LiteralExpression, SyntaxNames} from "../../models";
|
||||
import {ObjectExpression, LiteralExpression, SyntaxNames} from "../../models";
|
||||
import {ActivityInputContext} from "../../services/activity-input-driver";
|
||||
import {getInputPropertyValue, parseJson} from "../../utils";
|
||||
import {ExpressionChangedArs} from "../shared/input-control-switch/input-control-switch";
|
||||
|
|
@ -19,7 +19,7 @@ export class MultiTextInput {
|
|||
const hint = inputDescriptor.description;
|
||||
const input = getInputPropertyValue(inputContext);
|
||||
const syntax = input?.expression?.type ?? inputDescriptor.defaultSyntax;
|
||||
const json = (input?.expression as JsonExpression)?.value;
|
||||
const json = (input?.expression as ObjectExpression)?.value;
|
||||
const values = parseJson(json);
|
||||
|
||||
return (
|
||||
|
|
@ -31,7 +31,7 @@ export class MultiTextInput {
|
|||
|
||||
private onPropertyEditorChanged = (e: CustomEvent<Array<string>>) => {
|
||||
const json = JSON.stringify(e.detail);
|
||||
this.inputContext.inputChanged(json, SyntaxNames.Json);
|
||||
this.inputContext.inputChanged(json, SyntaxNames.Object);
|
||||
};
|
||||
|
||||
private onExpressionChanged = (e: CustomEvent<ExpressionChangedArs>) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import {Component, Prop, h} from '@stencil/core';
|
||||
import {JsonExpression, LiteralExpression, SyntaxNames, Variable} from "../../models";
|
||||
import {ObjectExpression, LiteralExpression, SyntaxNames, Variable} from "../../models";
|
||||
import {ActivityInputContext} from "../../services/activity-input-driver";
|
||||
import {getInputPropertyValue, getPropertyValue} from "../../utils";
|
||||
import {FormEntry} from "../shared/forms/form-entry";
|
||||
|
|
@ -22,7 +22,7 @@ export class OutcomePicker {
|
|||
const displayName = inputDescriptor.displayName;
|
||||
const description = inputDescriptor.description;
|
||||
const input = getInputPropertyValue(inputContext);
|
||||
const value = (input?.expression as JsonExpression)?.value;
|
||||
const value = (input?.expression as ObjectExpression)?.value;
|
||||
const syntax = input?.expression?.type ?? inputDescriptor.defaultSyntax;
|
||||
|
||||
return (
|
||||
|
|
@ -51,6 +51,6 @@ export class OutcomePicker {
|
|||
private onChange = (e: Event) => {
|
||||
const inputElement = e.target as HTMLSelectElement;
|
||||
const outcome = inputElement.value;
|
||||
this.inputContext.inputChanged(outcome, SyntaxNames.Json);
|
||||
this.inputContext.inputChanged(outcome, SyntaxNames.Object);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ export enum SyntaxNames {
|
|||
Literal = 'Literal',
|
||||
JavaScript = 'JavaScript',
|
||||
Liquid = 'Liquid',
|
||||
Json = 'Json'
|
||||
Object = 'Object'
|
||||
}
|
||||
|
||||
export interface ActivityMetadata {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
export type ExpressionType = string;
|
||||
export type Expression = LiteralExpression | JavaScriptExpression | JsonExpression;
|
||||
export type Expression = LiteralExpression | JavaScriptExpression | ObjectExpression;
|
||||
|
||||
export interface LiteralExpression {
|
||||
type: ExpressionType;
|
||||
|
|
@ -11,7 +11,7 @@ export interface JavaScriptExpression {
|
|||
value: string;
|
||||
}
|
||||
|
||||
export interface JsonExpression {
|
||||
export interface ObjectExpression {
|
||||
type: ExpressionType;
|
||||
value: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'reflect-metadata';
|
||||
import {Service} from "typedi";
|
||||
import {Activity, ActivityInput, InputDescriptor, JsonExpression, Port, PortMode} from "../../../models";
|
||||
import {Activity, ActivityInput, InputDescriptor, ObjectExpression, Port, PortMode} from "../../../models";
|
||||
import {PortProvider, PortProviderContext} from "../../../services";
|
||||
import {FlowSendHttpRequest} from "./models";
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ export class FlowHttpRequestPortProvider implements PortProvider {
|
|||
if(!expectedStatusCodes)
|
||||
return [];
|
||||
|
||||
const statusCodesJson = (expectedStatusCodes.expression as JsonExpression).value;
|
||||
const statusCodesJson = (expectedStatusCodes.expression as ObjectExpression).value;
|
||||
const statusCodes = JSON.parse(statusCodesJson) as Array<string>;
|
||||
const catchAllPort = {name: 'Unmatched status code', displayName: 'Unmatched status code', mode: PortMode.Port};
|
||||
const outcomes = [...statusCodes.map(x => ({name: x.toString(), displayName: x.toString(), mode: PortMode.Port})), catchAllPort];
|
||||
|
|
|
|||
|
|
@ -2,7 +2,13 @@ using Elsa.Expressions.Models;
|
|||
|
||||
namespace Elsa.Expressions.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Provides descriptors for expression syntaxes.
|
||||
/// </summary>
|
||||
public interface IExpressionSyntaxProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the descriptors for the expression syntaxes supported by this provider.
|
||||
/// </summary>
|
||||
ValueTask<IEnumerable<ExpressionSyntaxDescriptor>> GetDescriptorsAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ public static class ObjectConverter
|
|||
if (sourceType == targetType)
|
||||
return value;
|
||||
|
||||
var options = converterOptions?.SerializerOptions ?? new JsonSerializerOptions();
|
||||
var options = converterOptions?.SerializerOptions != null ? new JsonSerializerOptions(converterOptions.SerializerOptions) : new JsonSerializerOptions();
|
||||
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
options.ReferenceHandler = ReferenceHandler.Preserve;
|
||||
options.PropertyNameCaseInsensitive = true;
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ namespace Elsa.Expressions.Models;
|
|||
/// <summary>
|
||||
/// Represents a literal JSON expression.
|
||||
/// </summary>
|
||||
public class JsonLiteral : MemoryBlockReference
|
||||
public class ObjectLiteral : MemoryBlockReference
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[JsonConstructor]
|
||||
public JsonLiteral()
|
||||
public ObjectLiteral()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public JsonLiteral(string? value)
|
||||
public ObjectLiteral(string? value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
|
@ -29,26 +29,26 @@ public class JsonLiteral : MemoryBlockReference
|
|||
public override MemoryBlock Declare() => new();
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the value into a JSON string in the form of a <see cref="JsonLiteral{T}"/>
|
||||
/// Serializes the value into a JSON string in the form of a <see cref="ObjectLiteral{T}"/>
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static JsonLiteral From<T>(T value) => new JsonLiteral<T>(value);
|
||||
public static ObjectLiteral From<T>(T value) => new ObjectLiteral<T>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a JSON string for the specified type <code>T</code>
|
||||
/// </summary>
|
||||
public class JsonLiteral<T> : JsonLiteral
|
||||
public class ObjectLiteral<T> : ObjectLiteral
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public JsonLiteral()
|
||||
public ObjectLiteral()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public JsonLiteral(T value) : base(JsonSerializer.Serialize(value!))
|
||||
public ObjectLiteral(T value) : base(JsonSerializer.Serialize(value!))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ public class HttpEndpoint : Trigger<HttpRequest>
|
|||
Description = "The HTTP methods to accept.",
|
||||
Options = new[] { "GET", "POST", "PUT", "HEAD", "DELETE" },
|
||||
UIHint = InputUIHints.CheckList)]
|
||||
public Input<ICollection<string>> SupportedMethods { get; set; } = new(JsonLiteral.From(new[] { HttpMethods.Get }));
|
||||
public Input<ICollection<string>> SupportedMethods { get; set; } = new(ObjectLiteral.From(new[] { HttpMethods.Get }));
|
||||
|
||||
/// <summary>
|
||||
/// Allow authenticated requests only.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Elsa.Expressions.Models;
|
||||
using Elsa.Extensions;
|
||||
|
|
@ -51,7 +52,7 @@ public class Complete : Activity
|
|||
[Input(
|
||||
Description = "The outcome or set of outcomes to complete this activity with.",
|
||||
UIHint = InputUIHints.OutcomePicker,
|
||||
DefaultSyntax = "Json"
|
||||
DefaultSyntax = "Object"
|
||||
)]
|
||||
public Input<object> Outcomes { get; set; } = default!;
|
||||
|
||||
|
|
@ -83,6 +84,19 @@ public class Complete : Activity
|
|||
yield return outcome.ToString()!;
|
||||
break;
|
||||
}
|
||||
case JsonElement jsonElement:
|
||||
{
|
||||
if (jsonElement.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
var outcomeArray = jsonElement.EnumerateArray().ToList();
|
||||
foreach (var element in outcomeArray)
|
||||
yield return element.ToString();
|
||||
}
|
||||
else
|
||||
yield return jsonElement.ToString();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
yield return "Done";
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,29 +1,30 @@
|
|||
using System.Text.Json;
|
||||
using Elsa.Expressions.Contracts;
|
||||
using Elsa.Expressions.Helpers;
|
||||
using Elsa.Expressions.Models;
|
||||
using Elsa.Workflows.Core.Serialization.Converters;
|
||||
|
||||
namespace Elsa.Workflows.Core.Expressions;
|
||||
|
||||
public class JsonExpression : IExpression
|
||||
public class ObjectExpression : IExpression
|
||||
{
|
||||
public JsonExpression(string? value) => Value = value;
|
||||
public ObjectExpression(string? value) => Value = value;
|
||||
public string? Value { get; }
|
||||
}
|
||||
|
||||
public class JsonExpression<T> : JsonExpression
|
||||
public class ObjectExpression<T> : ObjectExpression
|
||||
{
|
||||
public JsonExpression(T? value) : base(JsonSerializer.Serialize(value))
|
||||
public ObjectExpression(T? value) : base(JsonSerializer.Serialize(value))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class JsonExpressionHandler : IExpressionHandler
|
||||
public class ObjectExpressionHandler : IExpressionHandler
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ValueTask<object?> EvaluateAsync(IExpression expression, Type returnType, ExpressionExecutionContext context)
|
||||
{
|
||||
var jsonExpression = (JsonExpression)expression;
|
||||
var jsonExpression = (ObjectExpression)expression;
|
||||
var value = jsonExpression.Value;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
|
|
@ -32,7 +33,8 @@ public class JsonExpressionHandler : IExpressionHandler
|
|||
var serializerOptions = new JsonSerializerOptions();
|
||||
serializerOptions.Converters.Add(new IntegerConverter());
|
||||
|
||||
var model = JsonSerializer.Deserialize(value, returnType, serializerOptions);
|
||||
var converterOptions = new ObjectConverterOptions(serializerOptions);
|
||||
var model = value.ConvertTo(returnType, converterOptions);
|
||||
return ValueTask.FromResult(model);
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ public class WorkflowsFeature : FeatureBase
|
|||
.AddExpressionHandler<LiteralExpressionHandler, LiteralExpression>()
|
||||
.AddExpressionHandler<DelegateExpressionHandler, DelegateExpression>()
|
||||
.AddExpressionHandler<VariableExpressionHandler, VariableExpression>()
|
||||
.AddExpressionHandler<JsonExpressionHandler, JsonExpression>()
|
||||
.AddExpressionHandler<ObjectExpressionHandler, ObjectExpression>()
|
||||
.AddExpressionHandler<OutputExpressionHandler, OutputExpression>()
|
||||
.AddExpressionHandler<ElsaExpressionHandler, ElsaExpression>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,12 +74,12 @@ public class Input<T> : Input
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Input(JsonLiteral<T> literal) : base(new JsonExpression(literal.Value), literal, typeof(T))
|
||||
public Input(ObjectLiteral<T> literal) : base(new ObjectExpression(literal.Value), literal, typeof(T))
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Input(JsonLiteral literal) : base(new JsonExpression(literal.Value), literal, typeof(T))
|
||||
public Input(ObjectLiteral literal) : base(new ObjectExpression(literal.Value), literal, typeof(T))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,43 +7,57 @@ using Elsa.Workflows.Core.Services;
|
|||
|
||||
namespace Elsa.Workflows.Management.Providers;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class DefaultExpressionSyntaxProvider : IExpressionSyntaxProvider
|
||||
{
|
||||
private readonly IIdentityGenerator _identityGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DefaultExpressionSyntaxProvider"/> class.
|
||||
/// </summary>
|
||||
public DefaultExpressionSyntaxProvider(IIdentityGenerator identityGenerator)
|
||||
{
|
||||
_identityGenerator = identityGenerator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<IEnumerable<ExpressionSyntaxDescriptor>> GetDescriptorsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var literal = CreateLiteralDescriptor();
|
||||
var @object = CreateObjectDescriptor();
|
||||
var json = CreateJsonDescriptor();
|
||||
var @delegate = CreateDelegateDescriptor();
|
||||
|
||||
return ValueTask.FromResult<IEnumerable<ExpressionSyntaxDescriptor>>(new[] { literal, json, @delegate });
|
||||
return ValueTask.FromResult<IEnumerable<ExpressionSyntaxDescriptor>>(new[] { literal, @object, json, @delegate });
|
||||
}
|
||||
|
||||
private ExpressionSyntaxDescriptor CreateLiteralDescriptor() => CreateDescriptor<LiteralExpression>(
|
||||
private ExpressionSyntaxDescriptor CreateLiteralDescriptor() => DefaultExpressionSyntaxProvider.CreateDescriptor<LiteralExpression>(
|
||||
"Literal",
|
||||
CreateLiteralExpression,
|
||||
context => new Literal(context.GetExpression<LiteralExpression>().Value),
|
||||
expression => expression.Value);
|
||||
|
||||
private ExpressionSyntaxDescriptor CreateJsonDescriptor() => CreateDescriptor<JsonExpression>(
|
||||
private ExpressionSyntaxDescriptor CreateObjectDescriptor() => DefaultExpressionSyntaxProvider.CreateDescriptor<ObjectExpression>(
|
||||
"Object",
|
||||
CreateObjectExpression,
|
||||
context => new ObjectLiteral(context.GetExpression<ObjectExpression>().Value),
|
||||
expression => expression.Value);
|
||||
|
||||
// TODO: this is replaced by the above and exists only for existing workflow definitions. To be removed in a future version.
|
||||
[Obsolete]
|
||||
private ExpressionSyntaxDescriptor CreateJsonDescriptor() => DefaultExpressionSyntaxProvider.CreateDescriptor<ObjectExpression>(
|
||||
"Json",
|
||||
CreateJsonExpression,
|
||||
context => new JsonLiteral(context.GetExpression<JsonExpression>().Value),
|
||||
CreateObjectExpression,
|
||||
context => new ObjectLiteral(context.GetExpression<ObjectExpression>().Value),
|
||||
expression => expression.Value);
|
||||
|
||||
private ExpressionSyntaxDescriptor CreateDelegateDescriptor() => CreateDescriptor<DelegateExpression>(
|
||||
private ExpressionSyntaxDescriptor CreateDelegateDescriptor() => DefaultExpressionSyntaxProvider.CreateDescriptor<DelegateExpression>(
|
||||
"Delegate",
|
||||
CreateJsonExpression,
|
||||
CreateObjectExpression,
|
||||
context => new DelegateBlockReference(),
|
||||
expression => expression.DelegateBlockReference.Delegate?.ToString());
|
||||
|
||||
private ExpressionSyntaxDescriptor CreateDescriptor<TExpression>(
|
||||
private static ExpressionSyntaxDescriptor CreateDescriptor<TExpression>(
|
||||
string syntax,
|
||||
Func<ExpressionConstructorContext, IExpression> constructor,
|
||||
Func<BlockReferenceConstructorContext, MemoryBlockReference> createBlockReference,
|
||||
|
|
@ -61,17 +75,17 @@ public class DefaultExpressionSyntaxProvider : IExpressionSyntaxProvider
|
|||
}
|
||||
};
|
||||
|
||||
private IExpression CreateLiteralExpression(ExpressionConstructorContext context)
|
||||
private static IExpression CreateLiteralExpression(ExpressionConstructorContext context)
|
||||
{
|
||||
return !context.Element.TryGetProperty("value", out var expressionValue)
|
||||
? new LiteralExpression()
|
||||
: new LiteralExpression(expressionValue.ToString());
|
||||
}
|
||||
|
||||
private IExpression CreateJsonExpression(ExpressionConstructorContext context)
|
||||
private IExpression CreateObjectExpression(ExpressionConstructorContext context)
|
||||
{
|
||||
var expressionValue = context.Element.GetProperty("value").ToString();
|
||||
return new JsonExpression(expressionValue);
|
||||
return new ObjectExpression(expressionValue);
|
||||
}
|
||||
|
||||
private string GenerateId() => _identityGenerator.GenerateId();
|
||||
|
|
|
|||
Loading…
Reference in a new issue