Remove Trigger separation
This commit is contained in:
parent
c600399f0d
commit
161a70e429
|
|
@ -1,32 +0,0 @@
|
|||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Elsa.Management.Contracts;
|
||||
using Elsa.Management.Serialization.Converters;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Api.Endpoints.TriggerDescriptors;
|
||||
|
||||
public static partial class TriggerDescriptors
|
||||
{
|
||||
public static IResult ListAsync(ITriggerRegistry registry, IWellKnownTypeRegistry wellKnownTypeRegistry)
|
||||
{
|
||||
var descriptors = registry.ListAll().ToList();
|
||||
|
||||
var model = new
|
||||
{
|
||||
TriggerDescriptors = descriptors
|
||||
};
|
||||
|
||||
return Results.Json(model, new JsonSerializerOptions
|
||||
{
|
||||
Converters =
|
||||
{
|
||||
new JsonStringEnumConverter(),
|
||||
new TypeJsonConverter(wellKnownTypeRegistry)
|
||||
},
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Elsa.Api.Endpoints.TriggerDescriptors;
|
||||
|
||||
public class TriggerDescriptorsResource
|
||||
{
|
||||
private readonly IEndpointRouteBuilder _endpoints;
|
||||
|
||||
public TriggerDescriptorsResource(IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
_endpoints = endpoints;
|
||||
}
|
||||
|
||||
public TriggerDescriptorsResource List()
|
||||
{
|
||||
_endpoints.MapGet("api/descriptors/triggers", TriggerDescriptors.ListAsync);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TriggerDescriptorsResourceExtensions
|
||||
{
|
||||
public static IEndpointRouteBuilder MapTriggerDescriptors(this IEndpointRouteBuilder endpoints, Action<TriggerDescriptorsResource> configureResource)
|
||||
{
|
||||
configureResource(new(endpoints));
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
public static IEndpointRouteBuilder MapTriggerDescriptors(this IEndpointRouteBuilder endpoints) => endpoints.MapTriggerDescriptors(x => x.List());
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@ public static partial class Workflows
|
|||
string? Name,
|
||||
string? Description,
|
||||
IActivity? Root,
|
||||
ICollection<ITrigger>? Triggers,
|
||||
bool Publish);
|
||||
|
||||
public static async Task<IResult> PostAsync(
|
||||
|
|
@ -49,12 +48,10 @@ public static partial class Workflows
|
|||
|
||||
// Update the draft with the received model.
|
||||
var root = model.Root ?? new Sequence();
|
||||
var triggers = model.Triggers ?? new List<ITrigger>();
|
||||
|
||||
draft = draft with
|
||||
{
|
||||
Root = root,
|
||||
Triggers = triggers,
|
||||
Metadata = draft.Metadata with
|
||||
{
|
||||
Name = model.Name,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Api.Endpoints.ActivityDescriptors;
|
||||
using Elsa.Api.Endpoints.Events;
|
||||
using Elsa.Api.Endpoints.TriggerDescriptors;
|
||||
using Elsa.Api.Endpoints.WorkflowInstances;
|
||||
using Elsa.Api.Endpoints.Workflows;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
|
@ -13,6 +12,5 @@ public static class EndpointRouteBuilderExtensions
|
|||
.MapWorkflows()
|
||||
.MapWorkflowInstances()
|
||||
.MapActivityDescriptors()
|
||||
.MapTriggerDescriptors()
|
||||
.MapEvents();
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ public class WorkflowDefinitionBuilder : IWorkflowDefinitionBuilder
|
|||
public string? DefinitionId { get; private set; }
|
||||
public int Version { get; private set; } = 1;
|
||||
public IActivity? Root { get; private set; }
|
||||
public ICollection<ITrigger> Triggers { get; } = new List<ITrigger>();
|
||||
public ICollection<Variable> Variables { get; set; } = new List<Variable>();
|
||||
|
||||
public IWorkflowDefinitionBuilder WithId(string id)
|
||||
|
|
@ -37,12 +36,6 @@ public class WorkflowDefinitionBuilder : IWorkflowDefinitionBuilder
|
|||
return this;
|
||||
}
|
||||
|
||||
public IWorkflowDefinitionBuilder AddTrigger(ITrigger trigger)
|
||||
{
|
||||
Triggers.Add(trigger);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Workflow BuildWorkflow()
|
||||
{
|
||||
var definitionId = DefinitionId ?? Guid.NewGuid().ToString("N");
|
||||
|
|
@ -51,6 +44,6 @@ public class WorkflowDefinitionBuilder : IWorkflowDefinitionBuilder
|
|||
var identity = new WorkflowIdentity(definitionId, Version, id);
|
||||
var publication = WorkflowPublication.LatestAndPublished;
|
||||
var metadata = new WorkflowMetadata();
|
||||
return new Workflow(identity, publication, metadata, root, Triggers, Variables);
|
||||
return new Workflow(identity, publication, metadata, root, Variables);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,22 @@ using Elsa.Models;
|
|||
|
||||
namespace Elsa.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Activities that act as a trigger should implement this interface.
|
||||
/// </summary>
|
||||
public interface ITrigger : INode
|
||||
{
|
||||
ValueTask<IEnumerable<object>> GetPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken = default);
|
||||
/// <summary>
|
||||
/// A value indicating whether this trigger can create a new workflow instances when triggered, or execute the workflow instance this trigger belongs to.
|
||||
/// </summary>
|
||||
TriggerMode TriggerMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implementing triggers should return zero or more objects that represent a lookup value.
|
||||
/// </summary>
|
||||
///<example>
|
||||
/// For example, if your trigger can be configured with a signal name to listen for, you would return an object with said signal name as a field.
|
||||
/// Your auxiliary services would then use this signal name to create a hash and use it to lookup a trigger stored in the database by this hash.
|
||||
/// </example>
|
||||
ValueTask<IEnumerable<object>> GetTriggerPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -7,11 +7,9 @@ public interface IWorkflowDefinitionBuilder
|
|||
string? DefinitionId { get; }
|
||||
int Version { get; }
|
||||
IActivity? Root { get; }
|
||||
ICollection<ITrigger> Triggers { get; }
|
||||
ICollection<Variable> Variables { get; set; }
|
||||
IWorkflowDefinitionBuilder WithDefinitionId(string definitionId);
|
||||
IWorkflowDefinitionBuilder WithVersion(int version);
|
||||
IWorkflowDefinitionBuilder WithRoot(IActivity root);
|
||||
IWorkflowDefinitionBuilder AddTrigger(ITrigger trigger);
|
||||
Workflow BuildWorkflow();
|
||||
}
|
||||
|
|
@ -1,22 +1,36 @@
|
|||
using Elsa.Contracts;
|
||||
using Elsa.Helpers;
|
||||
|
||||
namespace Elsa.Models;
|
||||
|
||||
public class Trigger : ITrigger
|
||||
public abstract class Trigger : Activity, ITrigger
|
||||
{
|
||||
protected Trigger() => NodeType = TypeNameHelper.GenerateTypeName(GetType());
|
||||
protected Trigger(string triggerType) => NodeType = triggerType;
|
||||
|
||||
public string Id { get; set; } = default!;
|
||||
public string NodeType { get; set; }
|
||||
public IDictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>();
|
||||
|
||||
public virtual ValueTask<IEnumerable<object>> GetPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken = default)
|
||||
protected Trigger()
|
||||
{
|
||||
var hashes = GetPayloads(context);
|
||||
}
|
||||
|
||||
protected Trigger(string triggerType) : base(triggerType)
|
||||
{
|
||||
}
|
||||
|
||||
public TriggerMode TriggerMode { get; set; } = TriggerMode.WorkflowDefinition;
|
||||
ValueTask<IEnumerable<object>> ITrigger.GetTriggerPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken) => GetTriggerPayloadsAsync(context, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to return a list of trigger payloads.
|
||||
/// </summary>
|
||||
protected virtual ValueTask<IEnumerable<object>> GetTriggerPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var hashes = GetTriggerPayloads(context);
|
||||
return ValueTask.FromResult(hashes);
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<object> GetPayloads(TriggerIndexingContext context) => Enumerable.Empty<object>();
|
||||
/// <summary>
|
||||
/// Override this method to return a list of trigger payloads.
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<object> GetTriggerPayloads(TriggerIndexingContext context) => new[]{ GetTriggerPayload(context) };
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to return a trigger payload.
|
||||
/// </summary>
|
||||
protected virtual object GetTriggerPayload(TriggerIndexingContext context) => new();
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
using Elsa.Contracts;
|
||||
|
||||
namespace Elsa.Models;
|
||||
|
||||
public class TriggerActivity : Activity, ITrigger
|
||||
{
|
||||
protected TriggerActivity()
|
||||
{
|
||||
}
|
||||
|
||||
protected TriggerActivity(string triggerType) : base(triggerType)
|
||||
{
|
||||
}
|
||||
|
||||
public string TriggerType
|
||||
{
|
||||
get => NodeType;
|
||||
set => NodeType = value;
|
||||
}
|
||||
|
||||
ValueTask<IEnumerable<object>> ITrigger.GetPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken) => GetPayloadsAsync(context, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to return a list of trigger payloads.
|
||||
/// </summary>
|
||||
protected virtual ValueTask<IEnumerable<object>> GetPayloadsAsync(TriggerIndexingContext context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var hashes = GetPayloads(context);
|
||||
return ValueTask.FromResult(hashes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to return a list of trigger payloads.
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<object> GetPayloads(TriggerIndexingContext context) => new[]{ GetPayload(context) };
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to return a trigger payloads.
|
||||
/// </summary>
|
||||
protected virtual object GetPayload(TriggerIndexingContext context) => new();
|
||||
}
|
||||
17
src/core/Elsa.Core/Models/TriggerMode.cs
Normal file
17
src/core/Elsa.Core/Models/TriggerMode.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
namespace Elsa.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A set of trigger modes.
|
||||
/// </summary>
|
||||
public enum TriggerMode
|
||||
{
|
||||
/// <summary>
|
||||
/// The trigger will create a new workflow instance and execute said instance.
|
||||
/// </summary>
|
||||
WorkflowDefinition,
|
||||
|
||||
/// <summary>
|
||||
/// The trigger will schedule the trigger for execution within the context of the workflow instance.
|
||||
/// </summary>
|
||||
WorkflowInstance
|
||||
}
|
||||
|
|
@ -7,10 +7,9 @@ public record Workflow(
|
|||
WorkflowPublication Publication,
|
||||
WorkflowMetadata Metadata,
|
||||
IActivity Root,
|
||||
ICollection<ITrigger> Triggers,
|
||||
ICollection<Variable> Variables)
|
||||
{
|
||||
public static Workflow FromActivity(IActivity root) => new(WorkflowIdentity.VersionOne, WorkflowPublication.LatestDraft, new WorkflowMetadata(), root, new List<ITrigger>(), new List<Variable>());
|
||||
public static Workflow FromActivity(IActivity root) => new(WorkflowIdentity.VersionOne, WorkflowPublication.LatestDraft, new WorkflowMetadata(), root, new List<Variable>());
|
||||
|
||||
public Workflow WithVersion(int version) => this with { Identity = Identity with { Version = version } };
|
||||
public Workflow IncrementVersion() => WithVersion(Identity.Version + 1);
|
||||
|
|
|
|||
|
|
@ -13,22 +13,8 @@ public class IdentityGraphService : IIdentityGraphService
|
|||
_activityWalker = activityWalker;
|
||||
}
|
||||
|
||||
public void AssignIdentities(Workflow workflow)
|
||||
{
|
||||
AssignIdentities(workflow.Root);
|
||||
public void AssignIdentities(Workflow workflow) => AssignIdentities(workflow.Root);
|
||||
|
||||
var triggers = workflow.Triggers;
|
||||
|
||||
if (triggers == null)
|
||||
return;
|
||||
|
||||
foreach (var trigger in triggers)
|
||||
{
|
||||
if(trigger is IActivity activity)
|
||||
AssignIdentities(activity);
|
||||
}
|
||||
}
|
||||
|
||||
public void AssignIdentities(IActivity root)
|
||||
{
|
||||
var graph = _activityWalker.Walk(root);
|
||||
|
|
|
|||
|
|
@ -35,5 +35,4 @@ public static class ServiceCollectionExtensions
|
|||
|
||||
public static IServiceCollection ConfigureApiOptions(this IServiceCollection services, Action<ApiOptions> configure) => services.Configure(configure);
|
||||
public static IServiceCollection AddActivity<T>(this IServiceCollection services) where T:IActivity => services.ConfigureApiOptions(options => options.ActivityTypes.Add(typeof(T)));
|
||||
public static IServiceCollection AddTrigger<T>(this IServiceCollection services) where T:ITrigger => services.ConfigureApiOptions(options => options.TriggerTypes.Add(typeof(T)));
|
||||
}
|
||||
|
|
@ -6,9 +6,4 @@ public class ApiOptions
|
|||
/// A collection of activity types made available from the API.
|
||||
/// </summary>
|
||||
public HashSet<Type> ActivityTypes { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// A collection of trigger types made available from the API.
|
||||
/// </summary>
|
||||
public HashSet<Type> TriggerTypes { get; set; } = new();
|
||||
}
|
||||
|
|
@ -34,7 +34,6 @@ namespace Elsa.Management.Services
|
|||
WorkflowPublication.LatestDraft,
|
||||
new WorkflowMetadata(CreatedAt: _systemClock.UtcNow),
|
||||
new Sequence(),
|
||||
new List<ITrigger>(),
|
||||
new List<Variable>());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,5 +76,4 @@ public static class ServiceCollectionExtensions
|
|||
public static IServiceCollection AddStimulusHandler<T>(this IServiceCollection services) where T : class, IStimulusHandler => services.AddSingleton<IStimulusHandler, T>();
|
||||
public static IServiceCollection AddInstructionInterpreter<T>(this IServiceCollection services) where T : class, IWorkflowInstructionInterpreter => services.AddSingleton<IWorkflowInstructionInterpreter, T>();
|
||||
public static IServiceCollection ConfigureWorkflowRuntime(this IServiceCollection services, Action<WorkflowRuntimeOptions> configure) => services.Configure(configure);
|
||||
public static IServiceCollection IndexWorkflowTriggers(this IServiceCollection services) => services.AddHostedService<IndexWorkflowTriggers>();
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
* It contains typing information for all components that exist in this project.
|
||||
*/
|
||||
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
|
||||
import { ActionDefinition, ActionInvokedArgs, Activity, ActivityDescriptor, ActivitySelectedArgs, ContainerSelectedArgs, GraphUpdatedArgs, IntellisenseContext, SelectListItem, TabChangedArgs, TabDefinition, Trigger, TriggerDescriptor, Workflow, WorkflowInstance, WorkflowInstanceSummary, WorkflowSummary } from "./models";
|
||||
import { ActionDefinition, ActionInvokedArgs, Activity, ActivityDescriptor, ActivitySelectedArgs, ContainerSelectedArgs, GraphUpdatedArgs, IntellisenseContext, SelectListItem, TabChangedArgs, TabDefinition, Workflow, WorkflowInstance, WorkflowInstanceSummary, WorkflowSummary } from "./models";
|
||||
import { ActivityUpdatedArgs, DeleteActivityRequestedArgs } from "./components/designer/activity-properties-editor/activity-properties-editor";
|
||||
import { ContainerActivityComponent } from "./components/activities/container-activity-component";
|
||||
import { AddActivityArgs } from "./components/designer/canvas/canvas";
|
||||
|
|
@ -18,8 +18,6 @@ import { ExpressionChangedArs } from "./components/designer/input-control-switch
|
|||
import { MonacoLib, MonacoValueChangedArgs } from "./components/shared/monaco-editor/monaco-editor";
|
||||
import { PagerData } from "./components/shared/pager/pager";
|
||||
import { PanelPosition, PanelStateChangedArgs } from "./components/designer/panel/models";
|
||||
import { TriggerDeselectedArgs, TriggerSelectedArgs, TriggersUpdatedArgs } from "./components/designer/trigger-container/trigger-container";
|
||||
import { DeleteTriggerRequestedArgs, TriggerUpdatedArgs } from "./components/designer/trigger-properties-editor/trigger-properties-editor";
|
||||
import { WorkflowUpdatedArgs } from "./components/designer/workflow-editor/workflow-editor";
|
||||
import { ActivityDriverRegistry } from "./services";
|
||||
import { WorkflowPropsUpdatedArgs } from "./components/designer/workflow-properties-editor/workflow-properties-editor";
|
||||
|
|
@ -155,24 +153,6 @@ export namespace Components {
|
|||
interface ElsaToolboxActivities {
|
||||
"activityDescriptors": Array<ActivityDescriptor>;
|
||||
"graph": Graph;
|
||||
"triggerDescriptors": Array<TriggerDescriptor>;
|
||||
}
|
||||
interface ElsaToolboxTriggers {
|
||||
"activityDescriptors": Array<ActivityDescriptor>;
|
||||
"graph": Graph;
|
||||
"triggerDescriptors": Array<TriggerDescriptor>;
|
||||
}
|
||||
interface ElsaTriggerContainer {
|
||||
"deselectAll": () => Promise<void>;
|
||||
"interactiveMode": boolean;
|
||||
"triggerDescriptors": Array<TriggerDescriptor>;
|
||||
"triggers": Array<Trigger>;
|
||||
}
|
||||
interface ElsaTriggerPropertiesEditor {
|
||||
"hide": () => Promise<void>;
|
||||
"show": () => Promise<void>;
|
||||
"trigger"?: Trigger;
|
||||
"triggerDescriptors": Array<TriggerDescriptor>;
|
||||
}
|
||||
interface ElsaWorkflowBrowser {
|
||||
"hide": () => Promise<void>;
|
||||
|
|
@ -186,7 +166,6 @@ export namespace Components {
|
|||
"importWorkflowMetadata": (workflow: Workflow) => Promise<void>;
|
||||
"monacoLibPath": string;
|
||||
"registerActivityDrivers": (register: (registry: ActivityDriverRegistry) => void) => Promise<void>;
|
||||
"triggerDescriptors": Array<TriggerDescriptor>;
|
||||
}
|
||||
interface ElsaWorkflowInstanceBrowser {
|
||||
"hide": () => Promise<void>;
|
||||
|
|
@ -356,24 +335,6 @@ declare global {
|
|||
prototype: HTMLElsaToolboxActivitiesElement;
|
||||
new (): HTMLElsaToolboxActivitiesElement;
|
||||
};
|
||||
interface HTMLElsaToolboxTriggersElement extends Components.ElsaToolboxTriggers, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaToolboxTriggersElement: {
|
||||
prototype: HTMLElsaToolboxTriggersElement;
|
||||
new (): HTMLElsaToolboxTriggersElement;
|
||||
};
|
||||
interface HTMLElsaTriggerContainerElement extends Components.ElsaTriggerContainer, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaTriggerContainerElement: {
|
||||
prototype: HTMLElsaTriggerContainerElement;
|
||||
new (): HTMLElsaTriggerContainerElement;
|
||||
};
|
||||
interface HTMLElsaTriggerPropertiesEditorElement extends Components.ElsaTriggerPropertiesEditor, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaTriggerPropertiesEditorElement: {
|
||||
prototype: HTMLElsaTriggerPropertiesEditorElement;
|
||||
new (): HTMLElsaTriggerPropertiesEditorElement;
|
||||
};
|
||||
interface HTMLElsaWorkflowBrowserElement extends Components.ElsaWorkflowBrowser, HTMLStencilElement {
|
||||
}
|
||||
var HTMLElsaWorkflowBrowserElement: {
|
||||
|
|
@ -442,9 +403,6 @@ declare global {
|
|||
"elsa-switch-editor": HTMLElsaSwitchEditorElement;
|
||||
"elsa-toolbox": HTMLElsaToolboxElement;
|
||||
"elsa-toolbox-activities": HTMLElsaToolboxActivitiesElement;
|
||||
"elsa-toolbox-triggers": HTMLElsaToolboxTriggersElement;
|
||||
"elsa-trigger-container": HTMLElsaTriggerContainerElement;
|
||||
"elsa-trigger-properties-editor": HTMLElsaTriggerPropertiesEditorElement;
|
||||
"elsa-workflow-browser": HTMLElsaWorkflowBrowserElement;
|
||||
"elsa-workflow-editor": HTMLElsaWorkflowEditorElement;
|
||||
"elsa-workflow-instance-browser": HTMLElsaWorkflowInstanceBrowserElement;
|
||||
|
|
@ -589,26 +547,6 @@ declare namespace LocalJSX {
|
|||
interface ElsaToolboxActivities {
|
||||
"activityDescriptors"?: Array<ActivityDescriptor>;
|
||||
"graph"?: Graph;
|
||||
"triggerDescriptors"?: Array<TriggerDescriptor>;
|
||||
}
|
||||
interface ElsaToolboxTriggers {
|
||||
"activityDescriptors"?: Array<ActivityDescriptor>;
|
||||
"graph"?: Graph;
|
||||
"triggerDescriptors"?: Array<TriggerDescriptor>;
|
||||
}
|
||||
interface ElsaTriggerContainer {
|
||||
"interactiveMode"?: boolean;
|
||||
"onTriggerDeselected"?: (event: CustomEvent<TriggerDeselectedArgs>) => void;
|
||||
"onTriggerSelected"?: (event: CustomEvent<TriggerSelectedArgs>) => void;
|
||||
"onTriggersUpdated"?: (event: CustomEvent<TriggersUpdatedArgs>) => void;
|
||||
"triggerDescriptors"?: Array<TriggerDescriptor>;
|
||||
"triggers"?: Array<Trigger>;
|
||||
}
|
||||
interface ElsaTriggerPropertiesEditor {
|
||||
"onDeleteTriggerRequested"?: (event: CustomEvent<DeleteTriggerRequestedArgs>) => void;
|
||||
"onTriggerUpdated"?: (event: CustomEvent<TriggerUpdatedArgs>) => void;
|
||||
"trigger"?: Trigger;
|
||||
"triggerDescriptors"?: Array<TriggerDescriptor>;
|
||||
}
|
||||
interface ElsaWorkflowBrowser {
|
||||
"onWorkflowDefinitionSelected"?: (event: CustomEvent<WorkflowSummary>) => void;
|
||||
|
|
@ -617,7 +555,6 @@ declare namespace LocalJSX {
|
|||
"activityDescriptors"?: Array<ActivityDescriptor>;
|
||||
"monacoLibPath"?: string;
|
||||
"onWorkflowUpdated"?: (event: CustomEvent<WorkflowUpdatedArgs>) => void;
|
||||
"triggerDescriptors"?: Array<TriggerDescriptor>;
|
||||
}
|
||||
interface ElsaWorkflowInstanceBrowser {
|
||||
"onWorkflowInstanceSelected"?: (event: CustomEvent<WorkflowInstanceSummary>) => void;
|
||||
|
|
@ -664,9 +601,6 @@ declare namespace LocalJSX {
|
|||
"elsa-switch-editor": ElsaSwitchEditor;
|
||||
"elsa-toolbox": ElsaToolbox;
|
||||
"elsa-toolbox-activities": ElsaToolboxActivities;
|
||||
"elsa-toolbox-triggers": ElsaToolboxTriggers;
|
||||
"elsa-trigger-container": ElsaTriggerContainer;
|
||||
"elsa-trigger-properties-editor": ElsaTriggerPropertiesEditor;
|
||||
"elsa-workflow-browser": ElsaWorkflowBrowser;
|
||||
"elsa-workflow-editor": ElsaWorkflowEditor;
|
||||
"elsa-workflow-instance-browser": ElsaWorkflowInstanceBrowser;
|
||||
|
|
@ -705,9 +639,6 @@ declare module "@stencil/core" {
|
|||
"elsa-switch-editor": LocalJSX.ElsaSwitchEditor & JSXBase.HTMLAttributes<HTMLElsaSwitchEditorElement>;
|
||||
"elsa-toolbox": LocalJSX.ElsaToolbox & JSXBase.HTMLAttributes<HTMLElsaToolboxElement>;
|
||||
"elsa-toolbox-activities": LocalJSX.ElsaToolboxActivities & JSXBase.HTMLAttributes<HTMLElsaToolboxActivitiesElement>;
|
||||
"elsa-toolbox-triggers": LocalJSX.ElsaToolboxTriggers & JSXBase.HTMLAttributes<HTMLElsaToolboxTriggersElement>;
|
||||
"elsa-trigger-container": LocalJSX.ElsaTriggerContainer & JSXBase.HTMLAttributes<HTMLElsaTriggerContainerElement>;
|
||||
"elsa-trigger-properties-editor": LocalJSX.ElsaTriggerPropertiesEditor & JSXBase.HTMLAttributes<HTMLElsaTriggerPropertiesEditorElement>;
|
||||
"elsa-workflow-browser": LocalJSX.ElsaWorkflowBrowser & JSXBase.HTMLAttributes<HTMLElsaWorkflowBrowserElement>;
|
||||
"elsa-workflow-editor": LocalJSX.ElsaWorkflowEditor & JSXBase.HTMLAttributes<HTMLElsaWorkflowEditorElement>;
|
||||
"elsa-workflow-instance-browser": LocalJSX.ElsaWorkflowInstanceBrowser & JSXBase.HTMLAttributes<HTMLElsaWorkflowInstanceBrowserElement>;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
import {createProviderConsumer} from "@stencil/state-tunnel";
|
||||
import {h} from "@stencil/core";
|
||||
import {ActivityDescriptor, TriggerDescriptor, Workflow} from "../../models";
|
||||
import {ActivityDescriptor, Workflow} from "../../models";
|
||||
|
||||
export interface WorkflowDesignerState {
|
||||
workflow: Workflow;
|
||||
activityDescriptors: Array<ActivityDescriptor>;
|
||||
triggerDescriptors: Array<TriggerDescriptor>;
|
||||
}
|
||||
|
||||
export default createProviderConsumer<WorkflowDesignerState>(
|
||||
{
|
||||
workflow: null,
|
||||
activityDescriptors: [],
|
||||
triggerDescriptors: []
|
||||
activityDescriptors: []
|
||||
},
|
||||
(subscribe, child) => (<context-consumer subscribe={subscribe} renderer={child}/>)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import {Component, h, Prop, State, Watch} from "@stencil/core";
|
|||
import {Addon, Graph} from '@antv/x6';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import {Container} from 'typedi';
|
||||
import {ActivityDescriptor, TriggerDescriptor} from '../../../models';
|
||||
import {ActivityDescriptor} from '../../../models';
|
||||
import {ActivityDriverRegistry} from '../../../services';
|
||||
import WorkflowEditorTunnel from '../state';
|
||||
|
||||
|
|
@ -18,7 +18,6 @@ interface ActivityCategoryModel {
|
|||
export class ToolboxActivities {
|
||||
@Prop() graph: Graph;
|
||||
@Prop({mutable: true}) activityDescriptors: Array<ActivityDescriptor> = [];
|
||||
@Prop({mutable: true}) triggerDescriptors: Array<TriggerDescriptor> = [];
|
||||
@State() activityCategoryModels: Array<ActivityCategoryModel> = [];
|
||||
private dnd: Addon.Dnd;
|
||||
private renderedActivities: Map<string, string>;
|
||||
|
|
@ -71,17 +70,9 @@ export class ToolboxActivities {
|
|||
this.handleActivityDescriptorsChanged(this.activityDescriptors);
|
||||
}
|
||||
|
||||
private onActivityStartDrag(e: DragEvent, activityDescriptor: ActivityDescriptor) {
|
||||
private static onActivityStartDrag(e: DragEvent, activityDescriptor: ActivityDescriptor) {
|
||||
const json = JSON.stringify(activityDescriptor);
|
||||
const triggerDescriptor = this.triggerDescriptors.find(x => x.nodeType == activityDescriptor.nodeType);
|
||||
const isTrigger = !!triggerDescriptor;
|
||||
|
||||
e.dataTransfer.setData('activity-descriptor', json);
|
||||
|
||||
if (isTrigger) {
|
||||
const triggerDescriptorJson = JSON.stringify(triggerDescriptor);
|
||||
e.dataTransfer.setData('trigger-descriptor', triggerDescriptorJson);
|
||||
}
|
||||
}
|
||||
|
||||
private onToggleActivityCategory(categoryModel: ActivityCategoryModel) {
|
||||
|
|
@ -121,7 +112,7 @@ export class ToolboxActivities {
|
|||
return (
|
||||
<div class="w-full flex items-center pl-10 pr-2 py-2">
|
||||
<div class="cursor-move"
|
||||
onDragStart={e => this.onActivityStartDrag(e, activityDescriptor)}>
|
||||
onDragStart={e => ToolboxActivities.onActivityStartDrag(e, activityDescriptor)}>
|
||||
<div innerHTML={activityHtml} draggable={true}/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -136,4 +127,4 @@ export class ToolboxActivities {
|
|||
}
|
||||
}
|
||||
|
||||
WorkflowEditorTunnel.injectProps(ToolboxActivities, ['activityDescriptors', 'triggerDescriptors']);
|
||||
WorkflowEditorTunnel.injectProps(ToolboxActivities, ['activityDescriptors']);
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
import {Component, h, Prop, State, Watch} from '@stencil/core';
|
||||
import {Addon, Graph} from '@antv/x6';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import {ActivityDescriptor, TriggerDescriptor} from '../../../models';
|
||||
import WorkflowEditorTunnel from '../state';
|
||||
import {Container} from "typedi";
|
||||
import {TriggerDriverRegistry} from '../../../services/trigger-driver-registry';
|
||||
|
||||
interface TriggerCategoryModel {
|
||||
category: string;
|
||||
triggers: Array<TriggerDescriptor>;
|
||||
expanded: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-toolbox-triggers',
|
||||
})
|
||||
export class ToolboxTriggers {
|
||||
@Prop() graph: Graph;
|
||||
@Prop({mutable: true}) triggerDescriptors: Array<TriggerDescriptor> = [];
|
||||
@Prop({mutable: true}) activityDescriptors: Array<ActivityDescriptor> = [];
|
||||
@State() triggerCategoryModels: Array<TriggerCategoryModel> = [];
|
||||
private dnd: Addon.Dnd;
|
||||
private renderedTriggers: Map<string, string>;
|
||||
|
||||
@Watch('graph')
|
||||
handleGraphChanged(value: Graph) {
|
||||
|
||||
if (this.dnd)
|
||||
this.dnd.dispose();
|
||||
|
||||
this.dnd = new Addon.Dnd({
|
||||
target: value,
|
||||
scaled: false,
|
||||
animation: true,
|
||||
});
|
||||
}
|
||||
|
||||
@Watch('triggerDescriptors')
|
||||
handleTriggerDescriptorsChanged(value: Array<TriggerDescriptor>) {
|
||||
const categorizedTriggersLookup = groupBy(value, x => x.category);
|
||||
const categories = Object.keys(categorizedTriggersLookup);
|
||||
const renderedTriggers: Map<string, string> = new Map<string, string>();
|
||||
|
||||
// Group triggers by category
|
||||
this.triggerCategoryModels = categories.map(x => {
|
||||
const model: TriggerCategoryModel = {
|
||||
category: x,
|
||||
expanded: false,
|
||||
triggers: categorizedTriggersLookup[x]
|
||||
};
|
||||
|
||||
return model;
|
||||
});
|
||||
|
||||
// Render activities.
|
||||
const driverRegistry = Container.get(TriggerDriverRegistry);
|
||||
|
||||
for (const triggerDescriptor of value) {
|
||||
const triggerType = triggerDescriptor.nodeType;
|
||||
const driver = driverRegistry.createDriver(triggerType);
|
||||
const html = driver.display({displayType: 'picker', triggerDescriptor: triggerDescriptor});
|
||||
|
||||
renderedTriggers.set(triggerType, html);
|
||||
}
|
||||
|
||||
this.renderedTriggers = renderedTriggers;
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
this.handleTriggerDescriptorsChanged(this.triggerDescriptors);
|
||||
}
|
||||
|
||||
private onTriggerStartDrag(e: DragEvent, triggerDescriptor: TriggerDescriptor) {
|
||||
const json = JSON.stringify(triggerDescriptor);
|
||||
const activityDescriptor = this.activityDescriptors.find(x => x.nodeType == triggerDescriptor.nodeType);
|
||||
const isActivity = !!activityDescriptor;
|
||||
|
||||
e.dataTransfer.setData('trigger-descriptor', json);
|
||||
|
||||
if (isActivity) {
|
||||
const activityJson = JSON.stringify(activityDescriptor);
|
||||
e.dataTransfer.setData('activity-descriptor', activityJson);
|
||||
}
|
||||
}
|
||||
|
||||
private onToggleTriggerCategory(categoryModel: TriggerCategoryModel) {
|
||||
categoryModel.expanded = !categoryModel.expanded;
|
||||
this.triggerCategoryModels = [...this.triggerCategoryModels];
|
||||
}
|
||||
|
||||
render() {
|
||||
const categoryModels = this.triggerCategoryModels;
|
||||
const renderedTriggers = this.renderedTriggers;
|
||||
|
||||
return <nav class=" flex-1 px-2 space-y-1 font-sans text-sm text-gray-600">
|
||||
{categoryModels.map(categoryModel => {
|
||||
|
||||
const category = categoryModel.category;
|
||||
const triggers = categoryModel.triggers;
|
||||
const categoryButtonClass = categoryModel.expanded ? 'rotate-90' : '';
|
||||
const categoryContentClass = categoryModel.expanded ? '' : 'hidden';
|
||||
|
||||
return <div class="space-y-1">
|
||||
<button type="button"
|
||||
onClick={() => this.onToggleTriggerCategory(categoryModel)}
|
||||
class="text-gray-600 hover:bg-gray-50 hover:text-gray-900 group w-full flex items-center pr-2 py-2 text-left text-sm font-medium rounded-md focus:outline-none">
|
||||
<svg
|
||||
class={`${categoryButtonClass} text-gray-300 mr-2 flex-shrink-0 h-5 w-5 transform group-hover:text-gray-400 transition-colors ease-in-out duration-150`}
|
||||
viewBox="0 0 20 20" aria-hidden="true">
|
||||
<path d="M6 6L14 10L6 14V6Z" fill="currentColor"/>
|
||||
</svg>
|
||||
{category}
|
||||
</button>
|
||||
|
||||
<div class={`space-y-1 ${categoryContentClass}`}>
|
||||
|
||||
{triggers.map(trigger => {
|
||||
const triggerHtml = renderedTriggers.get(trigger.nodeType);
|
||||
|
||||
return (
|
||||
<div class="w-full flex items-center pl-10 pr-2 py-2">
|
||||
<div class="cursor-move" onDragStart={e => this.onTriggerStartDrag(e, trigger)}>
|
||||
<div innerHTML={triggerHtml} draggable={true}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
)}
|
||||
|
||||
</nav>
|
||||
}
|
||||
}
|
||||
|
||||
WorkflowEditorTunnel.injectProps(ToolboxTriggers, ['activityDescriptors', 'triggerDescriptors']);
|
||||
|
|
@ -19,7 +19,6 @@ export class Toolbox {
|
|||
const selectedCss = 'border-blue-500 text-blue-600';
|
||||
const defaultCss = 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300';
|
||||
const activitiesTabCssClass = selectedTabIndex == 0 ? selectedCss : defaultCss;
|
||||
const triggersTabCssClass = selectedTabIndex == 1 ? selectedCss : defaultCss;
|
||||
|
||||
return (
|
||||
|
||||
|
|
@ -33,11 +32,6 @@ export class Toolbox {
|
|||
Activities
|
||||
</a>
|
||||
|
||||
<a href="#"
|
||||
onClick={e => this.onTabSelected(e, 1)}
|
||||
class={`${triggersTabCssClass} w-1/2 py-4 px-1 text-center border-b-2 font-medium text-sm`}>
|
||||
Triggers
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
|
@ -45,9 +39,6 @@ export class Toolbox {
|
|||
graph={this.graph}
|
||||
class={selectedTabIndex == 0 ? '' : 'hidden'}/>
|
||||
|
||||
<elsa-toolbox-triggers
|
||||
graph={this.graph}
|
||||
class={selectedTabIndex == 1 ? '' : 'hidden'}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,158 +0,0 @@
|
|||
import {Component, EventEmitter, h, Prop, State, Event, Method} from '@stencil/core';
|
||||
import {v4 as uuid} from 'uuid';
|
||||
import {Container} from 'typedi';
|
||||
import {Activity, ActivitySelectedArgs, Trigger, TriggerDescriptor, Workflow} from '../../../models';
|
||||
import {TriggerDriverRegistry} from '../../../services/trigger-driver-registry';
|
||||
import WorkflowEditorTunnel from "../state";
|
||||
|
||||
export interface TriggersUpdatedArgs {
|
||||
triggers: Array<Trigger>;
|
||||
}
|
||||
|
||||
export interface TriggerSelectedArgs {
|
||||
trigger: Trigger;
|
||||
applyChanges: (trigger: Trigger) => void;
|
||||
deleteTrigger: (trigger: Trigger) => void;
|
||||
}
|
||||
|
||||
export interface TriggerDeselectedArgs {
|
||||
trigger: Trigger;
|
||||
}
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-trigger-container',
|
||||
})
|
||||
export class TriggerContainer {
|
||||
private renderedTriggers: Map<string, string> = new Map<string, string>();
|
||||
|
||||
@Prop({mutable: true}) public triggerDescriptors: Array<TriggerDescriptor> = [];
|
||||
@Prop({mutable: true}) public triggers: Array<Trigger> = [];
|
||||
@Prop() public interactiveMode: boolean = true;
|
||||
@Event() public triggersUpdated: EventEmitter<TriggersUpdatedArgs>;
|
||||
@Event() triggerSelected: EventEmitter<TriggerSelectedArgs>;
|
||||
@Event() triggerDeselected: EventEmitter<TriggerDeselectedArgs>;
|
||||
@State() private selectedTriggers: Array<string> = [];
|
||||
|
||||
@Method()
|
||||
public async deselectAll(): Promise<void> {
|
||||
this.selectedTriggers = [];
|
||||
}
|
||||
|
||||
public componentWillRender() {
|
||||
const triggerDescriptors = this.triggerDescriptors;
|
||||
const triggers = this.triggers;
|
||||
const triggerDriverRegistry = Container.get(TriggerDriverRegistry);
|
||||
const renderedTriggers = new Map<string, string>();
|
||||
|
||||
for (const trigger of triggers) {
|
||||
const triggerType = trigger.nodeType;
|
||||
const triggerDescriptor = triggerDescriptors.find(x => x.nodeType == triggerType);
|
||||
const driver = triggerDriverRegistry.createDriver(triggerType);
|
||||
const html = driver.display({triggerDescriptor: triggerDescriptor, trigger: trigger, displayType: 'designer'});
|
||||
|
||||
renderedTriggers.set(trigger.id, html);
|
||||
}
|
||||
|
||||
this.renderedTriggers = renderedTriggers;
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div class="absolute left-0 top-0 right-0 bottom-0 overflow-auto"
|
||||
onDragOver={this.onDragOver}
|
||||
onDrop={e => this.onDrop(e)}>
|
||||
{this.renderTriggers()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderTriggers = () => {
|
||||
const triggers = this.triggers;
|
||||
|
||||
if (triggers.length == 0) {
|
||||
return <div>
|
||||
<div class="border-2 border-dashed m-2 p-2 text-center">
|
||||
<p class="mt-1 text-sm text-gray-600">Place your workflow triggers here to automatically invoke your workflow when a trigger executes.</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
return <div class="flex p-2 pt-4 space-x-4">
|
||||
{triggers.map(this.renderTrigger)}
|
||||
</div>
|
||||
};
|
||||
|
||||
private renderTrigger = (trigger: Trigger) => {
|
||||
const renderedTriggers = this.renderedTriggers;
|
||||
const html = renderedTriggers.get(trigger.id);
|
||||
const isSelected = this.getIsTriggerSelected(trigger);
|
||||
const cssClass = isSelected ? 'border-green-400' : 'border-transparent';
|
||||
return (
|
||||
<div class={`p-1 border-2 border-dashed outline-none ${cssClass}`} tabindex={0}
|
||||
onKeyDown={e => this.onKeyPress(e)}>
|
||||
<div class="flex-none cursor-pointer select-none" onClick={e => this.onTriggerClick(e, trigger)}>
|
||||
<div innerHTML={html}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
private updateTriggers = (triggers: Array<Trigger>) => {
|
||||
this.triggers = triggers;
|
||||
this.triggersUpdated.emit({triggers: triggers});
|
||||
};
|
||||
|
||||
private deleteTrigger = (trigger: Trigger) => {
|
||||
const triggers = this.triggers.filter(x => x != trigger);
|
||||
this.updateTriggers(triggers);
|
||||
};
|
||||
|
||||
private updateTrigger = (trigger: Trigger) => this.updateTriggers([...this.triggers]);
|
||||
private getIsTriggerSelected = (trigger: Trigger) => this.selectedTriggers.findIndex(x => x == trigger.id) >= 0;
|
||||
|
||||
private onDrop = (e: DragEvent) => {
|
||||
const json = e.dataTransfer.getData('trigger-descriptor');
|
||||
const triggerDescriptor: TriggerDescriptor = JSON.parse(json);
|
||||
|
||||
const trigger: Trigger = {
|
||||
id: uuid(),
|
||||
nodeType: triggerDescriptor.nodeType,
|
||||
metadata: {}
|
||||
};
|
||||
|
||||
const triggers = [...this.triggers, trigger];
|
||||
this.updateTriggers(triggers);
|
||||
};
|
||||
|
||||
private onDragOver = (e: DragEvent) => {
|
||||
const isTrigger = e.dataTransfer.types.indexOf('trigger-descriptor') >= 0;
|
||||
if (this.interactiveMode && isTrigger)
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
private onTriggerClick = (e: MouseEvent, trigger: Trigger) => {
|
||||
const isSelected = this.getIsTriggerSelected(trigger);
|
||||
|
||||
if (e.ctrlKey)
|
||||
this.selectedTriggers = isSelected ? this.selectedTriggers.filter(x => x != trigger.id) : [...this.selectedTriggers, trigger.id];
|
||||
else
|
||||
this.selectedTriggers = [trigger.id];
|
||||
|
||||
this.triggerSelected.emit({
|
||||
trigger: trigger,
|
||||
applyChanges: this.updateTrigger,
|
||||
deleteTrigger: this.deleteTrigger
|
||||
});
|
||||
};
|
||||
|
||||
private onKeyPress = (e: KeyboardEvent) => {
|
||||
if (e.key != 'Delete' || !this.interactiveMode)
|
||||
return;
|
||||
|
||||
const selectedTriggers = this.selectedTriggers;
|
||||
const triggers = this.triggers.filter(trigger => selectedTriggers.findIndex(x => x == trigger.id) < 0);
|
||||
this.updateTriggers(triggers);
|
||||
};
|
||||
}
|
||||
|
||||
WorkflowEditorTunnel.injectProps(TriggerContainer, ['triggerDescriptors', 'workflow']);
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
import {Component, Event, EventEmitter, h, Method, Prop, State} from '@stencil/core';
|
||||
import {camelCase} from 'lodash';
|
||||
import WorkflowEditorTunnel from '../state';
|
||||
import {
|
||||
DefaultActions, InputDescriptor,
|
||||
RenderNodePropContext,
|
||||
RenderNodePropsContext,
|
||||
TabChangedArgs,
|
||||
TabDefinition,
|
||||
Trigger,
|
||||
TriggerDescriptor
|
||||
} from '../../../models';
|
||||
import {FormEntry} from "../../shared/forms/form-entry";
|
||||
import {InputDriverRegistry} from "../../../services/input-driver-registry";
|
||||
import {Container} from "typedi";
|
||||
import {NodeInputContext} from "../../../services/node-input-driver";
|
||||
|
||||
export interface TriggerUpdatedArgs {
|
||||
trigger: Trigger;
|
||||
}
|
||||
|
||||
export interface DeleteTriggerRequestedArgs {
|
||||
trigger: Trigger;
|
||||
}
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-trigger-properties-editor',
|
||||
})
|
||||
export class TriggerPropertiesEditor {
|
||||
private slideOverPanel: HTMLElsaSlideOverPanelElement;
|
||||
private renderContext: RenderNodePropsContext;
|
||||
private readonly inputDriverRegistry: InputDriverRegistry;
|
||||
|
||||
constructor() {
|
||||
this.inputDriverRegistry = Container.get(InputDriverRegistry);
|
||||
}
|
||||
|
||||
@Prop({mutable: true}) triggerDescriptors: Array<TriggerDescriptor> = [];
|
||||
@Prop({mutable: true}) trigger?: Trigger;
|
||||
|
||||
@Event() triggerUpdated: EventEmitter<TriggerUpdatedArgs>;
|
||||
@Event() deleteTriggerRequested: EventEmitter<DeleteTriggerRequestedArgs>;
|
||||
|
||||
@State() private selectedTabIndex: number = 0;
|
||||
|
||||
@Method()
|
||||
public async show(): Promise<void> {
|
||||
await this.slideOverPanel.show();
|
||||
}
|
||||
|
||||
@Method()
|
||||
public async hide(): Promise<void> {
|
||||
await this.slideOverPanel.hide();
|
||||
}
|
||||
|
||||
public componentWillRender() {
|
||||
const trigger = this.trigger;
|
||||
const triggerDescriptor = this.findDescriptor();
|
||||
const title = triggerDescriptor?.displayName ?? triggerDescriptor?.nodeType ?? 'Unknown Trigger';
|
||||
const driverRegistry = this.inputDriverRegistry;
|
||||
|
||||
const renderPropertyContexts: Array<RenderNodePropContext> = triggerDescriptor.inputProperties.map(inputDescriptor => {
|
||||
const renderInputContext: NodeInputContext = {
|
||||
node: trigger,
|
||||
nodeDescriptor: triggerDescriptor,
|
||||
inputDescriptor,
|
||||
notifyInputChanged: () => this.triggerUpdated.emit({trigger}),
|
||||
inputChanged: (v, s) => this.onPropertyEditorChanged(inputDescriptor, v, s)
|
||||
};
|
||||
|
||||
const driver = driverRegistry.get(renderInputContext);
|
||||
const control = driver?.renderInput(renderInputContext);
|
||||
|
||||
return {
|
||||
inputContext: renderInputContext,
|
||||
inputControl: control,
|
||||
}
|
||||
});
|
||||
|
||||
this.renderContext = {
|
||||
node: trigger,
|
||||
nodeDescriptor: triggerDescriptor,
|
||||
title,
|
||||
properties: renderPropertyContexts
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {nodeDescriptor, title} = this.renderContext;
|
||||
|
||||
const propertiesTab: TabDefinition = {
|
||||
displayText: 'Properties',
|
||||
content: () => this.renderPropertiesTab()
|
||||
};
|
||||
|
||||
const commonTab: TabDefinition = {
|
||||
displayText: 'Common',
|
||||
content: () => this.renderCommonTab()
|
||||
};
|
||||
|
||||
const tabs = !!nodeDescriptor ? [propertiesTab, commonTab] : [];
|
||||
const actions = [DefaultActions.Delete(this.onDeleteTrigger)];
|
||||
|
||||
return (
|
||||
<elsa-form-panel
|
||||
headerText={title} tabs={tabs} selectedTabIndex={this.selectedTabIndex}
|
||||
onSelectedTabIndexChanged={e => this.onSelectedTabIndexChanged(e)}
|
||||
actions={actions}/>
|
||||
);
|
||||
}
|
||||
|
||||
private findDescriptor = (): TriggerDescriptor => !!this.trigger ? this.triggerDescriptors.find(x => x.nodeType == this.trigger.nodeType) : null;
|
||||
|
||||
private onSelectedTabIndexChanged(e: CustomEvent<TabChangedArgs>) {
|
||||
this.selectedTabIndex = e.detail.selectedTabIndex;
|
||||
}
|
||||
|
||||
private onTriggerIdChanged = (e: any) => {
|
||||
const trigger = this.trigger;
|
||||
const inputElement = e.target as HTMLInputElement;
|
||||
|
||||
trigger.id = inputElement.value;
|
||||
this.triggerUpdated.emit({trigger});
|
||||
};
|
||||
|
||||
private onPropertyEditorChanged = (inputDescriptor: InputDescriptor, propertyValue: any, syntax: string) => {
|
||||
const trigger = this.trigger;
|
||||
const propertyName = inputDescriptor.name;
|
||||
const camelCasePropertyName = camelCase(propertyName);
|
||||
|
||||
trigger[camelCasePropertyName] = {
|
||||
type: inputDescriptor.type,
|
||||
expression: {
|
||||
type: syntax,
|
||||
value: propertyValue
|
||||
}
|
||||
};
|
||||
|
||||
this.triggerUpdated.emit({trigger});
|
||||
}
|
||||
|
||||
private onDeleteTrigger = () => this.deleteTriggerRequested.emit({trigger: this.trigger});
|
||||
|
||||
private renderPropertiesTab = () => {
|
||||
const {node, properties} = this.renderContext;
|
||||
const activityId = node.id;
|
||||
|
||||
return <div>
|
||||
<FormEntry fieldId="ActivityId" label="ID" hint="The ID of the activity.">
|
||||
<input type="text" name="ActivityId" id="ActivityId" value={activityId} onChange={e => this.onTriggerIdChanged(e)}/>
|
||||
</FormEntry>
|
||||
|
||||
{properties.filter(x => !!x.inputControl).map(propertyContext => {
|
||||
return propertyContext.inputControl;
|
||||
})}
|
||||
</div>
|
||||
};
|
||||
|
||||
private renderCommonTab = () => {
|
||||
return <div>
|
||||
</div>
|
||||
};
|
||||
}
|
||||
|
||||
WorkflowEditorTunnel.injectProps(TriggerPropertiesEditor, ['triggerDescriptors']);
|
||||
|
|
@ -1,25 +1,13 @@
|
|||
$activity-picker-width: 300px;
|
||||
$trigger-panel-height: 76px;
|
||||
$activity-editor-width: 580px;
|
||||
|
||||
elsa-canvas {
|
||||
left: $activity-picker-width;
|
||||
top: $trigger-panel-height;
|
||||
top: 0;
|
||||
right: $activity-editor-width;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
elsa-panel.elsa-trigger-container {
|
||||
left: $activity-picker-width;
|
||||
right: $activity-editor-width;
|
||||
}
|
||||
|
||||
elsa-panel.panel-state-expanded.elsa-trigger-container {
|
||||
left: $activity-picker-width;
|
||||
right: $activity-editor-width;
|
||||
height: $trigger-panel-height;
|
||||
}
|
||||
|
||||
elsa-panel.panel-state-expanded.elsa-activity-picker-container {
|
||||
width: $activity-picker-width;
|
||||
}
|
||||
|
|
@ -39,21 +27,6 @@ elsa-panel.panel-state-expanded.elsa-activity-editor-container {
|
|||
elsa-canvas {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
elsa-panel.elsa-trigger-container {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.trigger-container-closed {
|
||||
|
||||
elsa-canvas {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
elsa-trigger-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.object-editor-closed {
|
||||
|
|
@ -65,8 +38,4 @@ elsa-panel.panel-state-expanded.elsa-activity-editor-container {
|
|||
elsa-canvas {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
elsa-panel.elsa-trigger-container {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,15 @@ import {Container} from "typedi";
|
|||
import {PanelPosition, PanelStateChangedArgs} from '../panel/models';
|
||||
import {
|
||||
Activity,
|
||||
ActivityDescriptor, ActivityPropertyChangedEventArgs,
|
||||
ActivitySelectedArgs, ContainerSelectedArgs, EventTypes,
|
||||
GraphUpdatedArgs, Trigger,
|
||||
TriggerDescriptor,
|
||||
Workflow, WorkflowInstance
|
||||
ActivityDescriptor,
|
||||
ActivityPropertyChangedEventArgs,
|
||||
ActivitySelectedArgs,
|
||||
ContainerSelectedArgs,
|
||||
EventTypes,
|
||||
GraphUpdatedArgs,
|
||||
Trigger,
|
||||
Workflow,
|
||||
WorkflowInstance
|
||||
} from '../../../models';
|
||||
import WorkflowEditorTunnel, {WorkflowDesignerState} from '../state';
|
||||
import {
|
||||
|
|
@ -17,8 +21,6 @@ import {
|
|||
DeleteActivityRequestedArgs
|
||||
} from '../activity-properties-editor/activity-properties-editor';
|
||||
import {ActivityDriverRegistry, EventBus} from '../../../services';
|
||||
import {TriggerSelectedArgs, TriggersUpdatedArgs} from '../trigger-container/trigger-container';
|
||||
import {DeleteTriggerRequestedArgs, TriggerUpdatedArgs} from "../trigger-properties-editor/trigger-properties-editor";
|
||||
import {WorkflowPropsUpdatedArgs} from "../workflow-properties-editor/workflow-properties-editor";
|
||||
import {MonacoEditorSettings} from "../../../services/monaco-editor-settings";
|
||||
import {PluginRegistry} from "../../../services/plugin-registry";
|
||||
|
|
@ -37,7 +39,6 @@ export class WorkflowEditor {
|
|||
private canvas: HTMLElsaCanvasElement;
|
||||
private container: HTMLDivElement;
|
||||
private toolbox: HTMLElsaToolboxElement;
|
||||
private triggerContainer: HTMLElsaTriggerContainerElement;
|
||||
private applyActivityChanges: (activity: Activity) => void;
|
||||
private deleteActivity: (activity: Activity) => void;
|
||||
private applyTriggerChanges: (trigger: Trigger) => void;
|
||||
|
|
@ -49,8 +50,7 @@ export class WorkflowEditor {
|
|||
root: null,
|
||||
identity: {id: uuid(), definitionId: uuid(), version: 1},
|
||||
publication: {isLatest: true, isPublished: false},
|
||||
metadata: {},
|
||||
triggers: []
|
||||
metadata: {}
|
||||
};
|
||||
|
||||
private workflowInstance?: WorkflowInstance;
|
||||
|
|
@ -65,11 +65,8 @@ export class WorkflowEditor {
|
|||
@Element() el: HTMLElsaWorkflowEditorElement;
|
||||
@Prop({attribute: 'monaco-lib-path'}) public monacoLibPath: string;
|
||||
@Prop() public activityDescriptors: Array<ActivityDescriptor> = [];
|
||||
@Prop() public triggerDescriptors: Array<TriggerDescriptor> = [];
|
||||
@Event() public workflowUpdated: EventEmitter<WorkflowUpdatedArgs>
|
||||
@State() private selectedActivity?: Activity;
|
||||
@State() private selectedTrigger?: Trigger;
|
||||
@State() private triggers: Array<Trigger> = [];
|
||||
|
||||
private get interactiveMode(): boolean {
|
||||
return !this.workflowInstance;
|
||||
|
|
@ -94,32 +91,15 @@ export class WorkflowEditor {
|
|||
@Listen('containerSelected')
|
||||
private async handleContainerSelected(e: CustomEvent<ContainerSelectedArgs>) {
|
||||
this.selectedActivity = null;
|
||||
this.selectedTrigger = null;
|
||||
await this.triggerContainer.deselectAll();
|
||||
}
|
||||
|
||||
@Listen('activitySelected')
|
||||
private async handleActivitySelected(e: CustomEvent<ActivitySelectedArgs>) {
|
||||
this.selectedActivity = e.detail.activity;
|
||||
this.selectedTrigger = null;
|
||||
await this.triggerContainer.deselectAll();
|
||||
this.applyActivityChanges = e.detail.applyChanges;
|
||||
this.deleteActivity = e.detail.deleteActivity;
|
||||
}
|
||||
|
||||
@Listen('triggerSelected')
|
||||
private async handleTriggerSelected(e: CustomEvent<TriggerSelectedArgs>) {
|
||||
this.selectedTrigger = e.detail.trigger;
|
||||
this.selectedActivity = null;
|
||||
this.applyTriggerChanges = e.detail.applyChanges;
|
||||
this.deleteTrigger = e.detail.deleteTrigger;
|
||||
}
|
||||
|
||||
@Listen('triggerDeselected')
|
||||
private async handleTriggerDeselected(e: CustomEvent<TriggerSelectedArgs>) {
|
||||
this.selectedTrigger = null;
|
||||
}
|
||||
|
||||
@Listen('graphUpdated')
|
||||
private handleGraphUpdated(e: CustomEvent<GraphUpdatedArgs>) {
|
||||
if (this.interactiveMode)
|
||||
|
|
@ -152,14 +132,12 @@ export class WorkflowEditor {
|
|||
@Method()
|
||||
public async importWorkflowMetadata(workflow: Workflow): Promise<void> {
|
||||
this.workflow = workflow;
|
||||
this.triggers = workflow.triggers;
|
||||
}
|
||||
|
||||
public render() {
|
||||
const tunnelState: WorkflowDesignerState = {
|
||||
workflow: this.workflow,
|
||||
activityDescriptors: this.activityDescriptors,
|
||||
triggerDescriptors: this.triggerDescriptors
|
||||
};
|
||||
|
||||
const interactiveMode = this.interactiveMode;
|
||||
|
|
@ -173,17 +151,6 @@ export class WorkflowEditor {
|
|||
onExpandedStateChanged={e => this.onActivityPickerPanelStateChanged(e.detail)}>
|
||||
<elsa-toolbox ref={el => this.toolbox = el}/>
|
||||
</elsa-panel>
|
||||
<elsa-panel
|
||||
class="elsa-trigger-container"
|
||||
onExpandedStateChanged={e => this.onTriggerContainerPanelStateChanged(e.detail)}
|
||||
position={PanelPosition.Top}>
|
||||
<elsa-trigger-container
|
||||
interactiveMode={interactiveMode}
|
||||
triggerDescriptors={this.triggerDescriptors}
|
||||
triggers={this.triggers}
|
||||
onTriggersUpdated={e => this.onTriggersUpdated(e.detail)}
|
||||
ref={el => this.triggerContainer = el}/>
|
||||
</elsa-panel>
|
||||
<elsa-canvas
|
||||
class="absolute" ref={el => this.canvas = el}
|
||||
interactiveMode={interactiveMode}
|
||||
|
|
@ -204,12 +171,6 @@ export class WorkflowEditor {
|
|||
}
|
||||
|
||||
private renderSelectedObject = () => {
|
||||
if (!!this.selectedTrigger)
|
||||
return <elsa-trigger-properties-editor
|
||||
trigger={this.selectedTrigger}
|
||||
onTriggerUpdated={e => this.onTriggerUpdated(e)}
|
||||
onDeleteTriggerRequested={e => this.onDeleteTriggerRequested(e)}/>
|
||||
|
||||
if (!!this.selectedActivity)
|
||||
return <elsa-activity-properties-editor
|
||||
activity={this.selectedActivity}
|
||||
|
|
@ -253,14 +214,8 @@ export class WorkflowEditor {
|
|||
}
|
||||
|
||||
private onActivityPickerPanelStateChanged = async (e: PanelStateChangedArgs) => await this.updateContainerLayout('activity-picker-closed', e.expanded)
|
||||
private onTriggerContainerPanelStateChanged = async (e: PanelStateChangedArgs) => await this.updateContainerLayout('trigger-container-closed', e.expanded)
|
||||
private onActivityEditorPanelStateChanged = async (e: PanelStateChangedArgs) => await this.updateContainerLayout('object-editor-closed', e.expanded)
|
||||
|
||||
private onTriggersUpdated = async (e: TriggersUpdatedArgs) => {
|
||||
this.workflow.triggers = e.triggers;
|
||||
await this.saveChangesDebounced();
|
||||
};
|
||||
|
||||
private onDragOver = (e: DragEvent) => {
|
||||
if (this.interactiveMode)
|
||||
e.preventDefault();
|
||||
|
|
@ -280,21 +235,10 @@ export class WorkflowEditor {
|
|||
this.saveChangesDebounced();
|
||||
}
|
||||
|
||||
private onTriggerUpdated = (e: CustomEvent<TriggerUpdatedArgs>) => {
|
||||
const updatedTrigger = e.detail.trigger;
|
||||
this.applyTriggerChanges(updatedTrigger);
|
||||
this.saveChangesDebounced();
|
||||
}
|
||||
|
||||
private onWorkflowPropsUpdated = (e: CustomEvent<WorkflowPropsUpdatedArgs>) => this.saveChangesDebounced()
|
||||
|
||||
private onDeleteActivityRequested = (e: CustomEvent<DeleteActivityRequestedArgs>) => {
|
||||
this.deleteActivity(e.detail.activity);
|
||||
this.selectedActivity = null;
|
||||
};
|
||||
|
||||
private onDeleteTriggerRequested = (e: CustomEvent<DeleteTriggerRequestedArgs>) => {
|
||||
this.deleteTrigger(e.detail.trigger);
|
||||
this.selectedTrigger = null;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import {Component, Element, h, Listen, Prop, Watch} from '@stencil/core';
|
|||
import 'reflect-metadata';
|
||||
import {Container} from 'typedi';
|
||||
import {ElsaApiClientProvider, ElsaClient, SaveWorkflowRequest, ServerSettings} from '../../../services';
|
||||
import {ActivityDescriptor, TriggerDescriptor, VersionOptions, Workflow, WorkflowInstanceSummary, WorkflowSummary} from '../../../models';
|
||||
import {ActivityDescriptor, VersionOptions, Workflow, WorkflowInstanceSummary, WorkflowSummary} from '../../../models';
|
||||
import {WorkflowUpdatedArgs} from '../../designer/workflow-editor/workflow-editor';
|
||||
import {PublishClickedArgs} from "../../toolbar/workflow-publish-button/workflow-publish-button";
|
||||
import {MonacoEditorSettings} from "../../../services/monaco-editor-settings";
|
||||
|
|
@ -12,7 +12,6 @@ import {MonacoEditorSettings} from "../../../services/monaco-editor-settings";
|
|||
})
|
||||
export class Studio {
|
||||
private activityDescriptors: Array<ActivityDescriptor>;
|
||||
private triggerDescriptors: Array<TriggerDescriptor>;
|
||||
private elsaClient: ElsaClient;
|
||||
private workflowEditorElement?: HTMLElsaWorkflowEditorElement;
|
||||
|
||||
|
|
@ -88,12 +87,10 @@ export class Studio {
|
|||
const elsaClientProvider = Container.get(ElsaApiClientProvider);
|
||||
this.elsaClient = await elsaClientProvider.getClient();
|
||||
this.activityDescriptors = await this.elsaClient.descriptors.activities.list();
|
||||
this.triggerDescriptors = await this.elsaClient.descriptors.triggers.list();
|
||||
this.workflowEditorElement = this.el.getElementsByTagName('elsa-workflow-editor')[0] as HTMLElsaWorkflowEditorElement;
|
||||
|
||||
if (!!this.workflowEditorElement) {
|
||||
this.workflowEditorElement.activityDescriptors = this.activityDescriptors;
|
||||
this.workflowEditorElement.triggerDescriptors = this.triggerDescriptors;
|
||||
this.workflowEditorElement.monacoLibPath = this.monacoLibPath;
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +105,6 @@ export class Studio {
|
|||
name: workflow.metadata.name,
|
||||
description: workflow.metadata.description,
|
||||
publish: publish,
|
||||
triggers: workflow.triggers,
|
||||
root: workflow.root
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
import {TriggerDisplayContext, TriggerDriver} from "../../services/trigger-driver";
|
||||
|
||||
export class DefaultTriggerDriver implements TriggerDriver {
|
||||
display(context: TriggerDisplayContext): any {
|
||||
const triggerDescriptor = context.triggerDescriptor;
|
||||
const text = triggerDescriptor?.displayName;
|
||||
const borderColor = 'border-green-600';
|
||||
const backgroundColor = 'bg-green-400';
|
||||
const iconBackgroundColor = 'bg-green-500';
|
||||
|
||||
return (`
|
||||
<div>
|
||||
<div class="activity-wrapper border ${borderColor} ${backgroundColor} rounded text-white overflow-hidden">
|
||||
<div class="flex flex-row">
|
||||
<div class="flex flex-shrink items-center ${iconBackgroundColor}">
|
||||
<div class="px-2 py-1">
|
||||
<svg class="h-6 w-6 text-white" width="24" height="24" viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M7 18a4.6 4.4 0 0 1 0 -9h0a5 4.5 0 0 1 11 2h1a3.5 3.5 0 0 1 0 7h-12"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="px-4 py-1">
|
||||
${text}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
<!--Use the studio shell component to handle automatic interaction with the Elsa Server API-->
|
||||
<elsa-studio server="https://localhost:5001" monaco-lib-path="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.31.1/min">
|
||||
<elsa-workflow-toolbar></elsa-workflow-toolbar>
|
||||
<div class="absolute inset-0" style="top: 63px;">
|
||||
<div class="absolute inset-0" style="top: 64px;">
|
||||
<elsa-workflow-editor></elsa-workflow-editor>
|
||||
</div>
|
||||
<!-- <elsa-workflow-editor></elsa-workflow-editor>-->
|
||||
|
|
|
|||
|
|
@ -18,13 +18,6 @@ export interface ActivityDescriptor extends NodeDescriptor {
|
|||
outPorts: Array<Port>;
|
||||
}
|
||||
|
||||
export interface TriggerDescriptor extends NodeDescriptor {
|
||||
}
|
||||
|
||||
export interface TriggerDescriptorResponse {
|
||||
triggerDescriptors: Array<TriggerDescriptor>;
|
||||
}
|
||||
|
||||
export enum ActivityTraits {
|
||||
Action = 1,
|
||||
Trigger = 2
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ export interface Node {
|
|||
[name: string]: any;
|
||||
}
|
||||
|
||||
export interface Trigger extends Node {
|
||||
export interface Activity extends Node {
|
||||
}
|
||||
|
||||
export interface Activity extends Node {
|
||||
export interface Trigger extends Activity {
|
||||
}
|
||||
|
||||
export interface Container extends Activity {
|
||||
|
|
@ -36,7 +36,6 @@ export interface Workflow {
|
|||
publication: WorkflowPublication;
|
||||
metadata: WorkflowMetadata;
|
||||
root: Activity;
|
||||
triggers: Array<Trigger>;
|
||||
}
|
||||
|
||||
export interface WorkflowMetadata {
|
||||
|
|
|
|||
|
|
@ -13,13 +13,12 @@ import {
|
|||
PagedList,
|
||||
SelectList,
|
||||
Trigger,
|
||||
TriggerDescriptor,
|
||||
TriggerDescriptorResponse, VersionOptions,
|
||||
VersionOptions,
|
||||
Workflow, WorkflowInstance, WorkflowInstanceSummary, WorkflowStatus, WorkflowSummary
|
||||
} from '../models';
|
||||
import 'reflect-metadata';
|
||||
import {ServerSettings} from './server-settings';
|
||||
import {getVersionOptionsString} from "../utils/utils";
|
||||
import {getVersionOptionsString} from "../utils";
|
||||
|
||||
function serializeQueryString(queryString: object): string {
|
||||
const filteredItems = _(queryString).omitBy(_.isUndefined).omitBy(_.isNull).value();
|
||||
|
|
@ -54,12 +53,6 @@ export async function createElsaClient(serverUrl: string): Promise<ElsaClient> {
|
|||
const response = await httpClient.get<ActivityDescriptorResponse>('api/descriptors/activities');
|
||||
return response.data.activityDescriptors;
|
||||
}
|
||||
},
|
||||
triggers: {
|
||||
async list(): Promise<Array<TriggerDescriptor>> {
|
||||
const response = await httpClient.get<TriggerDescriptorResponse>('api/descriptors/triggers');
|
||||
return response.data.triggerDescriptors;
|
||||
}
|
||||
}
|
||||
},
|
||||
workflows: {
|
||||
|
|
@ -140,17 +133,12 @@ export interface ElsaClient {
|
|||
|
||||
export interface DescriptorsApi {
|
||||
activities: ActivityDescriptorsApi;
|
||||
triggers: TriggerDescriptorsApi;
|
||||
}
|
||||
|
||||
export interface ActivityDescriptorsApi {
|
||||
list(): Promise<Array<ActivityDescriptor>>;
|
||||
}
|
||||
|
||||
export interface TriggerDescriptorsApi {
|
||||
list(): Promise<Array<TriggerDescriptor>>;
|
||||
}
|
||||
|
||||
export interface WorkflowsApi {
|
||||
post(request: SaveWorkflowRequest): Promise<Workflow>;
|
||||
|
||||
|
|
@ -180,7 +168,6 @@ export interface SaveWorkflowRequest {
|
|||
definitionId: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
triggers?: Array<Trigger>;
|
||||
publish: boolean;
|
||||
root?: Activity
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,5 +7,3 @@ export * from './event-bus';
|
|||
export * from './input-control-registry';
|
||||
export * from './input-driver-registry';
|
||||
export * from './server-settings';
|
||||
export * from './trigger-driver';
|
||||
export * from './trigger-driver-registry';
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
import {TriggerDriver, TriggerDriverFactory} from "./trigger-driver";
|
||||
import {Service} from "typedi";
|
||||
import {DefaultTriggerDriver} from "../drivers/trigger/default-trigger-driver";
|
||||
|
||||
@Service()
|
||||
export class TriggerDriverRegistry {
|
||||
private _driverMap: Map<string, TriggerDriverFactory> = new Map<string, TriggerDriverFactory>();
|
||||
private _defaultDriverFactory: TriggerDriverFactory = () => new DefaultTriggerDriver();
|
||||
|
||||
public add(triggerType: string, driverFactory: TriggerDriverFactory) {
|
||||
this._driverMap.set(triggerType, driverFactory);
|
||||
}
|
||||
|
||||
public get(triggerType: string): TriggerDriverFactory {
|
||||
return this._driverMap.get(triggerType);
|
||||
}
|
||||
|
||||
public createDriver(triggerType: string): TriggerDriver {
|
||||
const driverFactory = this.get(triggerType) ?? this._defaultDriverFactory;
|
||||
return driverFactory();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import {Trigger, TriggerDescriptor} from "../models";
|
||||
|
||||
export interface TriggerDisplayContext {
|
||||
triggerDescriptor: TriggerDescriptor;
|
||||
displayType: TriggerDisplayType;
|
||||
trigger?: Trigger;
|
||||
}
|
||||
|
||||
export interface TriggerDriver {
|
||||
display: (context: TriggerDisplayContext) => any;
|
||||
}
|
||||
|
||||
export type TriggerDriverFactory = () => TriggerDriver;
|
||||
|
||||
export type TriggerDisplayType = string | 'designer' | 'picker';
|
||||
|
||||
|
|
@ -5,7 +5,6 @@ GREATER : '>';
|
|||
INCREMENT : '++';
|
||||
DECREMENT : '--';
|
||||
NEW : 'new';
|
||||
TRIGGER : 'trigger';
|
||||
VARIABLE : 'variable';
|
||||
LET : 'let';
|
||||
IF : 'if';
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
using Elsa.Contracts;
|
||||
|
||||
namespace Elsa.Dsl.Interpreters;
|
||||
|
||||
public partial class WorkflowDefinitionBuilderInterpreter
|
||||
{
|
||||
|
||||
public override IWorkflowDefinitionBuilder VisitTrigger(ElsaParser.TriggerContext context)
|
||||
{
|
||||
VisitChildren(context);
|
||||
var trigger = (ITrigger)_object.Get(context.@object());
|
||||
|
||||
_workflowDefinitionBuilder.AddTrigger(trigger);
|
||||
|
||||
return DefaultResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ using Elsa.Modules.AzureServiceBus.Models;
|
|||
namespace Elsa.Modules.AzureServiceBus.Activities;
|
||||
|
||||
[Activity("Azure.ServiceBus.MessageReceived", "Executes when a message is received from the configured queue or topic and subscription", "Azure Service Bus")]
|
||||
public class MessageReceived : TriggerActivity
|
||||
public class MessageReceived : Trigger
|
||||
{
|
||||
internal const string MessageReceivedInputKey = "ReceivedMessage";
|
||||
public Input<string> QueueOrTopic { get; set; } = default!;
|
||||
|
|
@ -33,7 +33,7 @@ public class MessageReceived : TriggerActivity
|
|||
/// </summary>
|
||||
public IFormatter? Formatter { get; set; }
|
||||
|
||||
protected override object GetPayload(TriggerIndexingContext context) => GetPayload(context.ExpressionExecutionContext);
|
||||
protected override object GetTriggerPayload(TriggerIndexingContext context) => GetPayload(context.ExpressionExecutionContext);
|
||||
|
||||
protected override void Execute(ActivityExecutionContext context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ using Elsa.Modules.Http.Models;
|
|||
|
||||
namespace Elsa.Modules.Http;
|
||||
|
||||
public class HttpTrigger : TriggerActivity
|
||||
public class HttpTrigger : Trigger
|
||||
{
|
||||
[Input] public Input<string> Path { get; set; } = default!;
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ public class HttpTrigger : TriggerActivity
|
|||
|
||||
[Output] public Output<HttpRequestModel>? Result { get; set; }
|
||||
|
||||
protected override IEnumerable<object> GetPayloads(TriggerIndexingContext context) => GetHashInputs(context.ExpressionExecutionContext);
|
||||
protected override IEnumerable<object> GetTriggerPayloads(TriggerIndexingContext context) => GetHashInputs(context.ExpressionExecutionContext);
|
||||
protected override void Execute(ActivityExecutionContext context) => context.SetBookmarks(GetHashInputs(context.ExpressionExecutionContext));
|
||||
|
||||
private IEnumerable<object> GetHashInputs(ExpressionExecutionContext context)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public class Timer : Trigger
|
|||
{
|
||||
[Input] public Input<TimeSpan> Interval { get; set; } = default!;
|
||||
|
||||
protected override IEnumerable<object> GetPayloads(TriggerIndexingContext context)
|
||||
protected override IEnumerable<object> GetTriggerPayloads(TriggerIndexingContext context)
|
||||
{
|
||||
var interval = context.ExpressionExecutionContext.Get(Interval);
|
||||
var clock = context.ExpressionExecutionContext.GetRequiredService<ISystemClock>();
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ public class WorkflowDefinition : Entity
|
|||
public DateTime CreatedAt { get; set; }
|
||||
public int Version { get; set; } = 1;
|
||||
public IActivity Root { get; set; } = default!;
|
||||
public ICollection<ITrigger> Triggers { get; set; } = new List<ITrigger>();
|
||||
public ICollection<Variable> Variables { get; set; } = new List<Variable>();
|
||||
public bool IsLatest { get; set; }
|
||||
public bool IsPublished { get; set; }
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ public class WorkflowDefinitionMapper
|
|||
new WorkflowPublication(definition.IsLatest, definition.IsPublished),
|
||||
new WorkflowMetadata(definition.Name, definition.Description, definition.CreatedAt),
|
||||
definition.Root,
|
||||
definition.Triggers,
|
||||
definition.Variables);
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +32,6 @@ public class WorkflowDefinitionMapper
|
|||
definition.Name = metadata.Name;
|
||||
definition.Description = metadata.Description;
|
||||
definition.Root = workflow.Root;
|
||||
definition.Triggers = workflow.Triggers;
|
||||
definition.CreatedAt = metadata.CreatedAt;
|
||||
definition.IsLatest = publication.IsLatest;
|
||||
definition.IsPublished = publication.IsPublished;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ namespace Elsa.Persistence.EntityFrameworkCore.Configuration
|
|||
public void Configure(EntityTypeBuilder<WorkflowDefinition> builder)
|
||||
{
|
||||
builder.Ignore(x => x.Root);
|
||||
builder.Ignore(x => x.Triggers);
|
||||
builder.Property<string>("Data");
|
||||
|
||||
builder.HasIndex(x => new {x.DefinitionId, x.Version}).HasDatabaseName($"IX_{nameof(WorkflowDefinition)}_{nameof(WorkflowDefinition.DefinitionId)}_{nameof(WorkflowDefinition.Version)}").IsUnique();
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ public class WorkflowDefinitionSerializer : IEntitySerializer<WorkflowDefinition
|
|||
var data = new
|
||||
{
|
||||
entity.Root,
|
||||
entity.Triggers
|
||||
};
|
||||
|
||||
var options = _workflowSerializerOptionsProvider.CreatePersistenceOptions();
|
||||
|
|
@ -31,7 +30,7 @@ public class WorkflowDefinitionSerializer : IEntitySerializer<WorkflowDefinition
|
|||
|
||||
public void Deserialize(ElsaDbContext dbContext, WorkflowDefinition entity)
|
||||
{
|
||||
var data = new WorkflowDefinitionState(entity.Root, entity.Triggers);
|
||||
var data = new WorkflowDefinitionState(entity.Root);
|
||||
var json = (string?) dbContext.Entry(entity).Property("Data").CurrentValue;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(json))
|
||||
|
|
@ -41,7 +40,6 @@ public class WorkflowDefinitionSerializer : IEntitySerializer<WorkflowDefinition
|
|||
}
|
||||
|
||||
entity.Root = data.Root;
|
||||
entity.Triggers = data.Triggers;
|
||||
}
|
||||
|
||||
// Can't use records when using System.Text.Json serialization and reference handling. Hence, using a class with default constructor.
|
||||
|
|
@ -51,13 +49,11 @@ public class WorkflowDefinitionSerializer : IEntitySerializer<WorkflowDefinition
|
|||
{
|
||||
}
|
||||
|
||||
public WorkflowDefinitionState(IActivity root, ICollection<ITrigger> triggers)
|
||||
public WorkflowDefinitionState(IActivity root)
|
||||
{
|
||||
Root = root;
|
||||
Triggers = triggers;
|
||||
}
|
||||
|
||||
public IActivity Root { get; init; } = default!;
|
||||
public ICollection<ITrigger> Triggers { get; init; } = default!;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ using Elsa.Runtime.Middleware;
|
|||
|
||||
namespace Elsa.Runtime.Extensions;
|
||||
|
||||
public static class WorkflowExecutionBuilderExtensions
|
||||
public static class WorkflowExecutionPipelineBuilderExtensions
|
||||
{
|
||||
public static IWorkflowExecutionBuilder UsePersistence(this IWorkflowExecutionBuilder builder) => builder.UseMiddleware<PersistWorkflowInstanceMiddleware>();
|
||||
public static IWorkflowExecutionBuilder UseWorkflowExecutionEvents(this IWorkflowExecutionBuilder builder) => builder.UseMiddleware<PublishWorkflowExecutionEventsMiddleware>();
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ using Elsa.Persistence.Entities;
|
|||
using Elsa.Persistence.Requests;
|
||||
using Elsa.Runtime.Contracts;
|
||||
using Elsa.Runtime.Models;
|
||||
using Elsa.Runtime.Notifications;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Elsa.Runtime.Services;
|
||||
|
|
@ -26,6 +25,7 @@ namespace Elsa.Runtime.Services;
|
|||
public class TriggerIndexer : ITriggerIndexer
|
||||
{
|
||||
private readonly IWorkflowRegistry _workflowRegistry;
|
||||
private readonly IActivityWalker _activityWalker;
|
||||
private readonly IExpressionEvaluator _expressionEvaluator;
|
||||
private readonly IIdentityGenerator _identityGenerator;
|
||||
private readonly IRequestSender _requestSender;
|
||||
|
|
@ -37,6 +37,7 @@ public class TriggerIndexer : ITriggerIndexer
|
|||
|
||||
public TriggerIndexer(
|
||||
IWorkflowRegistry workflowRegistry,
|
||||
IActivityWalker activityWalker,
|
||||
IExpressionEvaluator expressionEvaluator,
|
||||
IIdentityGenerator identityGenerator,
|
||||
IRequestSender requestSender,
|
||||
|
|
@ -47,6 +48,7 @@ public class TriggerIndexer : ITriggerIndexer
|
|||
ILogger<TriggerIndexer> logger)
|
||||
{
|
||||
_workflowRegistry = workflowRegistry;
|
||||
_activityWalker = activityWalker;
|
||||
_expressionEvaluator = expressionEvaluator;
|
||||
_identityGenerator = identityGenerator;
|
||||
_requestSender = requestSender;
|
||||
|
|
@ -112,11 +114,11 @@ public class TriggerIndexer : ITriggerIndexer
|
|||
private async IAsyncEnumerable<WorkflowTrigger> GetTriggersAsync(Workflow workflow, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
var context = new WorkflowIndexingContext(workflow);
|
||||
var triggerSources = workflow.Triggers;
|
||||
var triggerNodes = _activityWalker.Walk(workflow.Root).Flatten().Where(x => x.Activity is ITrigger { TriggerMode: TriggerMode.WorkflowDefinition }).ToList();
|
||||
|
||||
foreach (var triggerSource in triggerSources)
|
||||
foreach (var triggerNode in triggerNodes)
|
||||
{
|
||||
var triggers = await GetTriggersAsync(workflow, context, triggerSource, cancellationToken);
|
||||
var triggers = await GetTriggersAsync(workflow, context, (ITrigger)triggerNode.Activity, cancellationToken);
|
||||
|
||||
foreach (var trigger in triggers)
|
||||
yield return trigger;
|
||||
|
|
@ -167,7 +169,7 @@ public class TriggerIndexer : ITriggerIndexer
|
|||
{
|
||||
try
|
||||
{
|
||||
return (await trigger.GetPayloadsAsync(context, cancellationToken)).ToList();
|
||||
return (await trigger.GetTriggerPayloadsAsync(context, cancellationToken)).ToList();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ using Elsa.Modules.Scheduling.Triggers;
|
|||
using Elsa.Persistence.EntityFrameworkCore.Extensions;
|
||||
using Elsa.Persistence.EntityFrameworkCore.Sqlite;
|
||||
using Elsa.Pipelines.WorkflowExecution.Components;
|
||||
using Elsa.Runtime.Middleware;
|
||||
using Elsa.Runtime.Extensions;
|
||||
using Elsa.Runtime.ProtoActor.Extensions;
|
||||
using Elsa.Samples.Web1.Activities;
|
||||
using Elsa.Samples.Web1.Workflows;
|
||||
|
|
@ -28,7 +28,6 @@ using Microsoft.AspNetCore.Builder;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using WorkflowExecutionBuilderExtensions = Elsa.Runtime.Extensions.WorkflowExecutionBuilderExtensions;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
|
|
@ -70,16 +69,12 @@ services
|
|||
.AddActivity<HttpTrigger>()
|
||||
.AddActivity<Flowchart>()
|
||||
.AddActivity<Delay>()
|
||||
.AddActivity<Timer>()
|
||||
.AddActivity<ForEach>()
|
||||
.AddActivity<Switch>()
|
||||
.AddActivity<SendMessage>()
|
||||
;
|
||||
|
||||
// Register available triggers.
|
||||
services
|
||||
.AddTrigger<HttpTrigger>()
|
||||
.AddTrigger<Timer>();
|
||||
|
||||
// Register scripting languages.
|
||||
services
|
||||
.AddJavaScriptExpressions()
|
||||
|
|
@ -97,8 +92,12 @@ wellKnownTypeRegistry.RegisterType<bool>("boolean");
|
|||
wellKnownTypeRegistry.RegisterType<string>("string");
|
||||
|
||||
// Configure workflow engine execution pipeline.
|
||||
serviceProvider.ConfigureDefaultWorkflowExecutionPipeline(pipeline => WorkflowExecutionBuilderExtensions.UseWorkflowExecutionEvents(WorkflowExecutionBuilderExtensions.UseWorkflowExecutionLogPersistence(WorkflowExecutionBuilderExtensions.UsePersistence(pipeline)))
|
||||
.UseActivityScheduler()
|
||||
serviceProvider.ConfigureDefaultWorkflowExecutionPipeline(pipeline =>
|
||||
pipeline
|
||||
.UseWorkflowExecutionEvents()
|
||||
.UseWorkflowExecutionLogPersistence()
|
||||
.UsePersistence()
|
||||
.UseActivityScheduler()
|
||||
);
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
|
|
|
|||
|
|
@ -15,18 +15,16 @@ public class ForkedHttpWorkflow : IWorkflow
|
|||
{
|
||||
public void Build(IWorkflowDefinitionBuilder workflow)
|
||||
{
|
||||
// Add triggers.
|
||||
workflow.AddTrigger(new HttpTrigger
|
||||
{
|
||||
Path = new Input<string>("/fork"),
|
||||
SupportedMethods = new Input<ICollection<string>>(new[] { HttpMethods.Get })
|
||||
});
|
||||
|
||||
// Setup workflow graph.
|
||||
workflow.WithRoot(new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new HttpTrigger
|
||||
{
|
||||
Path = new Input<string>("/fork"),
|
||||
SupportedMethods = new Input<ICollection<string>>(new[] { HttpMethods.Get })
|
||||
},
|
||||
new Fork
|
||||
{
|
||||
JoinMode = new Input<JoinMode>(JoinMode.WaitAll),
|
||||
|
|
|
|||
|
|
@ -19,18 +19,16 @@ public class HttpWorkflow : IWorkflow
|
|||
|
||||
public void Build(IWorkflowDefinitionBuilder workflow)
|
||||
{
|
||||
// Add triggers.
|
||||
workflow.AddTrigger(new HttpTrigger
|
||||
{
|
||||
Path = new Input<string>("/hello-world"),
|
||||
SupportedMethods = new Input<ICollection<string>>(new[] { HttpMethods.Get })
|
||||
});
|
||||
|
||||
// Setup workflow graph.
|
||||
workflow.WithRoot(new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new HttpTrigger
|
||||
{
|
||||
Path = new Input<string>("/hello-world"),
|
||||
SupportedMethods = new Input<ICollection<string>>(new[] { HttpMethods.Get })
|
||||
},
|
||||
new If
|
||||
{
|
||||
Condition = new Input<bool>(true),
|
||||
|
|
|
|||
|
|
@ -14,20 +14,19 @@ public class ReceiveMessageWorkflow : IWorkflow
|
|||
{
|
||||
public void Build(IWorkflowDefinitionBuilder workflow)
|
||||
{
|
||||
// var receivedMessage = new Variable<string>();
|
||||
// workflow.Variables.Add(receivedMessage);
|
||||
|
||||
workflow.AddTrigger(new MessageReceived
|
||||
{
|
||||
QueueOrTopic = new Input<string>("inbox"),
|
||||
//ReceivedMessageBody = new Output<object>(receivedMessage)
|
||||
});
|
||||
var receivedMessage = new Variable<string>();
|
||||
|
||||
workflow.WithRoot(new Sequence
|
||||
{
|
||||
Variables = { receivedMessage },
|
||||
Activities =
|
||||
{
|
||||
new WriteLine(context => $"Message received: {context.Input}")
|
||||
new MessageReceived
|
||||
{
|
||||
QueueOrTopic = new Input<string>("inbox"),
|
||||
ReceivedMessageBody = new Output<object>(receivedMessage)
|
||||
},
|
||||
new WriteLine(context => $"Message received: {receivedMessage.Get(context)}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class Program
|
|||
var workflow13 = new Func<IActivity>(BlockingParallelForEachWorkflow.Create);
|
||||
var workflow14 = new Func<IActivity>(FlowchartWorkflow.Create);
|
||||
|
||||
var workflowFactory = workflow1;
|
||||
var workflowFactory = workflow10;
|
||||
var workflowGraph = workflowFactory();
|
||||
var workflow = Workflow.FromActivity(workflowGraph);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue