Added expression editor view component

This commit is contained in:
Sipke Schoorstra 2019-01-05 21:19:13 +01:00
parent 8020c49d3c
commit 81a6f3893e
20 changed files with 240 additions and 32 deletions

View file

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using Elsa.Activities.Http.Models;
using Elsa.Expressions;
using Elsa.Models;
namespace Elsa.Activities.Http.Activities
{
public class HttpRequestAction : Activity
{
/// <summary>
/// The URL to invoke.
/// </summary>
public Uri Url { get; set; }
/// <summary>
/// The HTTP method to use.
/// </summary>
public string Method { get; set; }
/// <summary>
/// The body to send along with the request
/// </summary>
public WorkflowExpression<string> Body { get; set; }
/// <summary>
/// The body to send along with the request
/// </summary>
public IDictionary<string, string> RequestHeaders { get; set; }
}
}

View file

@ -22,6 +22,12 @@ namespace Elsa.Activities.Http
T["HTTP Request Trigger"],
T["Triggers when an incoming HTTP request is received."],
T["Done"]);
yield return ActivityDescriptor.ForAction<HttpRequestAction>(
Category,
T["HTTP Request"],
T["Execute a HTTP request."],
T["Done"]);
}
}
}

View file

@ -0,0 +1,24 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Activities.Http.Activities;
using Elsa.Handlers;
using Elsa.Models;
using Elsa.Results;
namespace Elsa.Activities.Http.Drivers
{
public class HttpRequestActionDriver : ActivityDriver<HttpRequestAction>
{
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
public HttpRequestActionDriver(IWorkflowExpressionEvaluator expressionEvaluator)
{
this.expressionEvaluator = expressionEvaluator;
}
protected override async Task<ActivityExecutionResult> OnExecuteAsync(HttpRequestAction activity, WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
{
return TriggerEndpoint("Done");
}
}
}

View file

@ -1,20 +1,23 @@
namespace Elsa.Expressions
{
public class WorkflowExpression<T>
public class WorkflowExpression
{
public WorkflowExpression()
{
}
public WorkflowExpression(string syntax, string expression)
protected WorkflowExpression(string syntax, string expression)
{
Syntax = syntax;
Expression = expression;
}
public string Syntax { get; set; }
public string Expression { get; set; }
public string Syntax { get; }
public string Expression { get; }
public override string ToString() => Expression;
}
public class WorkflowExpression<T> : WorkflowExpression
{
public WorkflowExpression(string syntax, string expression) : base(syntax, expression)
{
}
}
}

View file

@ -25,7 +25,9 @@ namespace Elsa.Extensions
services.TryAddSingleton<ITokenizerInvoker, TokenizerInvoker>();
services.AddSingleton<ITokenizer, DefaultTokenizer>();
services.AddSingleton<ITokenizer, ActivityTokenizer>();
services.AddSingleton<IExpressionEvaluator, PlainTextEvaluator>();
services.AddSingleton<IExpressionEvaluator, JavaScriptEvaluator>();
return services;
}
@ -34,8 +36,6 @@ namespace Elsa.Extensions
services.TryAddSingleton<IWorkflowInvoker, WorkflowInvoker>();
services.TryAddSingleton<IActivityInvoker, ActivityInvoker>();
services.TryAddSingleton<IActivityDriverRegistry, ActivityDriverRegistry>();
services.AddSingleton<IExpressionEvaluator, PlainTextEvaluator>();
services.AddSingleton<IExpressionEvaluator, JavaScriptEvaluator>();
services.TryAddSingleton<IWorkflowExpressionEvaluator, WorkflowExpressionEvaluator>();
return services;

View file

@ -0,0 +1,25 @@
using Elsa.Activities.Http.Activities;
using Elsa.Expressions;
using Elsa.Web.Activities.Http.ViewModels;
using Elsa.Web.Components.ViewModels;
using Elsa.Web.Drivers;
namespace Elsa.Web.Activities.Http.Display
{
public class HttpRequestActionDisplay : ActivityDisplayDriver<HttpRequestAction, HttpRequestActionViewModel>
{
protected override void EditActivity(HttpRequestAction activity, HttpRequestActionViewModel model)
{
model.Method = activity.Method;
model.Body = new ExpressionViewModel(activity.Body);
model.Url = activity.Url;
}
protected override void UpdateActivity(HttpRequestActionViewModel model, HttpRequestAction activity)
{
activity.Method = model.Method;
activity.Body = model.Body.ToWorkflowExpression<string>();
activity.Url = model.Url;
}
}
}

View file

@ -2,7 +2,7 @@
using Elsa.Web.Activities.Http.ViewModels;
using Elsa.Web.Drivers;
namespace Elsa.Web.Activities.Http.Drivers
namespace Elsa.Web.Activities.Http.Display
{
public class HttpRequestTriggerDisplay : ActivityDisplayDriver<HttpRequestTrigger, HttpRequestTriggerViewModel>
{

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
@ -15,6 +15,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
<ProjectReference Include="..\Elsa.Web.Abstractions\Elsa.Web.Abstractions.csproj" />
<ProjectReference Include="..\Elsa.Web.Components\Elsa.Web.Components.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -1,5 +1,5 @@
using Elsa.Activities.Http.Extensions;
using Elsa.Web.Activities.Http.Drivers;
using Elsa.Web.Activities.Http.Display;
using Elsa.Web.Extensions;
using Microsoft.Extensions.DependencyInjection;
using OrchardCore.Modules;
@ -12,7 +12,8 @@ namespace Elsa.Web.Activities.Http
{
services
.AddHttpWorkflowDescriptors()
.AddActivityDisplay<HttpRequestTriggerDisplay>();
.AddActivityDisplay<HttpRequestTriggerDisplay>()
.AddActivityDisplay<HttpRequestActionDisplay>();
}
}
}

View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Elsa.Expressions;
using Elsa.Web.Components.ViewModels;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace Elsa.Web.Activities.Http.ViewModels
{
public class HttpRequestActionViewModel
{
[Required]
public Uri Url { get; set; }
[Required]
public string Method { get; set; }
public ExpressionViewModel Body { get; set; }
public ICollection<SelectListItem> GetAvailableHttpMethods()
{
var availableHttpMethods = new[] { "GET", "POST", "PUT", "DELETE", "OPTIONS" };
return availableHttpMethods.Select(x => new SelectListItem { Text = x, Value = x }).ToList();
}
}
}

View file

@ -0,0 +1,6 @@
@model ActivityShapeModel<HttpRequestAction>
@{
var activityDescriptor = Model.Activity.Descriptor;
}
<h4 class="card-title"><i class="fas fa-globe"></i>@activityDescriptor.DisplayText</h4>
<p>@activityDescriptor.Description</p>

View file

@ -0,0 +1,6 @@
@model ActivityShapeModel<HttpRequestAction>
<header>
<h4><i class="fas fa-globe"></i>@Model.DisplayText</h4>
<i>&quot;@($"{Model.Activity.Method} {Model.Activity.Url}")&quot;</i>
</header>

View file

@ -0,0 +1,20 @@
@using OrchardCore.Mvc.Core.Utilities
@model HttpRequestActionViewModel
<div class="form-group">
<label asp-for="Url">@T["Url"]</label>
<input asp-for="Url" class="form-control"/>
<span asp-validation-for="Url" class="text-danger"></span>
<small class="form-text text-muted">@T["The relative path that will trigger this activity. Example: '/webhooks/my'"]</small>
</div>
<div class="form-group">
<label asp-for="Method">@T["Method"]</label>
<select class="form-control" asp-for="Method" asp-items="Model.GetAvailableHttpMethods()"></select>
<span asp-validation-for="Method" class="text-danger"></span>
<small class="form-text text-muted">@T["The HTTP method to use for the request."]</small>
</div>
<div class="form-group">
<label asp-for="Body">@T["Body"]</label>
<vc:expression-editor model="@Model.Body" prefix="@Html.NameFor(m => m.Body)"></vc:expression-editor>
<span asp-validation-for="Body" class="text-danger"></span>
<small class="form-text text-muted">@T["The HTTP request body to send along with the request."]</small>
</div>

View file

@ -1,5 +1,4 @@
@using OrchardCore.Mvc.Core.Utilities
@model Elsa.Web.Activities.Http.ViewModels.HttpRequestTriggerViewModel
@model HttpRequestTriggerViewModel
<div class="form-group">
<label asp-for="Path">@T["Path"]</label>
<div class="input-group mb-3">
@ -15,19 +14,19 @@
<label asp-for="Method">@T["Method"]</label>
<select class="form-control" asp-for="Method" asp-items="Model.GetAvailableHttpMethods()"></select>
<span asp-validation-for="Method" class="text-danger"></span>
<small class="form-text text-muted">@T["The HTTP method to match.'"]</small>
<small class="form-text text-muted">@T["The HTTP method to match."]</small>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input"/>
<label class="custom-control-label">@T["Include nonce"]</label>
</div>
<small class="form-text text-muted">@T["Check to generate a nonce that needs to be included when invoking the URL.'"]</small>
<small class="form-text text-muted">@T["Check to generate a nonce that needs to be included when invoking the URL."]</small>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input asp-for="ReadContent" type="checkbox" class="custom-control-input"/>
<label asp-for="ReadContent" class="custom-control-label">@T["Read content"]</label>
</div>
<small class="form-text text-muted">@T["Check to read the request body. If the content type represents a form, the body is parsed as a collection of key/value pairs. Otherwise the body is stored as a raw string'"]</small>
<small class="form-text text-muted">@T["Check to read the request body. If the content type represents a form, the body is parsed as a collection of key/value pairs. Otherwise the body is stored as a raw string"]</small>
</div>

View file

@ -1,3 +1,7 @@
@using Elsa.Web.Activities.Http.ViewModels
@using Elsa.Web.ViewModels
@using Elsa.Activities.Http.Activities
@using OrchardCore.Mvc.Core.Utilities
@inherits OrchardCore.DisplayManagement.Razor.RazorPage<TModel>
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Elsa.Web.Components

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Elsa.Web.Components</RootNamespace>
<PackageVersion>1.0.0</PackageVersion>
<Authors>Sipke Schoorstra</Authors>
@ -14,24 +14,24 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OrchardCore.Module.Targets" Version="1.0.0-beta3-70362"/>
<PackageReference Include="OrchardCore.DisplayManagement" Version="1.0.0-beta3-70362"/>
<PackageReference Include="OrchardCore.Resources" Version="1.0.0-beta3-70362"/>
<PackageReference Include="OrchardCore.Module.Targets" Version="1.0.0-beta3-70362" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="1.0.0-beta3-70362" />
<PackageReference Include="OrchardCore.Resources" Version="1.0.0-beta3-70362" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\core\Elsa.Abstractions\Elsa.Abstractions.csproj"/>
<ProjectReference Include="..\..\..\core\Elsa.Core\Elsa.Core.csproj"/>
<ProjectReference Include="..\..\..\core\Elsa.Persistence.Abstractions\Elsa.Persistence.Abstractions.csproj"/>
<ProjectReference Include="..\Elsa.Web.Abstractions\Elsa.Web.Abstractions.csproj"/>
<ProjectReference Include="..\..\..\core\Elsa.Abstractions\Elsa.Abstractions.csproj" />
<ProjectReference Include="..\..\..\core\Elsa.Core\Elsa.Core.csproj" />
<ProjectReference Include="..\..\..\core\Elsa.Persistence.Abstractions\Elsa.Persistence.Abstractions.csproj" />
<ProjectReference Include="..\Elsa.Web.Abstractions\Elsa.Web.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<RazorGenerate Remove="Views\Shared\Components\ActivityLibrary\Default.cshtml"/>
<RazorGenerate Remove="Views\Shared\Components\ActivityLibrary\Default.cshtml" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\scripts\contextmenu\contextmenu.js"/>
<None Remove="Assets\scripts\contextmenu\contextmenu.js" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Linq;
using Elsa.Web.Components.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace Elsa.Web.Components.ViewComponents
{
public class ExpressionEditor : ViewComponent
{
private readonly IEnumerable<IExpressionEvaluator> evaluators;
public ExpressionEditor(IEnumerable<IExpressionEvaluator> evaluators)
{
this.evaluators = evaluators;
}
public IViewComponentResult Invoke(ExpressionViewModel model, string prefix)
{
ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = prefix;
ViewContext.ViewBag.Syntaxes = evaluators.Select(x => new SelectListItem(x.Syntax, x.Syntax));
return View(model);
}
}
}

View file

@ -0,0 +1,21 @@
using Elsa.Expressions;
namespace Elsa.Web.Components.ViewModels
{
public class ExpressionViewModel
{
public ExpressionViewModel()
{
}
public ExpressionViewModel(WorkflowExpression workflowExpression)
{
Expression = workflowExpression?.Expression;
Syntax = workflowExpression?.Syntax;
}
public string Expression { get; set; }
public string Syntax { get; set; }
public WorkflowExpression<T> ToWorkflowExpression<T>() => new WorkflowExpression<T>(Syntax, Expression);
}
}

View file

@ -0,0 +1,7 @@
@model ExpressionViewModel
<div class="input-group mb-3">
<input asp-for="Expression" type="text" class="form-control" placeholder="Enter an expression">
<div class="input-group-append">
<select asp-for="Syntax" class="input-group-select" asp-items="@ViewBag.Syntaxes"></select>
</div>
</div>

View file

@ -1,5 +1,7 @@
@using Elsa.Web.Components.ViewModels
@inherits OrchardCore.DisplayManagement.Razor.RazorPage<TModel>
@namespace Elsa.Web.Components.Views
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, OrchardCore.DisplayManagement
@addTagHelper *, OrchardCore.ResourceManagement
@addTagHelper *, OrchardCore.ResourceManagement
@addTagHelper *, Elsa.Web.Components