From 2876bb65bcb6e3101cbbd17f6115a275f316722a Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Thu, 24 Nov 2022 16:03:35 +0100 Subject: [PATCH] Add FlowNode activity --- .../Elsa.WorkflowServer.Web/Program.cs | 22 +++---------- .../components/icons/activities/default.tsx | 10 ++++++ .../components/icons/activities/flow-node.tsx | 8 +++++ ...send-http-request.tsx => http-request.tsx} | 2 +- ...te-http-response.tsx => http-response.tsx} | 2 +- .../src/components/icons/activities/index.tsx | 19 +++++++---- .../flowchart/default-activity-template.tsx | 6 ++-- .../src/modules/flowchart/flowchart.tsx | 5 ++- .../modules/flowchart/workflow-navigator.tsx | 3 +- .../src/services/activity-icon-registry.tsx | 32 ++++++++++--------- .../Flowchart/Activities/FlowNode.cs | 23 +++++++++++++ 11 files changed, 86 insertions(+), 46 deletions(-) create mode 100644 src/designer/elsa-workflows-designer/src/components/icons/activities/default.tsx create mode 100644 src/designer/elsa-workflows-designer/src/components/icons/activities/flow-node.tsx rename src/designer/elsa-workflows-designer/src/components/icons/activities/{send-http-request.tsx => http-request.tsx} (86%) rename src/designer/elsa-workflows-designer/src/components/icons/activities/{write-http-response.tsx => http-response.tsx} (84%) create mode 100644 src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowNode.cs diff --git a/src/bundles/Elsa.WorkflowServer.Web/Program.cs b/src/bundles/Elsa.WorkflowServer.Web/Program.cs index 1c1da9794..0514b36bc 100644 --- a/src/bundles/Elsa.WorkflowServer.Web/Program.cs +++ b/src/bundles/Elsa.WorkflowServer.Web/Program.cs @@ -55,23 +55,11 @@ services .AddElsa(elsa => elsa .UseWorkflowManagement(management => management .UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString)) - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() - .AddActivity() + .AddActivitiesFrom() + .AddActivitiesFrom() + .AddActivitiesFrom() + .AddActivitiesFrom() + .AddActivitiesFrom() ) .Use(identity => { diff --git a/src/designer/elsa-workflows-designer/src/components/icons/activities/default.tsx b/src/designer/elsa-workflows-designer/src/components/icons/activities/default.tsx new file mode 100644 index 000000000..bd105deab --- /dev/null +++ b/src/designer/elsa-workflows-designer/src/components/icons/activities/default.tsx @@ -0,0 +1,10 @@ +import {FunctionalComponent, h} from '@stencil/core'; +import {ActivityIconSettings, getActivityIconCssClass} from "./models"; + +export const DefaultIcon: FunctionalComponent = (settings) => ( + + + + +); diff --git a/src/designer/elsa-workflows-designer/src/components/icons/activities/flow-node.tsx b/src/designer/elsa-workflows-designer/src/components/icons/activities/flow-node.tsx new file mode 100644 index 000000000..c1704d6e4 --- /dev/null +++ b/src/designer/elsa-workflows-designer/src/components/icons/activities/flow-node.tsx @@ -0,0 +1,8 @@ +import {FunctionalComponent, h} from '@stencil/core'; +import {ActivityIconSettings, getActivityIconCssClass} from "./models"; + +export const FlowNodeIcon: FunctionalComponent = (settings) => ( + + + +); diff --git a/src/designer/elsa-workflows-designer/src/components/icons/activities/send-http-request.tsx b/src/designer/elsa-workflows-designer/src/components/icons/activities/http-request.tsx similarity index 86% rename from src/designer/elsa-workflows-designer/src/components/icons/activities/send-http-request.tsx rename to src/designer/elsa-workflows-designer/src/components/icons/activities/http-request.tsx index e1263e568..94497c75e 100644 --- a/src/designer/elsa-workflows-designer/src/components/icons/activities/send-http-request.tsx +++ b/src/designer/elsa-workflows-designer/src/components/icons/activities/http-request.tsx @@ -1,7 +1,7 @@ import {FunctionalComponent, h} from '@stencil/core'; import {ActivityIconSettings, getActivityIconCssClass} from "./models"; -export const SendHttpRequestIcon: FunctionalComponent = (settings) => ( +export const HttpRequestIcon: FunctionalComponent = (settings) => ( diff --git a/src/designer/elsa-workflows-designer/src/components/icons/activities/write-http-response.tsx b/src/designer/elsa-workflows-designer/src/components/icons/activities/http-response.tsx similarity index 84% rename from src/designer/elsa-workflows-designer/src/components/icons/activities/write-http-response.tsx rename to src/designer/elsa-workflows-designer/src/components/icons/activities/http-response.tsx index 3de5a549e..74e0ba3db 100644 --- a/src/designer/elsa-workflows-designer/src/components/icons/activities/write-http-response.tsx +++ b/src/designer/elsa-workflows-designer/src/components/icons/activities/http-response.tsx @@ -1,7 +1,7 @@ import {FunctionalComponent, h} from '@stencil/core'; import {ActivityIconSettings, getActivityIconCssClass} from "./models"; -export const WriteHttpResponseIcon: FunctionalComponent = (settings) => ( +export const HttpResponseIcon: FunctionalComponent = (settings) => ( diff --git a/src/designer/elsa-workflows-designer/src/components/icons/activities/index.tsx b/src/designer/elsa-workflows-designer/src/components/icons/activities/index.tsx index 5304f0bb2..36eb7980a 100644 --- a/src/designer/elsa-workflows-designer/src/components/icons/activities/index.tsx +++ b/src/designer/elsa-workflows-designer/src/components/icons/activities/index.tsx @@ -1,12 +1,17 @@ +export * from "./default"; +export * from "./delay"; export * from "./event"; -export * from "./http-endpoint"; -export * from "./write-line"; -export * from "./read-line"; -export * from "./if"; export * from "./flow-decision"; +export * from "./flow-join"; +export * from "./flow-node"; export * from "./flowchart"; export * from "./foreach"; -export * from "./delay"; -export * from "./timer"; -export * from "./run-javascript"; +export * from "./http-endpoint"; +export * from "./http-request"; +export * from "./http-response"; +export * from "./if"; export * from "./models"; +export * from "./read-line"; +export * from "./run-javascript"; +export * from "./timer"; +export * from "./write-line"; diff --git a/src/designer/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx b/src/designer/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx index 752af8211..c4a56cc3e 100644 --- a/src/designer/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/flowchart/default-activity-template.tsx @@ -1,5 +1,5 @@ import {Component, h, Prop, State, Event, EventEmitter, Listen, Element} from "@stencil/core"; -import {ActivityIcon, ActivityIconRegistry, PortProviderRegistry} from "../../services"; +import {ActivityIconProducer, ActivityIconRegistry, PortProviderRegistry} from "../../services"; import {Container} from "typedi"; import {Activity, ActivityDescriptor, ActivityKind, ActivitySelectedArgs, ChildActivitySelectedArgs, EditChildActivityArgs, Port, PortMode} from "../../models"; import descriptorsStore from "../../data/descriptors-store"; @@ -14,7 +14,7 @@ export class DefaultActivityTemplate { private readonly iconRegistry: ActivityIconRegistry; private readonly portProviderRegistry: PortProviderRegistry; private activityDescriptor: ActivityDescriptor; - private icon: ActivityIcon; + private icon: ActivityIconProducer; private portElements: Array = []; constructor() { @@ -90,7 +90,7 @@ export class DefaultActivityTemplate { ) } - private renderIcon = (icon?: ActivityIcon): string => { + private renderIcon = (icon?: ActivityIconProducer): string => { const iconCssClass = this.displayTypeIsPicker ? 'px-2' : 'px-4'; if (!icon) diff --git a/src/designer/elsa-workflows-designer/src/modules/flowchart/flowchart.tsx b/src/designer/elsa-workflows-designer/src/modules/flowchart/flowchart.tsx index 3b14fe49e..e3e23e1a9 100644 --- a/src/designer/elsa-workflows-designer/src/modules/flowchart/flowchart.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/flowchart/flowchart.tsx @@ -406,7 +406,9 @@ export class FlowchartComponent implements ContainerActivityComponent { this.activity = flowchart; this.activityLookup = createActivityLookup(activityNodes); - this.currentPath = [{activityId: flowchart.id, portName: null, index: 0}]; + + if(!this.currentPath || this.currentPath.length == 0) + this.currentPath = [{activityId: flowchart.id, portName: null, index: 0}]; await this.setupGraph(flowchart); }; @@ -704,6 +706,7 @@ export class FlowchartComponent implements ContainerActivityComponent { const path = this.currentPath; const index = path.indexOf(item); + debugger; this.currentPath = path.slice(0, index + 1); if (!!item.portName) { diff --git a/src/designer/elsa-workflows-designer/src/modules/flowchart/workflow-navigator.tsx b/src/designer/elsa-workflows-designer/src/modules/flowchart/workflow-navigator.tsx index f68122e0b..b4db23240 100644 --- a/src/designer/elsa-workflows-designer/src/modules/flowchart/workflow-navigator.tsx +++ b/src/designer/elsa-workflows-designer/src/modules/flowchart/workflow-navigator.tsx @@ -20,6 +20,7 @@ export class WorkflowNavigator { @Prop() items: Array = []; @Prop() flowchart: Flowchart; + @Event() navigate: EventEmitter; render() { @@ -47,7 +48,7 @@ export class WorkflowNavigator { const activityId = item.activityId; const activity = nodes.find(x => x.activity.id == activityId).activity; const activityDescriptor = descriptorsStore.activityDescriptors.find(x => x.type == activity.type); - const icon = this.iconRegistry.get(activity.type)(); + const icon = this.iconRegistry.getOrDefault(activity.type)(); const listElements = []; const isLastItem = index == this.items.length - 1; diff --git a/src/designer/elsa-workflows-designer/src/services/activity-icon-registry.tsx b/src/designer/elsa-workflows-designer/src/services/activity-icon-registry.tsx index c7ea5c726..b92a9e109 100644 --- a/src/designer/elsa-workflows-designer/src/services/activity-icon-registry.tsx +++ b/src/designer/elsa-workflows-designer/src/services/activity-icon-registry.tsx @@ -3,36 +3,33 @@ import 'reflect-metadata'; import {Service} from "typedi"; import { - DelayIcon, + DefaultIcon, + DelayIcon, TimerIcon, EventIcon, - FlowchartIcon, FlowDecisionIcon, + FlowchartIcon, FlowDecisionIcon, FlowJoinIcon, FlowNodeIcon, ForEachIcon, - HttpEndpointIcon, IfIcon, - ReadLineIcon, + ReadLineIcon, WriteLineIcon, RunJavaScriptIcon, - TimerIcon, - WriteLineIcon + HttpEndpointIcon, HttpResponseIcon, HttpRequestIcon } from "../components/icons/activities"; -import {WriteHttpResponseIcon} from "../components/icons/activities/write-http-response"; -import {FlowJoinIcon} from "../components/icons/activities/flow-join"; -import {SendHttpRequestIcon} from "../components/icons/activities/send-http-request" export type ActivityType = string; -export type ActivityIcon = (ActivityIconSettings?) => any; +export type ActivityIconProducer = (ActivityIconSettings?) => any; // A registry of activity icons. @Service() export class ActivityIconRegistry { - private iconMap: Map = new Map(); + private iconMap: Map = new Map(); constructor() { + this.add('Elsa.WriteLine', settings => ); this.add('Elsa.WriteLine', settings => ); this.add('Elsa.ReadLine', settings => ); this.add('Elsa.If', settings => ); this.add('Elsa.Flowchart', settings => ); this.add('Elsa.HttpEndpoint', settings => ); - this.add('Elsa.WriteHttpResponse', settings => ); + this.add('Elsa.WriteHttpResponse', settings => ); this.add('Elsa.ForEach', settings => ); this.add('Elsa.Delay', settings => ); this.add('Elsa.Timer', settings => ); @@ -40,17 +37,22 @@ export class ActivityIconRegistry { this.add('Elsa.Event', settings => ); this.add('Elsa.RunJavaScript', settings => ); this.add('Elsa.FlowJoin', settings => ); - this.add('Elsa.SendHttpRequest', settings => ); + this.add('Elsa.FlowNode', settings => ); + this.add('Elsa.SendHttpRequest', settings => ); } - public add(activityType: ActivityType, icon: ActivityIcon) { + public add(activityType: ActivityType, icon: ActivityIconProducer) { this.iconMap.set(activityType, icon); } - public get(activityType: ActivityType): ActivityIcon { + public get(activityType: ActivityType): ActivityIconProducer { return this.iconMap.get(activityType); } + public getOrDefault(activityType: ActivityType): ActivityIconProducer { + return this.iconMap.get(activityType) ?? ((settings) => ); + } + has(activityType: string): boolean { return this.iconMap.has(activityType); } diff --git a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowNode.cs b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowNode.cs new file mode 100644 index 000000000..11461ca59 --- /dev/null +++ b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/FlowNode.cs @@ -0,0 +1,23 @@ +using Elsa.Workflows.Core.Attributes; +using Elsa.Workflows.Core.Models; +using Elsa.Workflows.Core.Services; + +namespace Elsa.Workflows.Core.Activities.Flowchart.Activities; + +/// +/// A simple container that executes the specified activity. +/// +[Activity("Elsa", "Flow", "A simple container that executes the specified activity.")] +public class FlowNode : ActivityBase +{ + /// + /// The activity to execute. + /// + [Port] + public IActivity? Body { get; set; } + + /// + protected override async ValueTask ExecuteAsync(ActivityExecutionContext context) => await context.ScheduleActivityAsync(Body, OnBodyCompletedAsync); + + private async ValueTask OnBodyCompletedAsync(ActivityExecutionContext context, ActivityExecutionContext childContext) => await context.CompleteActivityAsync(); +} \ No newline at end of file