Define activities (#78)
* Annotate activities with design-time attributes
This commit is contained in:
parent
02be088cdb
commit
e1da5f5f19
|
|
@ -83,6 +83,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample15", "samples\Sample1
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.WorkflowHost.Web", "src\dashboard\Elsa.WorkflowHost.Web\Elsa.WorkflowHost.Web.csproj", "{1680B0F4-4FA3-4ED3-8DA1-23DF034D6009}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.WorkflowDesigner", "src\dashboard\Elsa.WorkflowDesigner\Elsa.WorkflowDesigner.csproj", "{944DAD02-4024-4D3E-8C75-AE313EA02A94}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -209,6 +211,10 @@ Global
|
|||
{1680B0F4-4FA3-4ED3-8DA1-23DF034D6009}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1680B0F4-4FA3-4ED3-8DA1-23DF034D6009}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1680B0F4-4FA3-4ED3-8DA1-23DF034D6009}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{944DAD02-4024-4D3E-8C75-AE313EA02A94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{944DAD02-4024-4D3E-8C75-AE313EA02A94}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{944DAD02-4024-4D3E-8C75-AE313EA02A94}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{944DAD02-4024-4D3E-8C75-AE313EA02A94}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -249,6 +255,7 @@ Global
|
|||
{5155F75B-38F2-4B5B-9C8F-6F6641BF986B} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
|
||||
{5E5E1E84-DDBC-40D6-B891-0D563A15A44A} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
|
||||
{1680B0F4-4FA3-4ED3-8DA1-23DF034D6009} = {0DF567E8-2A21-4A1C-90E8-025F1EC615F3}
|
||||
{944DAD02-4024-4D3E-8C75-AE313EA02A94} = {0DF567E8-2A21-4A1C-90E8-025F1EC615F3}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
|
@ -10,6 +11,15 @@ namespace Elsa.Activities.Console.Activities
|
|||
/// <summary>
|
||||
/// Reads input from the console.
|
||||
/// </summary>
|
||||
[ActivityDefinition(
|
||||
Category = "Console",
|
||||
Description = "Read text from standard in."
|
||||
)]
|
||||
[ActivityDefinitionDesigner(
|
||||
Description =
|
||||
"a => !!a.state.variableName ? `Read text from standard in and store into <strong>${ a.state.variableName }</strong>.` : 'Read text from standard in.'",
|
||||
Outcomes = new[] { OutcomeNames.Done }
|
||||
)]
|
||||
public class ReadLine : Activity
|
||||
{
|
||||
private readonly TextReader input;
|
||||
|
|
@ -23,13 +33,15 @@ namespace Elsa.Activities.Console.Activities
|
|||
this.input = input;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The name of the variable to store the value into.")]
|
||||
public string VariableName
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext context,
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
|
||||
WorkflowExecutionContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (input == null)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -12,6 +13,15 @@ namespace Elsa.Activities.Console.Activities
|
|||
/// <summary>
|
||||
/// Writes a text string to the console.
|
||||
/// </summary>
|
||||
[ActivityDefinition(
|
||||
Category = "Console",
|
||||
Description = "Write text to standard out."
|
||||
)]
|
||||
[ActivityDefinitionDesigner(
|
||||
Description =
|
||||
"x => !!x.state.textExpression ? `Write <strong>${ x.state.textExpression.expression }</strong> to standard out.` : x.definition.description",
|
||||
Outcomes = new[] { OutcomeNames.Done }
|
||||
)]
|
||||
public class WriteLine : Activity
|
||||
{
|
||||
public WriteLine(IWorkflowExpressionEvaluator evaluator)
|
||||
|
|
@ -25,6 +35,7 @@ namespace Elsa.Activities.Console.Activities
|
|||
this.output = output;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The text to write.")]
|
||||
public WorkflowExpression<string> TextExpression
|
||||
{
|
||||
get => GetState(() => LiteralEvaluator.Expression<string>(null));
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Email.Options;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -11,6 +12,10 @@ using Microsoft.Extensions.Options;
|
|||
|
||||
namespace Elsa.Activities.Email.Activities
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "Email",
|
||||
Description = "Send an email message."
|
||||
)]
|
||||
public class SendEmail : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -18,7 +23,7 @@ namespace Elsa.Activities.Email.Activities
|
|||
private readonly SmtpClient smtpClient;
|
||||
|
||||
public SendEmail(
|
||||
IWorkflowExpressionEvaluator expressionEvaluator,
|
||||
IWorkflowExpressionEvaluator expressionEvaluator,
|
||||
IOptions<SmtpOptions> options,
|
||||
SmtpClient smtpClient)
|
||||
{
|
||||
|
|
@ -27,24 +32,28 @@ namespace Elsa.Activities.Email.Activities
|
|||
this.smtpClient = smtpClient;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The sender's email address.")]
|
||||
public WorkflowExpression<string> From
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The recipient's email address.")]
|
||||
public WorkflowExpression<string> To
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The subject of the email message.")]
|
||||
public WorkflowExpression<string> Subject
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The body of the email message.")]
|
||||
public WorkflowExpression<string> Body
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
|
|
@ -54,7 +63,8 @@ namespace Elsa.Activities.Email.Activities
|
|||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var from = (await expressionEvaluator.EvaluateAsync(From, workflowContext, cancellationToken)) ?? options.Value.DefaultSender;
|
||||
var from = (await expressionEvaluator.EvaluateAsync(From, workflowContext, cancellationToken)) ??
|
||||
options.Value.DefaultSender;
|
||||
var to = await expressionEvaluator.EvaluateAsync(To, workflowContext, cancellationToken);
|
||||
var subject = await expressionEvaluator.EvaluateAsync(Subject, workflowContext, cancellationToken);
|
||||
var body = await expressionEvaluator.EvaluateAsync(Body, workflowContext, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -8,16 +8,24 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Http.Models;
|
||||
using Elsa.Activities.Http.Services;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Elsa.WorkflowDesigner.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Elsa.Activities.Http.Activities
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "HTTP",
|
||||
DisplayName = "Send HTTP Request",
|
||||
Description = "Send an HTTP request."
|
||||
)]
|
||||
[ActivityDefinitionDesigner(Outcomes = "x => !!x.state.supportedStatusCodes ? x.state.supportedStatusCodes : []")]
|
||||
public class HttpRequestAction : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -37,6 +45,7 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// The URL to invoke.
|
||||
/// </summary>
|
||||
[ActivityProperty(Hint = "The URL to send the HTTP request to.")]
|
||||
public WorkflowExpression<Uri> Url
|
||||
{
|
||||
get
|
||||
|
|
@ -54,6 +63,11 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// The HTTP method to use.
|
||||
/// </summary>
|
||||
[ActivityProperty(
|
||||
Type = ActivityPropertyTypes.Select,
|
||||
Hint = "The HTTP method to use when making the request."
|
||||
)]
|
||||
[SelectOptions("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD")]
|
||||
public string Method
|
||||
{
|
||||
get => GetState(() => "GET");
|
||||
|
|
@ -63,7 +77,8 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// The body to send along with the request.
|
||||
/// </summary>
|
||||
public WorkflowExpression<string> Body
|
||||
[ActivityProperty(Hint = "The HTTP content to send along with the request.")]
|
||||
public WorkflowExpression<string> Content
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
set => SetState(value);
|
||||
|
|
@ -72,6 +87,11 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// The Content Type header to send along with the request body.
|
||||
/// </summary>
|
||||
[ActivityProperty(
|
||||
Type = ActivityPropertyTypes.Select,
|
||||
Hint = "The content type to send with the request."
|
||||
)]
|
||||
[SelectOptions("text/plain", "text/html", "application/json", "application/xml")]
|
||||
public WorkflowExpression<string> ContentType
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
|
|
@ -81,6 +101,7 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// The headers to send along with the request.
|
||||
/// </summary>
|
||||
[ActivityProperty(Hint = "The headers to send along with the request. One 'header: value' pair per line.")]
|
||||
public WorkflowExpression<string> RequestHeaders
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
|
|
@ -90,6 +111,10 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// A list of HTTP status codes this activity can handle.
|
||||
/// </summary>
|
||||
[ActivityProperty(
|
||||
Type = ActivityPropertyTypes.List,
|
||||
Hint = "A list of possible HTTP status codes to handle, comma-separated. Example: 200, 400, 404"
|
||||
)]
|
||||
public HashSet<int> SupportedStatusCodes
|
||||
{
|
||||
get => GetState(() => new HashSet<int> { 200 });
|
||||
|
|
@ -102,14 +127,16 @@ namespace Elsa.Activities.Http.Activities
|
|||
{
|
||||
var request = await CreateRequestAsync(workflowContext, cancellationToken);
|
||||
var response = await httpClient.SendAsync(request, cancellationToken);
|
||||
var content = response.Content != null ? await response.Content.ReadAsStringAsync() : default(string);
|
||||
var content = response.Content != null ? await response.Content.ReadAsStringAsync() : default;
|
||||
var contentType = response.Content?.Headers.ContentType.MediaType;
|
||||
var formatter = SelectContentFormatter(contentType);
|
||||
|
||||
var responseModel = new HttpResponseModel
|
||||
{
|
||||
StatusCode = response.StatusCode,
|
||||
Headers = new HeaderDictionary(response.Headers.ToDictionary(x => x.Key, x => new StringValues(x.Value.ToArray()))),
|
||||
Headers = new HeaderDictionary(
|
||||
response.Headers.ToDictionary(x => x.Key, x => new StringValues(x.Value.ToArray()))
|
||||
),
|
||||
Content = content,
|
||||
FormattedContent = await formatter.ParseAsync(content, contentType)
|
||||
};
|
||||
|
|
@ -123,10 +150,13 @@ namespace Elsa.Activities.Http.Activities
|
|||
private IContentFormatter SelectContentFormatter(string contentType)
|
||||
{
|
||||
var formatters = contentFormatters.OrderByDescending(x => x.Priority).ToList();
|
||||
return formatters.FirstOrDefault(x => x.SupportedContentTypes.Contains(contentType, StringComparer.OrdinalIgnoreCase)) ?? formatters.Last();
|
||||
return formatters.FirstOrDefault(
|
||||
x => x.SupportedContentTypes.Contains(contentType, StringComparer.OrdinalIgnoreCase)
|
||||
) ?? formatters.Last();
|
||||
}
|
||||
|
||||
private async Task<HttpRequestMessage> CreateRequestAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
private async Task<HttpRequestMessage> CreateRequestAsync(WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var methodSupportsBody = GetMethodSupportsBody(Method);
|
||||
var uri = await expressionEvaluator.EvaluateAsync(Url, workflowContext, cancellationToken);
|
||||
|
|
@ -135,8 +165,12 @@ namespace Elsa.Activities.Http.Activities
|
|||
|
||||
if (methodSupportsBody)
|
||||
{
|
||||
var body = await expressionEvaluator.EvaluateAsync(Body, workflowContext, cancellationToken);
|
||||
var contentType = await expressionEvaluator.EvaluateAsync(ContentType, workflowContext, cancellationToken);
|
||||
var body = await expressionEvaluator.EvaluateAsync(Content, workflowContext, cancellationToken);
|
||||
var contentType = await expressionEvaluator.EvaluateAsync(
|
||||
ContentType,
|
||||
workflowContext,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(body))
|
||||
{
|
||||
|
|
@ -152,9 +186,14 @@ namespace Elsa.Activities.Http.Activities
|
|||
return request;
|
||||
}
|
||||
|
||||
private async Task<IHeaderDictionary> ParseRequestHeadersAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
private async Task<IHeaderDictionary> ParseRequestHeadersAsync(WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var headersText = await expressionEvaluator.EvaluateAsync(RequestHeaders, workflowContext, cancellationToken);
|
||||
var headersText = await expressionEvaluator.EvaluateAsync(
|
||||
RequestHeaders,
|
||||
workflowContext,
|
||||
cancellationToken
|
||||
);
|
||||
var headers = new HeaderDictionary();
|
||||
|
||||
if (headersText != null)
|
||||
|
|
@ -167,7 +206,11 @@ namespace Elsa.Activities.Http.Activities
|
|||
foreach (var header in headersQuery)
|
||||
{
|
||||
var headerValueExpression = new WorkflowExpression<string>(RequestHeaders.Syntax, header.Value);
|
||||
var headerValue = await expressionEvaluator.EvaluateAsync(headerValueExpression, workflowContext, cancellationToken);
|
||||
var headerValue = await expressionEvaluator.EvaluateAsync(
|
||||
headerValueExpression,
|
||||
workflowContext,
|
||||
cancellationToken
|
||||
);
|
||||
headers.Add(header.Key, headerValue);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,27 +7,39 @@ using System.Threading.Tasks;
|
|||
using Elsa.Activities.Http.Extensions;
|
||||
using Elsa.Activities.Http.Models;
|
||||
using Elsa.Activities.Http.Services;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Elsa.WorkflowDesigner.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Activities.Http.Activities
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "HTTP",
|
||||
DisplayName = "Receive HTTP Request",
|
||||
Description = "Receive an incoming HTTP request."
|
||||
)]
|
||||
[ActivityDefinitionDesigner(
|
||||
Description =
|
||||
"x => !!x.state.path ? `Handle <strong>${ x.state.method } ${ x.state.path }</strong>.` : x.definition.description",
|
||||
Outcomes = new[] { OutcomeNames.Done }
|
||||
)]
|
||||
public class HttpRequestEvent : Activity
|
||||
{
|
||||
public static Uri GetPath(JObject state)
|
||||
{
|
||||
return state.GetState<Uri>(nameof(Path));
|
||||
}
|
||||
|
||||
|
||||
public static string GetMethod(JObject state)
|
||||
{
|
||||
return state.GetState<string>(nameof(Method));
|
||||
}
|
||||
|
||||
|
||||
private readonly IHttpContextAccessor httpContextAccessor;
|
||||
private readonly IEnumerable<IContentFormatter> contentFormatters;
|
||||
|
||||
|
|
@ -42,9 +54,7 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// The path that triggers this activity.
|
||||
/// </summary>
|
||||
[Display(Description = "The relative path that triggers this activity.")]
|
||||
[Required]
|
||||
[UIHint("RelativePath")]
|
||||
[ActivityProperty(Hint = "The relative path that triggers this activity.")]
|
||||
public Uri Path
|
||||
{
|
||||
get => GetState<Uri>();
|
||||
|
|
@ -54,10 +64,13 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// The HTTP method that triggers this activity.
|
||||
/// </summary>
|
||||
[Display(Description = "The HTTP method that triggers this activity.")]
|
||||
[Required]
|
||||
[UIHint("Dropdown")]
|
||||
public string Method {
|
||||
[ActivityProperty(
|
||||
Type = ActivityPropertyTypes.Select,
|
||||
Hint = "The HTTP method that triggers this activity."
|
||||
)]
|
||||
[SelectOptions("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD")]
|
||||
public string Method
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
|
@ -66,7 +79,10 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// A value indicating whether the HTTP request content body should be read and stored as part of the HTTP request model.
|
||||
/// The stored format depends on the content-type header.
|
||||
/// </summary>
|
||||
[Display(Description = "A value indicating whether the HTTP request content body should be read and stored as part of the HTTP request model. The stored format depends on the content-type header.")]
|
||||
[ActivityProperty(
|
||||
Hint =
|
||||
"A value indicating whether the HTTP request content body should be read and stored as part of the HTTP request model. The stored format depends on the content-type header."
|
||||
)]
|
||||
public bool ReadContent
|
||||
{
|
||||
get => GetState<bool>();
|
||||
|
|
@ -78,7 +94,8 @@ namespace Elsa.Activities.Http.Activities
|
|||
return Halt(true);
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnResumeAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
protected override async Task<ActivityExecutionResult> OnResumeAsync(WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var request = httpContextAccessor.HttpContext.Request;
|
||||
var model = new HttpRequestModel
|
||||
|
|
@ -93,7 +110,10 @@ namespace Elsa.Activities.Http.Activities
|
|||
{
|
||||
if (request.HasFormContentType)
|
||||
{
|
||||
model.Form = (await request.ReadFormAsync(cancellationToken)).ToDictionary(x => x.Key, x => new StringValuesModel(x.Value));
|
||||
model.Form = (await request.ReadFormAsync(cancellationToken)).ToDictionary(
|
||||
x => x.Key,
|
||||
x => new StringValuesModel(x.Value)
|
||||
);
|
||||
}
|
||||
|
||||
var parser = SelectContentParser(request.ContentType);
|
||||
|
|
@ -111,7 +131,9 @@ namespace Elsa.Activities.Http.Activities
|
|||
private IContentFormatter SelectContentParser(string contentType)
|
||||
{
|
||||
var formatters = contentFormatters.OrderByDescending(x => x.Priority).ToList();
|
||||
return formatters.FirstOrDefault(x => x.SupportedContentTypes.Contains(contentType, StringComparer.OrdinalIgnoreCase)) ?? formatters.Last();
|
||||
return formatters.FirstOrDefault(
|
||||
x => x.SupportedContentTypes.Contains(contentType, StringComparer.OrdinalIgnoreCase)
|
||||
) ?? formatters.Last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,73 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Elsa.WorkflowDesigner.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Activities.Http.Activities
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "HTTP",
|
||||
DisplayName = "Send HTTP Response",
|
||||
Description = "Send an HTTP response."
|
||||
)]
|
||||
[ActivityDefinitionDesigner(
|
||||
Description =
|
||||
"x => !!x.state.statusCode ? `Send an HTTP <strong>${ x.state.statusCode }</strong><br/><br/> ${ x.state.contentType }</strong><br/>${ !!x.state.content ? x.state.content.expression ? x.state.content.expression.substr(0,100) + '...' : '' : '' }` : x.definition.description",
|
||||
Outcomes = new[] { OutcomeNames.Done }
|
||||
)]
|
||||
public class HttpResponseAction : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
private readonly IHttpContextAccessor httpContextAccessor;
|
||||
|
||||
public HttpResponseAction(IWorkflowExpressionEvaluator expressionEvaluator, IHttpContextAccessor httpContextAccessor)
|
||||
public static IEnumerable<SelectItem> GetStatusCodes()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new SelectItem
|
||||
{
|
||||
Label = "2xx",
|
||||
Options = new object[] { 200, 201, 202, 203, 204 }
|
||||
},
|
||||
new SelectItem
|
||||
{
|
||||
Label = "3xx",
|
||||
Options = new object[] { 301, 302, 304, 307, 308 }
|
||||
},
|
||||
new SelectItem
|
||||
{
|
||||
Label = "4xx",
|
||||
Options = new object[] { 400, 401, 402, 403, 404, 405, 409, 410, 412, 413, 415, 417, 418, 420, 428, 429 }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public HttpResponseAction(IWorkflowExpressionEvaluator expressionEvaluator,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
this.expressionEvaluator = expressionEvaluator;
|
||||
this.httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The HTTP status code to return.
|
||||
/// </summary>
|
||||
[ActivityProperty(
|
||||
Type = ActivityPropertyTypes.Select,
|
||||
Hint = "The HTTP status code to write."
|
||||
)]
|
||||
[SelectOptions(nameof(GetStatusCodes), typeof(HttpResponseAction))]
|
||||
public HttpStatusCode StatusCode
|
||||
{
|
||||
get => GetState(() => HttpStatusCode.OK);
|
||||
|
|
@ -36,6 +77,8 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// The content to send along with the response
|
||||
/// </summary>
|
||||
[ActivityProperty(Hint = "The HTTP content to write.")]
|
||||
[ExpressionOptions(Multiline = true)]
|
||||
public WorkflowExpression<string> Content
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
|
|
@ -45,29 +88,40 @@ namespace Elsa.Activities.Http.Activities
|
|||
/// <summary>
|
||||
/// The Content-Type header to send along with the response.
|
||||
/// </summary>
|
||||
[ActivityProperty(
|
||||
Type = ActivityPropertyTypes.Select,
|
||||
Hint = "The HTTP content type header to write."
|
||||
)]
|
||||
[SelectOptions("text/plain", "text/html", "application/json", "application/xml")]
|
||||
public string ContentType
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The headers to send along with the response. One 'header: value' pair per line.
|
||||
/// </summary>
|
||||
[ActivityProperty(Hint = "The headers to send along with the response. One 'header: value' pair per line.")]
|
||||
public WorkflowExpression<string> ResponseHeaders
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = httpContextAccessor.HttpContext.Response;
|
||||
|
||||
response.StatusCode = (int) StatusCode;
|
||||
response.ContentType = ContentType;
|
||||
|
||||
var headersText = await expressionEvaluator.EvaluateAsync(ResponseHeaders, workflowContext, cancellationToken);
|
||||
var headersText = await expressionEvaluator.EvaluateAsync(
|
||||
ResponseHeaders,
|
||||
workflowContext,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
if (headersText != null)
|
||||
{
|
||||
|
|
@ -79,7 +133,11 @@ namespace Elsa.Activities.Http.Activities
|
|||
foreach (var header in headersQuery)
|
||||
{
|
||||
var headerValueExpression = new WorkflowExpression<string>(ResponseHeaders.Syntax, header.Value);
|
||||
response.Headers[header.Key] = await expressionEvaluator.EvaluateAsync(headerValueExpression, workflowContext, cancellationToken);
|
||||
response.Headers[header.Key] = await expressionEvaluator.EvaluateAsync(
|
||||
headerValueExpression,
|
||||
workflowContext,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
<ProjectReference Include="..\..\dashboard\Elsa.WorkflowDesigner\Elsa.WorkflowDesigner.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
@ -9,6 +10,11 @@ using Newtonsoft.Json.Linq;
|
|||
|
||||
namespace Elsa.Activities.MassTransit.Activities
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "MassTransit",
|
||||
DisplayName = "Receive MassTransit Message",
|
||||
Description = "Receive a message via MassTransit."
|
||||
)]
|
||||
public class ReceiveMassTransitMessage : Activity
|
||||
{
|
||||
public static Type GetMessageType(JObject state)
|
||||
|
|
@ -16,7 +22,8 @@ namespace Elsa.Activities.MassTransit.Activities
|
|||
var typeName = state.GetState<string>(nameof(MessageType));
|
||||
return string.IsNullOrWhiteSpace(typeName) ? null : System.Type.GetType(typeName);
|
||||
}
|
||||
|
||||
|
||||
[ActivityProperty(Hint = "The assembly-qualified type name of the message to receive.")]
|
||||
public Type MessageType
|
||||
{
|
||||
get => GetMessageType(State);
|
||||
|
|
@ -27,7 +34,7 @@ namespace Elsa.Activities.MassTransit.Activities
|
|||
{
|
||||
var message = context.Workflow.Input["message"];
|
||||
var messageType = MessageType;
|
||||
|
||||
|
||||
return message != null && messageType != null && message.GetType() == messageType;
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +43,8 @@ namespace Elsa.Activities.MassTransit.Activities
|
|||
return Halt(true);
|
||||
}
|
||||
|
||||
protected override Task<ActivityExecutionResult> OnResumeAsync(WorkflowExecutionContext context, CancellationToken cancellationToken)
|
||||
protected override Task<ActivityExecutionResult> OnResumeAsync(WorkflowExecutionContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var message = context.Workflow.Input["message"];
|
||||
context.SetLastResult(message);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
@ -9,6 +10,11 @@ using MassTransit;
|
|||
|
||||
namespace Elsa.Activities.MassTransit.Activities
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "MassTransit",
|
||||
DisplayName = "Send MassTransit Message",
|
||||
Description = "Send a message via MassTransit."
|
||||
)]
|
||||
public class SendMassTransitMessage : Activity
|
||||
{
|
||||
private readonly ISendEndpointProvider sender;
|
||||
|
|
@ -20,6 +26,7 @@ namespace Elsa.Activities.MassTransit.Activities
|
|||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The assembly-qualified type name of the message to send.")]
|
||||
public Type MessageType
|
||||
{
|
||||
get
|
||||
|
|
@ -30,6 +37,7 @@ namespace Elsa.Activities.MassTransit.Activities
|
|||
set => SetState(value.AssemblyQualifiedName);
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the message to send.")]
|
||||
public WorkflowExpression Message
|
||||
{
|
||||
get => GetState<WorkflowExpression>();
|
||||
|
|
@ -41,7 +49,8 @@ namespace Elsa.Activities.MassTransit.Activities
|
|||
return MessageType != null;
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext context, CancellationToken cancellationToken)
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var message = await evaluator.EvaluateAsync(Message, MessageType, context, cancellationToken);
|
||||
await sender.Send(message, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -10,6 +11,10 @@ using NodaTime;
|
|||
|
||||
namespace Elsa.Activities.Timers.Activities
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "Timers",
|
||||
Description = "Triggers periodically based on a specified CRON expression."
|
||||
)]
|
||||
public class CronEvent : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -21,6 +26,7 @@ namespace Elsa.Activities.Timers.Activities
|
|||
this.clock = clock;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "Specify a CRON expression. See https://crontab.guru/ for help.")]
|
||||
public WorkflowExpression<string> CronExpression
|
||||
{
|
||||
get => GetState(() => new LiteralExpression("* * * * *"));
|
||||
|
|
@ -39,16 +45,22 @@ namespace Elsa.Activities.Timers.Activities
|
|||
return Halt();
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnResumeAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
protected override async Task<ActivityExecutionResult> OnResumeAsync(WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var isExpired = await IsExpiredAsync(workflowContext, cancellationToken);
|
||||
|
||||
return isExpired ? Done() : Halt();
|
||||
}
|
||||
|
||||
private async Task<bool> IsExpiredAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
private async Task<bool> IsExpiredAsync(WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var cronExpression = await expressionEvaluator.EvaluateAsync(CronExpression, workflowContext, cancellationToken);
|
||||
var cronExpression = await expressionEvaluator.EvaluateAsync(
|
||||
CronExpression,
|
||||
workflowContext,
|
||||
cancellationToken
|
||||
);
|
||||
var schedule = CrontabSchedule.Parse(cronExpression);
|
||||
var now = clock.GetCurrentInstant();
|
||||
var startTime = StartTime ?? now;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -12,6 +13,10 @@ namespace Elsa.Activities.Timers.Activities
|
|||
/// <summary>
|
||||
/// Triggers at a specific instant in the future.
|
||||
/// </summary>
|
||||
[ActivityDefinition(
|
||||
Category = "Timers",
|
||||
Description = "Triggers at a specified moment in time."
|
||||
)]
|
||||
public class InstantEvent : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -26,6 +31,7 @@ namespace Elsa.Activities.Timers.Activities
|
|||
/// <summary>
|
||||
/// An expression that evaluates to an <see cref="Instant"/>
|
||||
/// </summary>
|
||||
[ActivityProperty(Hint = "An expression that evaluates to a NodaTime Instant")]
|
||||
public WorkflowExpression<Instant> InstantExpression
|
||||
{
|
||||
get => GetState<WorkflowExpression<Instant>>();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Workflows;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -11,6 +12,10 @@ using NodaTime;
|
|||
|
||||
namespace Elsa.Activities.Timers.Activities
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "Timers",
|
||||
Description = "Triggers at a specified interval."
|
||||
)]
|
||||
public class TimerEvent : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -22,6 +27,7 @@ namespace Elsa.Activities.Timers.Activities
|
|||
this.clock = clock;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to a TimeSpan value")]
|
||||
public WorkflowExpression<TimeSpan> TimeoutExpression
|
||||
{
|
||||
get => GetState(() => new LiteralExpression<TimeSpan>("00:01:00"));
|
||||
|
|
|
|||
|
|
@ -1,16 +1,26 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Elsa.WorkflowDesigner.Models;
|
||||
|
||||
namespace Elsa.Activities.UserTask.Activities
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores a set of possible user actions and halts the workflow until one of the actions has been performed.
|
||||
/// </summary>
|
||||
[ActivityDefinition(
|
||||
Category = "User Tasks",
|
||||
Description = "Triggers when a user action is received."
|
||||
)]
|
||||
public class UserTask : Activity
|
||||
{
|
||||
[ActivityProperty(
|
||||
Type = ActivityPropertyTypes.List,
|
||||
Hint = "Enter a comma-separated list of available actions"
|
||||
)]
|
||||
public string[] Actions
|
||||
{
|
||||
get => GetState(() => new string[0]);
|
||||
|
|
@ -35,6 +45,7 @@ namespace Elsa.Activities.UserTask.Activities
|
|||
return Outcome(userAction);
|
||||
}
|
||||
|
||||
private string GetUserAction(WorkflowExecutionContext context) => (string) context.Workflow.Input.GetVariable("UserAction");
|
||||
private string GetUserAction(WorkflowExecutionContext context) =>
|
||||
(string) context.Workflow.Input.GetVariable("UserAction");
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
<ProjectReference Include="..\..\dashboard\Elsa.WorkflowDesigner\Elsa.WorkflowDesigner.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace Elsa.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ActivityDefinitionAttribute : Attribute
|
||||
{
|
||||
public string Type { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Category { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Elsa.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ActivityDefinitionDesignerAttribute : Attribute
|
||||
{
|
||||
public string Description { get; set; }
|
||||
public object Outcomes { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace Elsa.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ActivityPropertyAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Label { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Hint { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace Elsa.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public abstract class ActivityPropertyOptionsAttribute : Attribute
|
||||
{
|
||||
public abstract object GetOptions();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
namespace Elsa.Attributes
|
||||
{
|
||||
public class ExpressionOptionsAttribute : ActivityPropertyOptionsAttribute
|
||||
{
|
||||
public bool Multiline { get; set; }
|
||||
|
||||
public override object GetOptions()
|
||||
{
|
||||
return new
|
||||
{
|
||||
Multiline
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Elsa.Attributes
|
||||
{
|
||||
public class SelectOptionsAttribute : ActivityPropertyOptionsAttribute
|
||||
{
|
||||
public SelectOptionsAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
public SelectOptionsAttribute(params string[] items)
|
||||
{
|
||||
Items = items.Cast<object>().ToArray();
|
||||
}
|
||||
|
||||
public SelectOptionsAttribute(string optionsProviderMethod, Type providerType)
|
||||
{
|
||||
OptionsProviderMethod = optionsProviderMethod;
|
||||
ProviderType = providerType;
|
||||
}
|
||||
|
||||
public object[] Items { get; }
|
||||
public string OptionsProviderMethod { get; }
|
||||
public Type ProviderType { get; }
|
||||
|
||||
public override object GetOptions()
|
||||
{
|
||||
if (Items != null)
|
||||
return new
|
||||
{
|
||||
Items
|
||||
};
|
||||
|
||||
|
||||
var selectItems = GetItemsFromProvider();
|
||||
return new
|
||||
{
|
||||
Items = selectItems.Select(ToObject).ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<object> GetItemsFromProvider()
|
||||
{
|
||||
var method = ProviderType.GetMethod(OptionsProviderMethod, BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
return (IEnumerable<object>) method.Invoke(null, null);
|
||||
}
|
||||
|
||||
private object ToObject(object item)
|
||||
{
|
||||
if ((item is SelectItem selectItem) && selectItem.Options != null && selectItem.Label == null)
|
||||
return selectItem.Options;
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public class SelectItem
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public object[] Options { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -9,6 +10,7 @@ using Elsa.Services.Models;
|
|||
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
[ActivityDefinition(Category = "Control Flow", Description = "Iterate over a collection.")]
|
||||
public class ForEach : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -18,12 +20,14 @@ namespace Elsa.Activities.ControlFlow
|
|||
this.expressionEvaluator = expressionEvaluator;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "Enter an expression that evaluates to an array of items to iterate over.")]
|
||||
public WorkflowExpression<IList<object>> CollectionExpression
|
||||
{
|
||||
get => GetState(() => new JavaScriptExpression<IList<object>>("[]"));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
|
||||
[ActivityProperty(Hint = "Enter a name for the iterator variable.")]
|
||||
public string IteratorName
|
||||
{
|
||||
get => GetState(() => "CurrentValue");
|
||||
|
|
@ -36,7 +40,9 @@ namespace Elsa.Activities.ControlFlow
|
|||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext context, CancellationToken cancellationToken)
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
|
||||
WorkflowExecutionContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var collection = await expressionEvaluator.EvaluateAsync(CollectionExpression, context, cancellationToken);
|
||||
var index = CurrentIndex;
|
||||
|
|
@ -55,7 +61,7 @@ namespace Elsa.Activities.ControlFlow
|
|||
{
|
||||
context.BeginScope();
|
||||
}
|
||||
|
||||
|
||||
context.CurrentScope.SetVariable(IteratorName, value);
|
||||
|
||||
return Outcome(OutcomeNames.Iterate);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,24 @@
|
|||
using System.Collections.Generic;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
[ActivityDefinition(Category = "Control Flow", Description = "Fork workflow execution into multiple branches.")]
|
||||
[ActivityDefinitionDesigner(Outcomes = "x => x.state.branches")]
|
||||
public class Fork : Activity
|
||||
{
|
||||
[ActivityProperty(
|
||||
Hint = "Enter one or more names representing branches, separated with a comma. Example: Branch 1, Branch 2"
|
||||
)]
|
||||
public IList<string> Branches
|
||||
{
|
||||
get => GetState(() => new List<string>());
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
|
||||
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext workflowContext)
|
||||
{
|
||||
return Outcomes(Branches);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -8,6 +9,16 @@ using Elsa.Services.Models;
|
|||
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
[ActivityDefinition(
|
||||
DisplayName = "If/Else",
|
||||
Category = "Control Flow",
|
||||
Description = "Evaluate a Boolean expression and continue execution depending on the result."
|
||||
)]
|
||||
[ActivityDefinitionDesigner(
|
||||
Description =
|
||||
"x => !!x.state.expression ? `Evaluate <strong>${ x.state.expression.expression }</strong> and continue execution depending on the result.` : x.definition.description",
|
||||
Outcomes = new[] { OutcomeNames.True, OutcomeNames.False }
|
||||
)]
|
||||
public class IfElse : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -17,16 +28,22 @@ namespace Elsa.Activities.ControlFlow
|
|||
this.expressionEvaluator = expressionEvaluator;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The expression to evaluate. The evaluated value will be used to switch on.")]
|
||||
public WorkflowExpression<bool> ConditionExpression
|
||||
{
|
||||
get => GetState(() => new JavaScriptExpression<bool>("true"));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await expressionEvaluator.EvaluateAsync(ConditionExpression, workflowContext, cancellationToken);
|
||||
return Outcome(result ? OutcomeNames.True: OutcomeNames.False);
|
||||
var result = await expressionEvaluator.EvaluateAsync(
|
||||
ConditionExpression,
|
||||
workflowContext,
|
||||
cancellationToken
|
||||
);
|
||||
return Outcome(result ? OutcomeNames.True : OutcomeNames.False);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Extensions;
|
||||
|
|
@ -9,19 +10,29 @@ using Elsa.Services.Models;
|
|||
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "Control Flow",
|
||||
Description = "Merge workflow execution back into a single branch."
|
||||
)]
|
||||
[ActivityDefinitionDesigner(
|
||||
Description =
|
||||
"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 }
|
||||
)]
|
||||
public class Join : Activity, IWorkflowEventHandler
|
||||
{
|
||||
public Join()
|
||||
{
|
||||
InboundTransitions = new List<string>().AsReadOnly();
|
||||
}
|
||||
|
||||
|
||||
public enum JoinMode
|
||||
{
|
||||
WaitAll,
|
||||
WaitAny
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "Either 'WaitAll' or 'WaitAny'")]
|
||||
public JoinMode Mode
|
||||
{
|
||||
get => GetState(() => JoinMode.WaitAll);
|
||||
|
|
@ -33,7 +44,7 @@ namespace Elsa.Activities.ControlFlow
|
|||
get => GetState<IReadOnlyCollection<string>>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
|
||||
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext workflowContext)
|
||||
{
|
||||
var recordedInboundTransitions = InboundTransitions ?? new List<string>();
|
||||
|
|
@ -50,12 +61,13 @@ namespace Elsa.Activities.ControlFlow
|
|||
done = inboundConnections.Any(x => recordedInboundTransitions.Contains(GetTransitionKey(x)));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (done)
|
||||
{
|
||||
// Remove any inbound blocking activities.
|
||||
var ancestorActivityIds = workflow.GetInboundActivityPath(Id).ToList();
|
||||
var blockingActivities = workflow.BlockingActivities.Where(x => ancestorActivityIds.Contains(x.Id)).ToList();
|
||||
var blockingActivities =
|
||||
workflow.BlockingActivities.Where(x => ancestorActivityIds.Contains(x.Id)).ToList();
|
||||
|
||||
foreach (var blockingActivity in blockingActivities)
|
||||
{
|
||||
|
|
@ -87,7 +99,10 @@ namespace Elsa.Activities.ControlFlow
|
|||
{
|
||||
var joinActivity = (Join) inboundConnection.Target.Activity;
|
||||
var inboundTransitions = joinActivity.InboundTransitions ?? new List<string>();
|
||||
joinActivity.InboundTransitions = inboundTransitions.Union(new[] { GetTransitionKey(inboundConnection) }).Distinct().ToList();
|
||||
joinActivity.InboundTransitions = inboundTransitions
|
||||
.Union(new[] { GetTransitionKey(inboundConnection) })
|
||||
.Distinct()
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,14 +114,18 @@ namespace Elsa.Activities.ControlFlow
|
|||
return $"@{sourceActivityId}_{sourceOutcomeName}";
|
||||
}
|
||||
|
||||
Task IWorkflowEventHandler.ActivityExecutedAsync(WorkflowExecutionContext workflowContext, IActivity activity, CancellationToken cancellationToken)
|
||||
Task IWorkflowEventHandler.ActivityExecutedAsync(WorkflowExecutionContext workflowContext, IActivity activity,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
RecordInboundTransitions(workflowContext, activity);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
Task IWorkflowEventHandler.InvokingHaltedActivitiesAsync(WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
Task IWorkflowEventHandler.WorkflowInvokedAsync(WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
Task IWorkflowEventHandler.InvokingHaltedActivitiesAsync(WorkflowExecutionContext workflowExecutionContext,
|
||||
CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
Task IWorkflowEventHandler.WorkflowInvokedAsync(WorkflowExecutionContext workflowExecutionContext,
|
||||
CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -9,29 +10,41 @@ using Elsa.Services.Models;
|
|||
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "Control Flow",
|
||||
Description = "Switch execution based on a given expression."
|
||||
)]
|
||||
[ActivityDefinitionDesigner(
|
||||
Description =
|
||||
"x => !!x.state.expression ? `Switch execution based on <strong>${ x.state.expression.expression }</strong>.` : x.definition.description",
|
||||
Outcomes = "x => x.state.cases.map(c => c.toString())"
|
||||
)]
|
||||
public class Switch : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
||||
|
||||
public Switch(IWorkflowExpressionEvaluator expressionEvaluator)
|
||||
{
|
||||
this.expressionEvaluator = expressionEvaluator;
|
||||
Cases = new List<string>();
|
||||
}
|
||||
|
||||
|
||||
[ActivityProperty(Hint = "The expression to evaluate. The evaluated value will be used to switch on.")]
|
||||
public WorkflowExpression<string> Expression
|
||||
{
|
||||
get => GetState<WorkflowExpression<string>>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "A comma-separated list of possible outcomes of the expression.")]
|
||||
public IReadOnlyCollection<string> Cases
|
||||
{
|
||||
get => GetState<IReadOnlyCollection<string>>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await expressionEvaluator.EvaluateAsync(Expression, workflowContext, cancellationToken);
|
||||
return Outcome(result);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,23 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Activities.Primitives
|
||||
{
|
||||
[ActivityDefinition(
|
||||
DisplayName = "Set Variable",
|
||||
Description = "Set variable on the workflow.",
|
||||
Category = "Primitives"
|
||||
)]
|
||||
[ActivityDefinitionDesigner(
|
||||
Description =
|
||||
"x => !!x.state.variableName ? `${x.state.expression.syntax}: <strong>${x.state.variableName}</strong> = <strong>${x.state.expression.expression}</strong>` : x.definition.description",
|
||||
Outcomes = new[] { OutcomeNames.Done }
|
||||
)]
|
||||
public class SetVariable : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -17,21 +27,30 @@ namespace Elsa.Activities.Primitives
|
|||
this.expressionEvaluator = expressionEvaluator;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "The name of the variable to store the value into.")]
|
||||
public string VariableName
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the value to store in the variable.")]
|
||||
public WorkflowExpression ValueExpression
|
||||
{
|
||||
get => GetState<WorkflowExpression>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
|
||||
WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var value = await expressionEvaluator.EvaluateAsync(ValueExpression, ValueExpression.Type, workflowContext, cancellationToken);
|
||||
var value = await expressionEvaluator.EvaluateAsync(
|
||||
ValueExpression,
|
||||
ValueExpression.Type,
|
||||
workflowContext,
|
||||
cancellationToken
|
||||
);
|
||||
workflowContext.CurrentScope.SetVariable(VariableName, value);
|
||||
return Done();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -11,6 +12,10 @@ namespace Elsa.Activities.Workflows
|
|||
/// <summary>
|
||||
/// Sets the CorrelationId of the workflow to a given value.
|
||||
/// </summary>
|
||||
[ActivityDefinition(
|
||||
Category = "Workflows",
|
||||
Description = "Set the CorrelationId of the workflow to a given value."
|
||||
)]
|
||||
public class Correlate : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -20,15 +25,18 @@ namespace Elsa.Activities.Workflows
|
|||
this.expressionEvaluator = expressionEvaluator;
|
||||
}
|
||||
|
||||
public WorkflowExpression<string> Expression
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the value to store as the correlation ID.")]
|
||||
public WorkflowExpression<string> ValueExpression
|
||||
{
|
||||
get => GetState<WorkflowExpression<string>>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(
|
||||
WorkflowExecutionContext workflowContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var value = await expressionEvaluator.EvaluateAsync(Expression, workflowContext, cancellationToken);
|
||||
var value = await expressionEvaluator.EvaluateAsync(ValueExpression, workflowContext, cancellationToken);
|
||||
workflowContext.Workflow.CorrelationId = value;
|
||||
return Done();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Models;
|
||||
|
|
@ -9,6 +10,10 @@ using Elsa.Services.Models;
|
|||
|
||||
namespace Elsa.Activities.Workflows
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "Workflows",
|
||||
Description = "Removes any blocking activities and sets the status of the workflow to Finished."
|
||||
)]
|
||||
public class Finish : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -18,6 +23,7 @@ namespace Elsa.Activities.Workflows
|
|||
this.expressionEvaluator = expressionEvaluator;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to a dictionary to be set as the workflow's output.'")]
|
||||
public WorkflowExpression<Variables> WorkflowOutput
|
||||
{
|
||||
get => GetState(() => new JavaScriptExpression<Variables>("({})"));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
|
|
@ -11,6 +12,10 @@ namespace Elsa.Activities.Workflows
|
|||
/// <summary>
|
||||
/// Halts workflow execution until the specified signal is received.
|
||||
/// </summary>
|
||||
[ActivityDefinition(
|
||||
Category = "Workflows",
|
||||
Description = "Halt workflow execution until the specified signal is received."
|
||||
)]
|
||||
public class Signaled : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -20,6 +25,7 @@ namespace Elsa.Activities.Workflows
|
|||
this.expressionEvaluator = expressionEvaluator;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the name of the signal to wait for.")]
|
||||
public WorkflowExpression<string> Signal
|
||||
{
|
||||
get => GetState<WorkflowExpression<string>>();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
using Elsa.Results;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Activities.Workflows
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "Workflows",
|
||||
Description = "Useful when you need to invoke the workflow manually."
|
||||
)]
|
||||
public class Start : Activity
|
||||
{
|
||||
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext context)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Models;
|
||||
|
|
@ -12,6 +13,10 @@ namespace Elsa.Activities.Workflows
|
|||
/// <summary>
|
||||
/// Triggers the specified signal.
|
||||
/// </summary>
|
||||
[ActivityDefinition(
|
||||
Category = "Workflows",
|
||||
Description = "Trigger the specified signal."
|
||||
)]
|
||||
public class Trigger : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
|
|
@ -23,18 +28,23 @@ namespace Elsa.Activities.Workflows
|
|||
this.workflowInvoker = workflowInvoker;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the name of the signal to trigger.")]
|
||||
public WorkflowExpression<string> Signal
|
||||
{
|
||||
get => GetState<WorkflowExpression<string>>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityProperty(
|
||||
Hint = "An expression that evaluates to a dictionary to be provided as input when signaling."
|
||||
)]
|
||||
public WorkflowExpression<Variables> Input
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<Variables>(JavaScriptEvaluator.SyntaxName, "{}"));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the correlation ID to use when signaling.")]
|
||||
public WorkflowExpression<string> CorrelationId
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression<string>(LiteralEvaluator.SyntaxName, ""));
|
||||
|
|
@ -57,7 +67,7 @@ namespace Elsa.Activities.Workflows
|
|||
correlationId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
|
||||
return Done();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Models;
|
||||
|
|
@ -10,6 +11,10 @@ using Elsa.Services.Models;
|
|||
|
||||
namespace Elsa.Activities.Workflows
|
||||
{
|
||||
[ActivityDefinition(
|
||||
Category = "Workflows",
|
||||
Description = "Trigger all workflows that start with or are blocked on the specified activity type."
|
||||
)]
|
||||
public class TriggerWorkflow : Activity
|
||||
{
|
||||
private readonly IWorkflowInvoker workflowInvoker;
|
||||
|
|
@ -21,18 +26,23 @@ namespace Elsa.Activities.Workflows
|
|||
this.expressionEvaluator = expressionEvaluator;
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the activity type to use when triggering workflows.")]
|
||||
public WorkflowExpression<string> ActivityType
|
||||
{
|
||||
get => GetState(() => new LiteralExpression(""));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityProperty(
|
||||
Hint = "An expression that evaluates to a dictionary to be provided as input when triggering workflows."
|
||||
)]
|
||||
public WorkflowExpression<Variables> Input
|
||||
{
|
||||
get => GetState(() => new JavaScriptExpression<Variables>("{}"));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityProperty(Hint = "An expression that evaluates to the correlation ID to use when triggering workflows.")]
|
||||
public WorkflowExpression<string> CorrelationId
|
||||
{
|
||||
get => GetState(() => new LiteralExpression(Guid.NewGuid().ToString()));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
using Elsa.Attributes;
|
||||
using Elsa.Services;
|
||||
|
||||
namespace Elsa.Dashboard.Web.Activities
|
||||
{
|
||||
public class SampleActivity : Activity
|
||||
{
|
||||
[ActivityProperty]
|
||||
public string FirstName
|
||||
{
|
||||
get => GetState<string>();
|
||||
set => SetState(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,12 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
|
||||
<ProjectReference Include="..\..\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj" />
|
||||
<ProjectReference Include="..\..\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
|
||||
<ProjectReference Include="..\..\activities\Elsa.Activities.MassTransit\Elsa.Activities.MassTransit.csproj" />
|
||||
<ProjectReference Include="..\..\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj" />
|
||||
<ProjectReference Include="..\..\activities\Elsa.Activities.UserTask\Elsa.Activities.UserTask.csproj" />
|
||||
<ProjectReference Include="..\..\persistence\Elsa.Persistence.EntityFrameworkCore\Elsa.Persistence.EntityFrameworkCore.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Dashboard\Elsa.Dashboard.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.IO;
|
||||
using Elsa.Dashboard.Extensions;
|
||||
using Elsa.Persistence.EntityFrameworkCore.Extensions;
|
||||
using Elsa.Services.Models;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
|
@ -27,6 +28,8 @@ namespace Elsa.Dashboard.Web
|
|||
services
|
||||
.AddMvc( /*options => options.Conventions.Add(new AddLocalhostFilterConvention())*/)
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest)
|
||||
|
||||
// This is entirely optional and only useful when developing the Elsa.Dashboard project.
|
||||
.AddRazorOptions(
|
||||
options =>
|
||||
{
|
||||
|
|
@ -47,7 +50,19 @@ namespace Elsa.Dashboard.Web
|
|||
)
|
||||
.AddEntityFrameworkCoreWorkflowDefinitionStore()
|
||||
.AddEntityFrameworkCoreWorkflowInstanceStore()
|
||||
.AddElsaDashboard();
|
||||
.AddElsaDashboard(
|
||||
options => options
|
||||
// Add activity definitions from configuration.
|
||||
.Bind(Configuration.GetSection("WorkflowDesigner"))
|
||||
.Configure(
|
||||
configureOptions => configureOptions.ActivityDefinitions
|
||||
// Add all activities from all referenced assemblies.
|
||||
.Discover(
|
||||
selector => selector.FromApplicationDependencies()
|
||||
.AddClasses(x => x.AssignableTo<IActivity>())
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,31 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"Sqlite": "Data Source=c:\\data\\elsa.db;Cache=Shared"
|
||||
},
|
||||
"WorkflowDesigner": {
|
||||
"ActivityDefinitions": [
|
||||
{
|
||||
"Type": "MyCustomActivity2",
|
||||
"DisplayName": "My Custom Activity 2",
|
||||
"Category": "Custom",
|
||||
"Description": "Demonstrates adding custom activities to the designer",
|
||||
"Properties": [
|
||||
{
|
||||
"Name": "Property1",
|
||||
"Label": "Property 1",
|
||||
"Type": "expression",
|
||||
"Hint": "Specify any value you like.",
|
||||
"Options": {
|
||||
"Multiline": false
|
||||
},
|
||||
"Designer": {
|
||||
"Outcomes": [
|
||||
"Done"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
|||
using Elsa.Dashboard.Areas.Elsa.ViewModels;
|
||||
using Elsa.Dashboard.Extensions;
|
||||
using Elsa.Dashboard.Models;
|
||||
using Elsa.Dashboard.Options;
|
||||
using Elsa.Dashboard.Services;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Models;
|
||||
|
|
@ -12,6 +13,9 @@ using Elsa.Serialization;
|
|||
using Elsa.Serialization.Formatters;
|
||||
using Elsa.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Elsa.Dashboard.Areas.Elsa.Controllers
|
||||
{
|
||||
|
|
@ -23,6 +27,7 @@ namespace Elsa.Dashboard.Areas.Elsa.Controllers
|
|||
private readonly IWorkflowInstanceStore workflowInstanceStore;
|
||||
private readonly IWorkflowPublisher publisher;
|
||||
private readonly IWorkflowSerializer serializer;
|
||||
private readonly IOptions<ElsaDashboardOptions> options;
|
||||
private readonly IIdGenerator idGenerator;
|
||||
private readonly INotifier notifier;
|
||||
|
||||
|
|
@ -31,6 +36,7 @@ namespace Elsa.Dashboard.Areas.Elsa.Controllers
|
|||
IWorkflowInstanceStore workflowInstanceStore,
|
||||
IWorkflowPublisher publisher,
|
||||
IWorkflowSerializer serializer,
|
||||
IOptions<ElsaDashboardOptions> options,
|
||||
IIdGenerator idGenerator,
|
||||
INotifier notifier)
|
||||
{
|
||||
|
|
@ -38,6 +44,7 @@ namespace Elsa.Dashboard.Areas.Elsa.Controllers
|
|||
this.workflowDefinitionStore = workflowDefinitionStore;
|
||||
this.workflowInstanceStore = workflowInstanceStore;
|
||||
this.serializer = serializer;
|
||||
this.options = options;
|
||||
this.idGenerator = idGenerator;
|
||||
this.notifier = notifier;
|
||||
}
|
||||
|
|
@ -73,7 +80,8 @@ namespace Elsa.Dashboard.Areas.Elsa.Controllers
|
|||
var model = new WorkflowDefinitionEditModel
|
||||
{
|
||||
Name = workflow.Name,
|
||||
Json = serializer.Serialize(workflow, JsonTokenFormatter.FormatName)
|
||||
Json = serializer.Serialize(workflow, JsonTokenFormatter.FormatName),
|
||||
ActivityDefinitions = options.Value.ActivityDefinitions.ToArray()
|
||||
};
|
||||
|
||||
return View(model);
|
||||
|
|
@ -110,7 +118,8 @@ namespace Elsa.Dashboard.Areas.Elsa.Controllers
|
|||
Id = workflow.Id,
|
||||
Name = workflow.Name,
|
||||
Description = workflow.Description,
|
||||
Json = serializer.Serialize(workflow, JsonTokenFormatter.FormatName)
|
||||
Json = serializer.Serialize(workflow, JsonTokenFormatter.FormatName),
|
||||
ActivityDefinitions = options.Value.ActivityDefinitions.ToArray()
|
||||
};
|
||||
|
||||
return View(model);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
using Elsa.WorkflowDesigner.Models;
|
||||
|
||||
namespace Elsa.Dashboard.Areas.Elsa.ViewModels
|
||||
{
|
||||
public class WorkflowDefinitionEditModel
|
||||
|
|
@ -7,5 +9,6 @@ namespace Elsa.Dashboard.Areas.Elsa.ViewModels
|
|||
public string SubmitAction { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public ActivityDefinition[] ActivityDefinitions { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<div class="card-body">
|
||||
<form asp-action="@formAction">
|
||||
<input asp-for="Json" id="workflowData" type="hidden"/>
|
||||
<wf-designer-host id="designerHost" canvas-height="300vh"></wf-designer-host>
|
||||
<vc:workflow-designer activity-definitions="@Model.ActivityDefinitions" />
|
||||
<div class="text-center">
|
||||
<button asp-for="SubmitAction" name="SubmitAction" type="submit" value="draft" class="btn btn-primary mt-4">Save Draft</button>
|
||||
<button asp-for="SubmitAction" name="SubmitAction" type="submit" value="publish" class="btn btn-success mt-4">Publish</button>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<!-- CSS Files -->
|
||||
<link href="~/assets/css/argon-dashboard.css?v=1.1.0" rel="stylesheet"/>
|
||||
<link href="~/assets/css/elsa.css?v=1.1.0" rel="stylesheet"/>
|
||||
<script src='https://unpkg.com/@@elsa-workflows/elsa-workflow-designer@0.0.41/dist/elsa-workflow-designer.js'></script>
|
||||
<script src='https://unpkg.com/@@elsa-workflows/elsa-workflow-designer@0.0.43/dist/elsa-workflow-designer.js'></script>
|
||||
@await RenderSectionAsync("HeadScripts", false)
|
||||
</head>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@
|
|||
@using Elsa.Dashboard.Areas.Elsa.ViewModels
|
||||
@addTagHelper *, GravatarHelper.AspNetCore
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@addTagHelper *, Elsa.WorkflowDesigner
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.2.0" />
|
||||
<PackageReference Include="Scrutor" Version="3.0.2.19" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -26,20 +27,17 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa.Abstractions\Elsa.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
<ProjectReference Include="..\..\core\Elsa.Abstractions\Elsa.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
<ProjectReference Include="..\Elsa.WorkflowDesigner\Elsa.WorkflowDesigner.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Extensions.FileProviders.Physical, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
|
||||
<HintPath>..\..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.fileproviders.physical\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_ContentIncludedByDefault Remove="wwwroot\assets\css\argon-dashboard.css" />
|
||||
<_ContentIncludedByDefault Remove="wwwroot\assets\css\argon-dashboard.css.map" />
|
||||
<_ContentIncludedByDefault Remove="wwwroot\assets\css\argon-dashboard.min.css" />
|
||||
<_ContentIncludedByDefault Remove="wwwroot\assets\css\argon-dashboard.css" />
|
||||
<_ContentIncludedByDefault Remove="wwwroot\assets\css\argon-dashboard.css.map" />
|
||||
<_ContentIncludedByDefault Remove="wwwroot\assets\css\argon-dashboard.min.css" />
|
||||
<_ContentIncludedByDefault Remove="Views\Shared\Components\WorkflowDesigner\Default.cshtml" />
|
||||
<_ContentIncludedByDefault Remove="Views\_ViewImports.cshtml" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using Elsa.Dashboard.Options;
|
||||
using Elsa.Services.Models;
|
||||
using Elsa.WorkflowDesigner;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Scrutor;
|
||||
|
||||
namespace Elsa.Dashboard.Extensions
|
||||
{
|
||||
public static class ActivityDefinitionListExtensions
|
||||
{
|
||||
public static ActivityDefinitionList Add<T>(this ActivityDefinitionList list) where T : IActivity
|
||||
{
|
||||
return list.Add(ActivityDescriber.Describe<T>());
|
||||
}
|
||||
|
||||
public static ActivityDefinitionList Discover(this ActivityDefinitionList list, Action<ITypeSourceSelector> selector)
|
||||
{
|
||||
var typeSourceSelector = new TypeSourceSelector();
|
||||
selector(typeSourceSelector);
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
typeSourceSelector.Populate(serviceCollection, RegistrationStrategy.Replace(ReplacementBehavior.All));
|
||||
|
||||
foreach (var service in serviceCollection)
|
||||
{
|
||||
list.Add(ActivityDescriber.Describe(service.ImplementationType));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.WorkflowDesigner.Models;
|
||||
|
||||
namespace Elsa.Dashboard.Options
|
||||
{
|
||||
public class ActivityDefinitionList : IEnumerable<ActivityDefinition>
|
||||
{
|
||||
public ActivityDefinitionList()
|
||||
{
|
||||
Items = new Dictionary<string, ActivityDefinition>();
|
||||
}
|
||||
|
||||
private IDictionary<string, ActivityDefinition> Items { get; }
|
||||
|
||||
public ActivityDefinitionList Add(ActivityDefinition item)
|
||||
{
|
||||
Items[item.Type] = item;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IEnumerator<ActivityDefinition> GetEnumerator() => Items.Values.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,13 @@ namespace Elsa.Dashboard.Options
|
|||
{
|
||||
public class ElsaDashboardOptions
|
||||
{
|
||||
public ElsaDashboardOptions()
|
||||
{
|
||||
Scripts = new List<string>();
|
||||
ActivityDefinitions = new ActivityDefinitionList();
|
||||
}
|
||||
|
||||
public IList<string> Scripts { get; set; }
|
||||
public ActivityDefinitionList ActivityDefinitions { get; set; }
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 537 B |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.5 KiB |
97
src/dashboard/Elsa.WorkflowDesigner/ActivityDescriber.cs
Normal file
97
src/dashboard/Elsa.WorkflowDesigner/ActivityDescriber.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services.Models;
|
||||
using Elsa.WorkflowDesigner.Models;
|
||||
using Humanizer;
|
||||
|
||||
namespace Elsa.WorkflowDesigner
|
||||
{
|
||||
public static class ActivityDescriber
|
||||
{
|
||||
public static ActivityDefinition Describe<T>() where T : IActivity
|
||||
{
|
||||
return Describe(typeof(T));
|
||||
}
|
||||
|
||||
public static ActivityDefinition Describe(Type activityType)
|
||||
{
|
||||
var activityDefinitionAttribute = activityType.GetCustomAttribute<ActivityDefinitionAttribute>();
|
||||
var activityDesignerAttribute = activityType.GetCustomAttribute<ActivityDefinitionDesignerAttribute>();
|
||||
var typeName = activityDefinitionAttribute?.Type ?? activityType.Name;
|
||||
|
||||
var displayName =
|
||||
activityDefinitionAttribute?.DisplayName ??
|
||||
activityType.Name.Humanize(LetterCasing.Title);
|
||||
|
||||
var description = activityDefinitionAttribute?.Description;
|
||||
var category = activityDefinitionAttribute?.Category ?? "Miscellaneous";
|
||||
var designerDescription = activityDesignerAttribute?.Description;
|
||||
var designerOutcomes = activityDesignerAttribute?.Outcomes ?? new[] { OutcomeNames.Done };
|
||||
var properties = DescribeProperties(activityType);
|
||||
|
||||
return new ActivityDefinition
|
||||
{
|
||||
Type = typeName.Camelize(),
|
||||
DisplayName = displayName,
|
||||
Description = description,
|
||||
Category = category,
|
||||
Properties = properties.ToArray(),
|
||||
Designer = new ActivityDesignerSettings
|
||||
{
|
||||
Description = designerDescription,
|
||||
Outcomes = designerOutcomes
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<ActivityPropertyDescriptor> DescribeProperties(Type activityType)
|
||||
{
|
||||
var properties = activityType.GetProperties();
|
||||
|
||||
foreach (var propertyInfo in properties)
|
||||
{
|
||||
var activityProperty = propertyInfo.GetCustomAttribute<ActivityPropertyAttribute>();
|
||||
|
||||
if (activityProperty == null)
|
||||
yield break;
|
||||
|
||||
yield return new ActivityPropertyDescriptor
|
||||
{
|
||||
Name = (activityProperty.Name ?? propertyInfo.Name).Camelize(),
|
||||
Label = activityProperty.Label ?? propertyInfo.Name.Humanize(LetterCasing.Title),
|
||||
Type = (activityProperty.Type ?? DeterminePropertyType(propertyInfo)).Camelize(),
|
||||
Hint = activityProperty.Hint,
|
||||
Options = GetPropertyTypeOptions(propertyInfo)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static object GetPropertyTypeOptions(PropertyInfo propertyInfo)
|
||||
{
|
||||
var optionsAttribute = propertyInfo.GetCustomAttribute<ActivityPropertyOptionsAttribute>();
|
||||
|
||||
return optionsAttribute?.GetOptions() ?? new object();
|
||||
}
|
||||
|
||||
private static string DeterminePropertyType(PropertyInfo propertyInfo)
|
||||
{
|
||||
var type = propertyInfo.PropertyType;
|
||||
|
||||
if (typeof(IWorkflowExpression).IsAssignableFrom(type))
|
||||
return ActivityPropertyTypes.Expression;
|
||||
|
||||
if (type == typeof(bool) || type == typeof(bool?))
|
||||
return ActivityPropertyTypes.Boolean;
|
||||
|
||||
if (typeof(IEnumerable).IsAssignableFrom(type))
|
||||
return ActivityPropertyTypes.List;
|
||||
|
||||
return ActivityPropertyTypes.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<PackageVersion>1.0.0</PackageVersion>
|
||||
<Authors>Sipke Schoorstra</Authors>
|
||||
<Description>Elsa is a set of workflowing libraries and tools to enable super-fast workflowing capabilities in any .NET Core application.</Description>
|
||||
<Copyright>2019</Copyright>
|
||||
<PackageProjectUrl>https://github.com/elsa-workflows/elsa-core</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/elsa-workflows/elsa-core</RepositoryUrl>
|
||||
<RepositoryType>GitHub</RepositoryType>
|
||||
<PackageTags>elsa, workflows</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.7.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa.Abstractions\Elsa.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
namespace Elsa.WorkflowDesigner.Models
|
||||
{
|
||||
public class ActivityDefinition
|
||||
{
|
||||
public ActivityDefinition()
|
||||
{
|
||||
Properties = new ActivityPropertyDescriptor[0];
|
||||
}
|
||||
|
||||
public string Type { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Category { get; set; }
|
||||
public ActivityPropertyDescriptor[] Properties { get; set; }
|
||||
public ActivityDesignerSettings Designer { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace Elsa.WorkflowDesigner.Models
|
||||
{
|
||||
public class ActivityDesignerSettings
|
||||
{
|
||||
public object Description { get; set; }
|
||||
public object Outcomes { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
namespace Elsa.WorkflowDesigner.Models
|
||||
{
|
||||
public class ActivityPropertyDescriptor
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Label { get; set; }
|
||||
public string Hint { get; set; }
|
||||
public object Options { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
namespace Elsa.WorkflowDesigner.Models
|
||||
{
|
||||
public static class ActivityPropertyTypes
|
||||
{
|
||||
public const string Text = "text";
|
||||
public const string Boolean = "boolean";
|
||||
public const string Expression = "expression";
|
||||
public const string List = "list";
|
||||
public const string Select = "select";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Elsa.WorkflowDesigner.Models
|
||||
{
|
||||
public class WorkflowExpressionOptions
|
||||
{
|
||||
public bool Multiline { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using Elsa.WorkflowDesigner.Models;
|
||||
using Elsa.WorkflowDesigner.ViewModels;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Elsa.WorkflowDesigner.ViewComponents
|
||||
{
|
||||
public class WorkflowDesignerViewComponent : ViewComponent
|
||||
{
|
||||
public IViewComponentResult Invoke(ActivityDefinition[] activityDefinitions)
|
||||
{
|
||||
var model = new WorkflowDesignerViewComponentModel
|
||||
{
|
||||
ActivityDefinitionsJson = GetActivityDefinitionOptions(activityDefinitions)
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
private string GetActivityDefinitionOptions(ActivityDefinition[] activityDefinitions)
|
||||
{
|
||||
var definitions = activityDefinitions ?? new ActivityDefinition[0];
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
return JsonConvert.SerializeObject(definitions, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Elsa.WorkflowDesigner.ViewModels
|
||||
{
|
||||
public class WorkflowDesignerViewComponentModel
|
||||
{
|
||||
public string ActivityDefinitionsJson { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
@model Elsa.WorkflowDesigner.ViewModels.WorkflowDesignerViewComponentModel
|
||||
|
||||
<wf-designer-host id="designerHost" canvas-height="300vh" activity-definitions="@Model.ActivityDefinitionsJson"></wf-designer-host>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@addTagHelper *, Elsa.Dashboard
|
||||
Loading…
Reference in a new issue