diff --git a/src/designer/elsa-workflows-studio/src/components.d.ts b/src/designer/elsa-workflows-studio/src/components.d.ts index 28f381cea..2bdbd4d4d 100644 --- a/src/designer/elsa-workflows-studio/src/components.d.ts +++ b/src/designer/elsa-workflows-studio/src/components.d.ts @@ -47,6 +47,7 @@ export namespace Components { "activityBorderColor"?: (activity: ActivityModel) => string; "activityContextMenu"?: ActivityContextMenuState; "activityContextMenuButton"?: (activity: ActivityModel) => string; + "activityContextTestMenu"?: ActivityContextMenuState; "connectionContextMenu"?: ActivityContextMenuState; "enableMultipleConnectionsFromSingleSource": boolean; "layoutDirection": LayoutDirection; @@ -776,12 +777,14 @@ declare namespace LocalJSX { "activityBorderColor"?: (activity: ActivityModel) => string; "activityContextMenu"?: ActivityContextMenuState; "activityContextMenuButton"?: (activity: ActivityModel) => string; + "activityContextTestMenu"?: ActivityContextMenuState; "connectionContextMenu"?: ActivityContextMenuState; "enableMultipleConnectionsFromSingleSource"?: boolean; "layoutDirection"?: LayoutDirection; "mode"?: WorkflowDesignerMode; "model"?: WorkflowModel; "onActivityContextMenuButtonClicked"?: (event: CustomEvent) => void; + "onActivityContextMenuButtonTestClicked"?: (event: CustomEvent) => void; "onActivityDeselected"?: (event: CustomEvent) => void; "onActivitySelected"?: (event: CustomEvent) => void; "onConnectionContextMenuButtonClicked"?: (event: CustomEvent) => void; diff --git a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.tsx b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.tsx index e4407bdd4..1d876b270 100644 --- a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.tsx +++ b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/elsa-designer-tree.tsx @@ -46,6 +46,7 @@ export class ElsaWorkflowDesigner { @Prop() activityBorderColor?: (activity: ActivityModel) => string; @Prop() activityContextMenu?: ActivityContextMenuState; @Prop() connectionContextMenu?: ActivityContextMenuState; + @Prop() activityContextTestMenu?: ActivityContextMenuState; @Prop() mode: WorkflowDesignerMode = WorkflowDesignerMode.Edit; @Prop() layoutDirection: LayoutDirection = LayoutDirection.Vertical; @Prop({attribute: 'enable-multiple-connections'}) enableMultipleConnectionsFromSingleSource: boolean; @@ -59,6 +60,7 @@ export class ElsaWorkflowDesigner { @Event() activityDeselected: EventEmitter; @Event() activityContextMenuButtonClicked: EventEmitter; @Event() connectionContextMenuButtonClicked: EventEmitter; + @Event() activityContextMenuButtonTestClicked: EventEmitter; @State() workflowModel: WorkflowModel; @@ -76,6 +78,13 @@ export class ElsaWorkflowDesigner { activity: null, }; + @State() activityContextMenuTestState: ActivityContextMenuState = { + shown: false, + x: 0, + y: 0, + activity: null, + }; + el: HTMLElement; svg: SVGSVGElement; inner: SVGGElement; @@ -104,6 +113,12 @@ export class ElsaWorkflowDesigner { this.connectionContextMenuButtonClicked.emit(state); } + handleContextMenuTestChange(state: ActivityContextMenuState) { + this.ignoreCopyPasteActivities = true; + this.activityContextMenuTestState = state; + this.activityContextMenuButtonTestClicked.emit(state); + } + @Watch('model') handleModelChanged(newValue: WorkflowModel) { this.updateWorkflowModel(newValue, false); @@ -132,6 +147,11 @@ export class ElsaWorkflowDesigner { this.connectionContextMenuState = newValue; } + @Watch('activityContextTestMenu') + handleActivityContextMenuTestChanged(newValue: ActivityContextMenuState) { + this.activityContextMenuTestState = newValue; + } + @Listen('keydown', {target: 'window'}) async handleKeyDown(event: KeyboardEvent) { if (this.ignoreCopyPasteActivities) @@ -809,6 +829,14 @@ export class ElsaWorkflowDesigner { this.handleContextMenuChange({x: evt.clientX, y: evt.clientY, shown: true, activity: node.activity}); }); } + else if (this.mode == WorkflowDesignerMode.Test) { + d3.select(node.elem) + .select('.context-menu-button-container button') + .on('click', evt => { + evt.stopPropagation(); + this.handleContextMenuTestChange({x: evt.clientX, y: evt.clientY, shown: true, activity: node.activity}); + }); + } }); } diff --git a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/elsa-workflow-definition-editor-screen.tsx b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/elsa-workflow-definition-editor-screen.tsx index ce14cc386..c6b7f9979 100644 --- a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/elsa-workflow-definition-editor-screen.tsx +++ b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/elsa-workflow-definition-editor-screen.tsx @@ -11,9 +11,10 @@ import { WorkflowDefinition, WorkflowModel, WorkflowPersistenceBehavior, - WorkflowTestActivityMessage + WorkflowTestActivityMessage, + WorkflowTestUpdateRequest } from "../../../../models"; -import {eventBus, createElsaClient, SaveWorkflowDefinitionRequest} from "../../../../services"; +import {ActivityStats, createElsaClient, eventBus, SaveWorkflowDefinitionRequest} from "../../../../services"; import state from '../../../../utils/store'; import WorkflowEditorTunnel, {WorkflowEditorState} from '../../../../data/workflow-editor'; import DashboardTunnel from "../../../../data/dashboard"; @@ -23,6 +24,8 @@ import {registerClickOutside} from "stencil-click-outside"; import {i18n} from "i18next"; import {loadTranslations} from "../../../i18n/i18n-loader"; import {resources} from "./localizations"; +import * as collection from 'lodash/collection'; +import {convert} from 'json-to-json-schema'; @Component({ tag: 'elsa-workflow-definition-editor-screen', @@ -65,6 +68,13 @@ export class ElsaWorkflowDefinitionEditorScreen { activity: null, }; + @State() activityContextMenuTestState: ActivityContextMenuState = { + shown: false, + x: 0, + y: 0, + activity: null, + }; + i18next: i18n; el: HTMLElement; designer: HTMLElsaDesignerTreeElement; @@ -346,6 +356,15 @@ export class ElsaWorkflowDefinitionEditorScreen { this.connectionContextMenuState = state; } + handleContextMenuTestChange(x: number, y: number, shown: boolean, activity: ActivityModel) { + this.activityContextMenuTestState = { + shown, + x, + y, + activity, + }; + } + onShowWorkflowSettingsClick() { eventBus.emit(EventTypes.ShowWorkflowSettings); } @@ -391,16 +410,12 @@ export class ElsaWorkflowDefinitionEditorScreen { } async onActivityContextMenuButtonTestClicked(e: CustomEvent) { - debugger - this.activityContextMenuState = e.detail; - //this.activityStats = null; + this.activityContextMenuTestState = e.detail; + this.selectedActivityId = e.detail.activity.activityId; if (!e.detail.shown) { return; } - - const elsaClient = createElsaClient(this.serverUrl); - //this.activityStats = await elsaClient.activityStatsApi.get(this.workflowInstanceId, e.detail.activity.activityId); } async onActivitySelected(e: CustomEvent) { @@ -527,11 +542,11 @@ export class ElsaWorkflowDefinitionEditorScreen { activityContextMenuButton={this.workflowDesignerMode == WorkflowDesignerMode.Edit ? activityContextMenuButton : this.renderActivityStatsButton} - onActivityContextMenuButtonClicked={this.workflowDesignerMode == WorkflowDesignerMode.Edit - ? e => this.onActivityContextMenuButtonClicked(e) - : e => this.onActivityContextMenuButtonTestClicked(e)} - onConnectionContextMenuButtonClicked={e => this.onConnectionContextMenuButtonClicked(e)} - activityContextMenu={this.activityContextMenuState} + onActivityContextMenuButtonClicked={e => this.onActivityContextMenuButtonClicked(e)} + onActivityContextMenuButtonTestClicked={e => this.onActivityContextMenuButtonTestClicked(e)} + activityContextMenu={this.workflowDesignerMode == WorkflowDesignerMode.Edit + ? this.activityContextMenuState + : this.activityContextMenuTestState} enableMultipleConnectionsFromSingleSource={false} selectedActivityIds={[this.selectedActivityId]} onActivitySelected={e => this.onActivitySelected(e)} @@ -551,10 +566,151 @@ export class ElsaWorkflowDefinitionEditorScreen { {this.renderPublishButton()} + {this.renderTestActivityMenu()} ); } + async onUseAsSchemaClick(message: WorkflowTestActivityMessage) { + const value = message.data["Body"]; + const request: WorkflowTestUpdateRequest = { + activityId: message.activityId, + jsonSchema: JSON.stringify(convert(value), null, 4) + }; + + eventBus.emit(EventTypes.ActivityJsonSchemaUpdated, this, request); + } + + renderTestActivityMenu = () => { + const message = this.workflowTestActivityMessages.find(x => x.activityId == this.selectedActivityId); + + const renderActivityTestError = () => { + + if (message == undefined || !message) + return + + const t = (x, params?) => this.i18next.t(x, params); + + if (!message.error) + return; + + return ( +
+

+ {t('Error')} +

+

+ {message.error} +

+
+ ); + } + + const renderMessage = () => { + + if (message == undefined || !message) + return + + const t = (x, params?) => this.i18next.t(x, params); + const filteredData = {}; + const wellKnownDataKeys = {State: true, Input: null, Outcomes: true, Exception: true}; + let dataKey = null; + + for (const key in message.data) { + if (!message.data.hasOwnProperty(key)) + continue; + + if (!!wellKnownDataKeys[key]) + continue; + + const value = message.data[key]; + + if (!value && value != 0) + continue; + + let valueText = null; + dataKey = key; + + if (typeof value == 'string') + valueText = value; + else if (typeof value == 'object') + valueText = JSON.stringify(value, null, 1); + else if (typeof value == 'undefined') + valueText = null; + else + valueText = value.toString(); + + filteredData[key] = valueText; + } + + const hasBody = dataKey === "Body"; + + return ( +
+
+

+ {t('Status')} +

+

+ {message.status} +

+
+ {collection.map(filteredData, (v, k) => ( +
+

+ {k} +

+

+ {v} +

+
+ ))} + {hasBody ? renderUseAsSchemaButton() : undefined} + {renderActivityTestError()} +
+ ); + }; + + const renderUseAsSchemaButton = () => { + + const t = (x, params?) => this.i18next.t(x, params); + + return ( +
+ +
+ ) + }; + + const renderLoader = function () { + return
Loading...
; + }; + + return
+ registerClickOutside(this, el, () => { + this.handleContextMenuTestChange(0, 0, false, null); + }) + } + > +
+ {!!message ? renderMessage() : renderLoader()} +
+
+ } + renderActivityContextMenu() { const t = this.t; diff --git a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/localizations.ts b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/localizations.ts index e09fb4ff5..43153ecec 100644 --- a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/localizations.ts +++ b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/localizations.ts @@ -9,7 +9,8 @@ }, "ConnectionContextMenu":{ "Paste": "Paste", - } + }, + 'UseAsSchema': 'Use as Schema' } }, 'nl-NL': { @@ -22,7 +23,8 @@ }, "ConnectionContextMenu":{ "Paste": "Plakken", - } + }, + 'UseAsSchema': 'Gebruik als schema' } } }; \ No newline at end of file diff --git a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-test-panel/elsa-workflow-test-panel.tsx b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-test-panel/elsa-workflow-test-panel.tsx index e3dd94544..7ef089a29 100644 --- a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-test-panel/elsa-workflow-test-panel.tsx +++ b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-test-panel/elsa-workflow-test-panel.tsx @@ -1,13 +1,11 @@ import {Component, Prop, h, State, Watch, Host} from '@stencil/core'; import {HubConnection, HubConnectionBuilder} from '@microsoft/signalr'; -import * as collection from 'lodash/collection'; -import {EventTypes, WorkflowDefinition, WorkflowTestActivityMessage, WorkflowTestUpdateRequest} from "../../../../models"; +import {EventTypes, WorkflowDefinition, WorkflowTestActivityMessage} from "../../../../models"; import {i18n} from "i18next"; import {loadTranslations} from "../../../i18n/i18n-loader"; import {resources} from "./localizations"; import {createElsaClient, eventBus, WorkflowTestExecuteRequest} from "../../../../services"; import Tunnel from "../../../../data/dashboard"; -import {convert} from 'json-to-json-schema'; import {clip} from "../../../../utils/utils"; @Component({ @@ -33,7 +31,6 @@ export class ElsaWorkflowTestPanel { @Watch('workflowTestActivityId') async workflowTestActivityMessageChangedHandler(newMessage: string, oldMessage: string) { - debugger const message = this.workflowTestActivityMessages.find(x => x.activityId == newMessage); this.message = !!message ? message : null; } @@ -79,21 +76,38 @@ export class ElsaWorkflowTestPanel { await elsaClient.workflowTestApi.execute(request); } - async onUseAsSchemaClick() { - debugger - const value = this.message.data["Body"]; - const request: WorkflowTestUpdateRequest = { - activityId: this.message.activityId, - jsonSchema: JSON.stringify(convert(value), null, 4) - }; - - eventBus.emit(EventTypes.ActivityJsonSchemaUpdated, this, request); - } - render() { const t = (x, params?) => this.i18next.t(x, params); + const renderActivityTestMessage = () => { + + const {message} = this; + + if (message == undefined || !message) + return + + const t = (x, params?) => this.i18next.t(x, params); + + return ( +
+ {!!message.path ? +
+
+
 clip(e.currentTarget)}>{this.serverUrl + '/workflows' + message.path + '?correlation=' + message.correlationId}
+
+
+ : + '' + } +
+
{t('Status')}
+
{message.status}
+
+
+ ); + } + return (
@@ -105,112 +119,11 @@ export class ElsaWorkflowTestPanel {
- {this.renderActivityTestMessage()} + {renderActivityTestMessage()}
); } - - renderActivityTestMessage() { - - const {message} = this; - - if (message == undefined || !message) - return - - const t = (x, params?) => this.i18next.t(x, params); - const filteredData = {}; - const wellKnownDataKeys = {State: true, Input: null, Outcomes: true, Exception: true}; - let dataKey = null; - - for (const key in message.data) { - if (!message.data.hasOwnProperty(key)) - continue; - - if (!!wellKnownDataKeys[key]) - continue; - - const value = message.data[key]; - - if (!value && value != 0) - continue; - - let valueText = null; - dataKey = key; - - if (typeof value == 'string') - valueText = value; - else if (typeof value == 'object') - valueText = JSON.stringify(value, null, 1); - else if (typeof value == 'undefined') - valueText = null; - else - valueText = value.toString(); - - filteredData[key] = valueText; - } - - const hasBody = dataKey === "Body"; - - return ( -
- {!!message.path ? -
-
-
 clip(e.currentTarget)}>{this.serverUrl + '/workflows' + message.path + '?correlation=' + message.correlationId}
-
-
- : - '' - } -
-
{t('Status')}
-
{message.status}
-
- {collection.map(filteredData, (v, k) => ( -
-
-
{k}
-
{v}
-
- {hasBody ? -
- -
- : - null - } -
- ))} - {this.renderActivityTestError()} -
- ); - } - - renderActivityTestError() { - - const {message} = this; - - if (message == undefined || !message) - return - - const t = (x, params?) => this.i18next.t(x, params); - - if (!message.error) - return; - - return ( -
-
{t('Error')}
-
{message.error}
-
- ); - } - createClient() { return createElsaClient(this.serverUrl); } diff --git a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-test-panel/localizations.ts b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-test-panel/localizations.ts index 79d9c9982..6c2be3134 100644 --- a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-test-panel/localizations.ts +++ b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-test-panel/localizations.ts @@ -2,13 +2,13 @@ export const resources = { 'en': { default: { 'ExecuteWorkflow': 'Execute Workflow', - 'UseAsSchema': 'Use as Schema' + 'Status': 'Status' } }, 'nl-NL': { default: { 'ExecuteWorkflow': 'Werkstroom uitvoeren', - 'UseAsSchema': 'Gebruik als schema' + 'Status': 'Toestand' } } };