From 88e69871766238fc7517c0483f2d72c6427ac3e5 Mon Sep 17 00:00:00 2001 From: simona-taran <88426876+simona-taran@users.noreply.github.com> Date: Tue, 21 Dec 2021 15:33:17 +0200 Subject: [PATCH] Added feature panel. Added ability to manage experimental features. (#2619) --- .../src/assets/designer.config.json | 7 ++ .../elsa-workflows-studio/src/components.d.ts | 25 ++++- .../elsa-studio-root/elsa-studio-root.tsx | 25 ++++- .../pages/elsa-studio-root/readme.md | 15 +-- .../readme.md | 1 + .../elsa-designer-tree/elsa-designer-tree.tsx | 20 +++- .../tree/elsa-designer-tree/models.ts | 6 +- .../tree/elsa-designer-tree/readme.md | 2 +- ...elsa-workflow-definition-editor-screen.tsx | 64 +++++++++-- .../readme.md | 3 + .../elsa-designer-panel.tsx | 100 ++++++++++++++++++ .../elsa-designer-panel/localizations.ts | 12 +++ .../shared/elsa-designer-panel/readme.md | 38 +++++++ .../elsa-workflows-studio/src/index.html | 2 +- .../src/models/services.ts | 2 +- .../src/services/features-data-manager.ts | 73 +++++++++++++ .../src/services/index.ts | 3 +- 17 files changed, 369 insertions(+), 29 deletions(-) create mode 100644 src/designer/elsa-workflows-studio/src/assets/designer.config.json create mode 100644 src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/elsa-designer-panel.tsx create mode 100644 src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/localizations.ts create mode 100644 src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/readme.md create mode 100644 src/designer/elsa-workflows-studio/src/services/features-data-manager.ts diff --git a/src/designer/elsa-workflows-studio/src/assets/designer.config.json b/src/designer/elsa-workflows-studio/src/assets/designer.config.json new file mode 100644 index 000000000..d85db8f5a --- /dev/null +++ b/src/designer/elsa-workflows-studio/src/assets/designer.config.json @@ -0,0 +1,7 @@ +{ + "workflowLayout": { + "enabled": true, + "ui": true, + "defaultValue": "topbottom" + } +} diff --git a/src/designer/elsa-workflows-studio/src/components.d.ts b/src/designer/elsa-workflows-studio/src/components.d.ts index d0f71320a..3ffef0f66 100644 --- a/src/designer/elsa-workflows-studio/src/components.d.ts +++ b/src/designer/elsa-workflows-studio/src/components.d.ts @@ -49,6 +49,9 @@ export namespace Components { interface ElsaCopyButton { "value": string; } + interface ElsaDesignerPanel { + "culture": string; + } interface ElsaDesignerTree { "activityBorderColor"?: (activity: ActivityModel) => string; "activityContextMenu"?: ActivityContextMenuState; @@ -201,8 +204,9 @@ export namespace Components { "addPlugin": (pluginType: any) => Promise; "addPlugins": (pluginTypes: Array) => Promise; "basePath": string; + "config": string; "culture": string; - "featuresString": string; + "features": any; "monacoLibPath": string; "serverUrl": string; } @@ -285,6 +289,7 @@ export namespace Components { "basePath": string; "culture": string; "exportWorkflow": () => Promise; + "features": string; "getServerUrl": () => Promise; "getWorkflowDefinitionId": () => Promise; "history": RouterHistory; @@ -410,6 +415,12 @@ declare global { prototype: HTMLElsaCopyButtonElement; new (): HTMLElsaCopyButtonElement; }; + interface HTMLElsaDesignerPanelElement extends Components.ElsaDesignerPanel, HTMLStencilElement { + } + var HTMLElsaDesignerPanelElement: { + prototype: HTMLElsaDesignerPanelElement; + new (): HTMLElsaDesignerPanelElement; + }; interface HTMLElsaDesignerTreeElement extends Components.ElsaDesignerTree, HTMLStencilElement { } var HTMLElsaDesignerTreeElement: { @@ -731,6 +742,7 @@ declare global { "elsa-context-menu": HTMLElsaContextMenuElement; "elsa-control": HTMLElsaControlElement; "elsa-copy-button": HTMLElsaCopyButtonElement; + "elsa-designer-panel": HTMLElsaDesignerPanelElement; "elsa-designer-tree": HTMLElsaDesignerTreeElement; "elsa-dictionary-property": HTMLElsaDictionaryPropertyElement; "elsa-dropdown-button": HTMLElsaDropdownButtonElement; @@ -815,6 +827,11 @@ declare namespace LocalJSX { interface ElsaCopyButton { "value"?: string; } + interface ElsaDesignerPanel { + "culture"?: string; + "onFeatureChanged"?: (event: CustomEvent) => void; + "onFeatureStatusChanged"?: (event: CustomEvent) => void; + } interface ElsaDesignerTree { "activityBorderColor"?: (activity: ActivityModel) => string; "activityContextMenu"?: ActivityContextMenuState; @@ -973,8 +990,9 @@ declare namespace LocalJSX { } interface ElsaStudioRoot { "basePath"?: string; + "config"?: string; "culture"?: string; - "featuresString"?: string; + "features"?: any; "monacoLibPath"?: string; "onInitialized"?: (event: CustomEvent) => void; "onInitializing"?: (event: CustomEvent) => void; @@ -1053,6 +1071,7 @@ declare namespace LocalJSX { interface ElsaWorkflowDefinitionEditorScreen { "basePath"?: string; "culture"?: string; + "features"?: string; "history"?: RouterHistory; "monacoLibPath"?: string; "onWorkflowSaved"?: (event: CustomEvent) => void; @@ -1136,6 +1155,7 @@ declare namespace LocalJSX { "elsa-context-menu": ElsaContextMenu; "elsa-control": ElsaControl; "elsa-copy-button": ElsaCopyButton; + "elsa-designer-panel": ElsaDesignerPanel; "elsa-designer-tree": ElsaDesignerTree; "elsa-dictionary-property": ElsaDictionaryProperty; "elsa-dropdown-button": ElsaDropdownButton; @@ -1202,6 +1222,7 @@ declare module "@stencil/core" { "elsa-context-menu": LocalJSX.ElsaContextMenu & JSXBase.HTMLAttributes; "elsa-control": LocalJSX.ElsaControl & JSXBase.HTMLAttributes; "elsa-copy-button": LocalJSX.ElsaCopyButton & JSXBase.HTMLAttributes; + "elsa-designer-panel": LocalJSX.ElsaDesignerPanel & JSXBase.HTMLAttributes; "elsa-designer-tree": LocalJSX.ElsaDesignerTree & JSXBase.HTMLAttributes; "elsa-dictionary-property": LocalJSX.ElsaDictionaryProperty & JSXBase.HTMLAttributes; "elsa-dropdown-button": LocalJSX.ElsaDropdownButton & JSXBase.HTMLAttributes; diff --git a/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-root/elsa-studio-root.tsx b/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-root/elsa-studio-root.tsx index 6ec80fe31..1c329f3c8 100644 --- a/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-root/elsa-studio-root.tsx +++ b/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-root/elsa-studio-root.tsx @@ -1,4 +1,4 @@ -import {Component, Event, EventEmitter, h, Listen, Method, Prop} from '@stencil/core'; +import {Component, Event, EventEmitter, h, Listen, Method, Prop, State} from '@stencil/core'; import Tunnel, {DashboardState} from "../../../../data/dashboard"; import {ElsaStudio, WorkflowModel} from "../../../../models"; import { @@ -10,7 +10,8 @@ import { createElsaClient, createHttpClient, ElsaClient, - propertyDisplayManager + propertyDisplayManager, + featuresDataManager } from "../../../../services"; import {AxiosInstance} from "axios"; import {EventTypes} from "../../../../models"; @@ -27,7 +28,9 @@ export class ElsaStudioRoot { @Prop({attribute: 'monaco-lib-path', reflect: true}) monacoLibPath: string; @Prop({attribute: 'culture', reflect: true}) culture: string; @Prop({attribute: 'base-path', reflect: true}) basePath: string = ''; - @Prop({attribute: 'features', reflect: true}) featuresString: string; + @Prop() features: any; + @Prop() config: string; + @State() featuresConfig: any; @Event() initializing: EventEmitter; @Event() initialized: EventEmitter; @@ -67,13 +70,26 @@ export class ElsaStudioRoot { async componentWillLoad() { const elsaClientFactory: () => Promise = () => createElsaClient(this.serverUrl); const httpClientFactory: () => Promise = () => createHttpClient(this.serverUrl); + await fetch(`${document.location.origin}/${this.config}`) + .then(response => { + if (!response.ok) { + throw new Error("HTTP error " + response.status); + } + + return response.json() + }) + .then(data => { + this.featuresConfig = data; + }).catch((error) => { + console.error(error) + }); const elsaClient = await elsaClientFactory(); const elsaStudio: ElsaStudio = this.elsaStudio = { serverUrl: this.serverUrl, basePath: this.basePath, - featuresString: this.featuresString, + features: this.featuresConfig, serverFeatures: [], eventBus, pluginManager, @@ -91,6 +107,7 @@ export class ElsaStudioRoot { await eventBus.emit(EventTypes.Root.Initializing); pluginManager.initialize(elsaStudio); propertyDisplayManager.initialize(elsaStudio); + featuresDataManager.initialize(elsaStudio); elsaStudio.serverFeatures = await elsaClient.featuresApi.list(); } diff --git a/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-root/readme.md b/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-root/readme.md index dc8306aa0..dbcdec05d 100644 --- a/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-root/readme.md +++ b/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-root/readme.md @@ -7,13 +7,14 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ---------------- | ----------------- | ----------- | -------- | ----------- | -| `basePath` | `base-path` | | `string` | `''` | -| `culture` | `culture` | | `string` | `undefined` | -| `featuresString` | `features` | | `string` | `undefined` | -| `monacoLibPath` | `monaco-lib-path` | | `string` | `undefined` | -| `serverUrl` | `server-url` | | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| --------------- | ----------------- | ----------- | -------- | ----------- | +| `basePath` | `base-path` | | `string` | `''` | +| `config` | `config` | | `string` | `undefined` | +| `culture` | `culture` | | `string` | `undefined` | +| `features` | `features` | | `any` | `undefined` | +| `monacoLibPath` | `monaco-lib-path` | | `string` | `undefined` | +| `serverUrl` | `server-url` | | `string` | `undefined` | ## Events diff --git a/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-workflow-definitions-edit/readme.md b/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-workflow-definitions-edit/readme.md index d456877cc..0c4191573 100644 --- a/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-workflow-definitions-edit/readme.md +++ b/src/designer/elsa-workflows-studio/src/components/dashboard/pages/elsa-studio-workflow-definitions-edit/readme.md @@ -36,6 +36,7 @@ graph TD; elsa-workflow-definition-editor-screen --> elsa-tab-content elsa-workflow-definition-editor-screen --> elsa-workflow-properties-panel elsa-workflow-definition-editor-screen --> elsa-workflow-test-panel + elsa-workflow-definition-editor-screen --> elsa-designer-panel elsa-workflow-definition-editor-screen --> context-consumer elsa-workflow-settings-modal --> elsa-modal-dialog elsa-workflow-settings-modal --> elsa-monaco 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 43cbcbbe0..23dd207a9 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,7 +46,7 @@ export class ElsaWorkflowDesigner { @Prop() connectionContextMenu?: ActivityContextMenuState; @Prop() activityContextTestMenu?: ActivityContextMenuState; @Prop() mode: WorkflowDesignerMode = WorkflowDesignerMode.Edit; - @Prop() layoutDirection: LayoutDirection = LayoutDirection.Vertical; + @Prop() layoutDirection: LayoutDirection = LayoutDirection.TopBottom; @Prop({attribute: 'enable-multiple-connections'}) enableMultipleConnectionsFromSingleSource: boolean; @Event({ eventName: 'workflow-changed', @@ -568,9 +568,7 @@ export class ElsaWorkflowDesigner { setEntities() { this.graph = new dagreD3.graphlib.Graph().setGraph({}); - - const layoutDirection = this.layoutDirection; - this.graph.graph().rankdir = layoutDirection == LayoutDirection.Vertical ? 'TB' : 'LR'; + this.graph.graph().rankdir = this.getLayoutDirection(); const rootActivities = this.getRootActivities(); @@ -947,4 +945,18 @@ export class ElsaWorkflowDesigner { ); } + + private getLayoutDirection = () => { + switch (this.layoutDirection) { + case LayoutDirection.BottomTop: + return 'BT'; + case LayoutDirection.LeftRight: + return 'LR'; + case LayoutDirection.RightLeft: + return 'RL'; + case LayoutDirection.TopBottom: + default: + return 'TB'; + } + } } diff --git a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/models.ts b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/models.ts index fc7693eef..403d31a90 100644 --- a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/models.ts +++ b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/models.ts @@ -17,6 +17,8 @@ export interface ActivityContextMenuState { } export enum LayoutDirection { - Horizontal, - Vertical + LeftRight ='leftright', + TopBottom = 'topbottom', + RightLeft = 'rightleft', + BottomTop = 'bottomtop' } diff --git a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/readme.md b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/readme.md index db8897b1c..ed1d6f38b 100644 --- a/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/readme.md +++ b/src/designer/elsa-workflows-studio/src/components/designers/tree/elsa-designer-tree/readme.md @@ -15,7 +15,7 @@ | `activityContextTestMenu` | -- | | `ActivityContextMenuState` | `undefined` | | `connectionContextMenu` | -- | | `ActivityContextMenuState` | `undefined` | | `enableMultipleConnectionsFromSingleSource` | `enable-multiple-connections` | | `boolean` | `undefined` | -| `layoutDirection` | `layout-direction` | | `LayoutDirection.Horizontal \| LayoutDirection.Vertical` | `LayoutDirection.Vertical` | +| `layoutDirection` | `layout-direction` | | `LayoutDirection.BottomTop \| LayoutDirection.LeftRight \| LayoutDirection.RightLeft \| LayoutDirection.TopBottom` | `LayoutDirection.TopBottom` | | `mode` | `mode` | | `WorkflowDesignerMode.Blueprint \| WorkflowDesignerMode.Edit \| WorkflowDesignerMode.Instance \| WorkflowDesignerMode.Test` | `WorkflowDesignerMode.Edit` | | `model` | -- | | `WorkflowModel` | `{ activities: [], connections: [], persistenceBehavior: WorkflowPersistenceBehavior.WorkflowBurst }` | | `selectedActivityIds` | -- | | `string[]` | `[]` | 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 2f587f4cc..af0a883af 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 @@ -1,33 +1,38 @@ import {Component, Event, EventEmitter, h, Host, Listen, Method, Prop, State, Watch} from '@stencil/core'; -import {RouterHistory, injectHistory} from '@stencil/router'; +import {injectHistory, RouterHistory} from '@stencil/router'; import { ActivityDefinition, ActivityDescriptor, ActivityModel, - ConfigureComponentCustomButtonContext, ComponentCustomButtonClickContext, + ConfigureComponentCustomButtonContext, ConnectionDefinition, ConnectionModel, EventTypes, VersionOptions, WorkflowDefinition, + WorkflowInstance, WorkflowModel, WorkflowPersistenceBehavior, WorkflowTestActivityMessage, - WorkflowInstance, WorkflowTestActivityMessageStatus, + WorkflowTestActivityMessageStatus, } from "../../../../models"; import { ActivityStats, createElsaClient, eventBus, - SaveWorkflowDefinitionRequest, toastNotificationService, - WorkflowTestRestartFromActivityRequest + featuresDataManager, + SaveWorkflowDefinitionRequest } from "../../../../services"; import state from '../../../../utils/store'; import WorkflowEditorTunnel, {WorkflowEditorState} from '../../../../data/workflow-editor'; import DashboardTunnel from "../../../../data/dashboard"; import {downloadFromBlob} from "../../../../utils/download"; -import {ActivityContextMenuState, WorkflowDesignerMode} from "../../../designers/tree/elsa-designer-tree/models"; +import { + ActivityContextMenuState, + LayoutDirection, + WorkflowDesignerMode +} from "../../../designers/tree/elsa-designer-tree/models"; import {i18n} from "i18next"; import {loadTranslations} from "../../../i18n/i18n-loader"; import {resources} from "./localizations"; @@ -44,6 +49,7 @@ export class ElsaWorkflowDefinitionEditorScreen { @Prop({attribute: 'workflow-definition-id', reflect: true}) workflowDefinitionId: string; @Prop({attribute: 'server-url', reflect: true}) serverUrl: string; @Prop({attribute: 'monaco-lib-path', reflect: true}) monacoLibPath: string; + @Prop() features: string; @Prop() culture: string; @Prop() basePath: string; @Prop() serverFeatures: Array = []; @@ -64,6 +70,7 @@ export class ElsaWorkflowDefinitionEditorScreen { @State() workflowInstance?: WorkflowInstance; @State() workflowInstanceId?: string; @State() activityStats?: ActivityStats; + @State() layoutDirection: LayoutDirection = LayoutDirection.TopBottom;//??? @State() activityContextMenuState: ActivityContextMenuState = { shown: false, @@ -197,6 +204,11 @@ export class ElsaWorkflowDefinitionEditorScreen { async componentWillLoad() { this.i18next = await loadTranslations(this.culture, resources); this.workflowDesignerMode = WorkflowDesignerMode.Edit; + + const layoutFeature = featuresDataManager.getFeatureConfig(featuresDataManager.supportedFeatures.workflowLayout); + if (layoutFeature && layoutFeature.enabled) { + this.layoutDirection = layoutFeature.value as LayoutDirection; + } await this.serverUrlChangedHandler(this.serverUrl); await this.workflowDefinitionIdChangedHandler(this.workflowDefinitionId); await this.monacoLibPathChangedHandler(this.monacoLibPath); @@ -647,6 +659,7 @@ export class ElsaWorkflowDefinitionEditorScreen {
{this.renderTestPanel()} + {this.renderDesignerPanel()} ); } @@ -1081,6 +1095,44 @@ export class ElsaWorkflowDefinitionEditorScreen { ]; } + + private renderDesignerPanel = () => { + const isFeaturePanelVisible = featuresDataManager.getUIFeatureList().length != 0; + + if (isFeaturePanelVisible) { + return [ + Designer, + + + + ]; + } + } + + handleFeatureChange = (e: CustomEvent) => { + const feature = e.detail; + + if (feature === featuresDataManager.supportedFeatures.workflowLayout) { + const layoutFeature = featuresDataManager.getFeatureConfig(feature); + this.layoutDirection = layoutFeature.value as LayoutDirection; + } + } + + handleFeatureStatusChange = (e: CustomEvent) => { + const feature = e.detail; + + if (feature === featuresDataManager.supportedFeatures.workflowLayout) { + const layoutFeature = featuresDataManager.getFeatureConfig(feature); + if (layoutFeature.enabled) { + this.layoutDirection = layoutFeature.value as LayoutDirection; + } else { + this.layoutDirection = LayoutDirection.TopBottom; + } + } + } } injectHistory(ElsaWorkflowDefinitionEditorScreen); diff --git a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/readme.md b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/readme.md index fe4e0f4dc..55aa661c5 100644 --- a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/readme.md +++ b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-workflow-definition-editor-screen/readme.md @@ -10,6 +10,7 @@ | Property | Attribute | Description | Type | Default | | ---------------------- | ------------------------ | ----------- | --------------- | ----------- | | `culture` | `culture` | | `string` | `undefined` | +| `features` | `features` | | `string` | `undefined` | | `history` | -- | | `RouterHistory` | `undefined` | | `monacoLibPath` | `monaco-lib-path` | | `string` | `undefined` | | `serverUrl` | `server-url` | | `string` | `undefined` | @@ -88,6 +89,7 @@ Type: `Promise` - [elsa-tab-content](../../../shared/elsa-tab-content) - [elsa-workflow-properties-panel](../elsa-workflow-properties-panel) - [elsa-workflow-test-panel](../elsa-workflow-test-panel) +- [elsa-designer-panel](../../../shared/elsa-designer-panel) - context-consumer ### Graph @@ -107,6 +109,7 @@ graph TD; elsa-workflow-definition-editor-screen --> elsa-tab-content elsa-workflow-definition-editor-screen --> elsa-workflow-properties-panel elsa-workflow-definition-editor-screen --> elsa-workflow-test-panel + elsa-workflow-definition-editor-screen --> elsa-designer-panel elsa-workflow-definition-editor-screen --> context-consumer elsa-workflow-settings-modal --> elsa-modal-dialog elsa-workflow-settings-modal --> elsa-monaco diff --git a/src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/elsa-designer-panel.tsx b/src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/elsa-designer-panel.tsx new file mode 100644 index 000000000..234f7e8e7 --- /dev/null +++ b/src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/elsa-designer-panel.tsx @@ -0,0 +1,100 @@ +import {Component, Host, h, Event, EventEmitter, Prop, State} from '@stencil/core'; +import {FeatureConfig, featuresDataManager} from "../../../services"; +import {LayoutDirection} from "../../designers/tree/elsa-designer-tree/models"; +import {i18n} from "i18next"; +import {resources} from "./localizations"; +import {loadTranslations} from "../../i18n/i18n-loader"; + +@Component({ + tag: 'elsa-designer-panel', + shadow: false, +}) + +export class ElsaDesignerPanel { + + @Prop() culture: string; + @State() lastChangeTime: Date; + @Event() featureChanged: EventEmitter; + @Event() featureStatusChanged: EventEmitter; + + i18next: i18n; + + async componentWillLoad() { + this.i18next = await loadTranslations(this.culture, resources); + } + + t = (key: string, options?: any) => this.i18next.t(key, options); + + render() { + const features = featuresDataManager.getUIFeatureList(); + const {t} = this; + + return ( + +
+ {features.map(name => { + const feature = featuresDataManager.getFeatureConfig(name); + + return ( +
+
+
+ this.onToggleChange(e, name)} + class="focus:elsa-ring-blue-500 elsa-h-4 elsa-w-4 elsa-text-blue-600 elsa-border-gray-300 rounded" + /> +
+
+ +

{t(`${name}Description`)}

+
+
+
+ {this.renderFeatureData(name, feature)} +
+
+ ) + })} +
+
+ ); + } + + renderFeatureData = (name: string, feature: FeatureConfig) => { + if (!feature.enabled) { + return null; + } + + const {t} = this; + switch (name) { + case featuresDataManager.supportedFeatures.workflowLayout: + return ( + + ) + default: + return null; + } + } + + onToggleChange = (e: Event, name: string) => { + const element = e.target as HTMLInputElement; + featuresDataManager.setEnableStatus(name, element.checked); + this.lastChangeTime = new Date(); + this.featureStatusChanged.emit(name); + } + + onPropertyChange = (e: Event, name: string) => { + const element = e.target as HTMLInputElement; + featuresDataManager.setFeatureConfig(name, element.value.trim()); + this.featureChanged.emit(name); + } +} diff --git a/src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/localizations.ts b/src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/localizations.ts new file mode 100644 index 000000000..1ea820ed7 --- /dev/null +++ b/src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/localizations.ts @@ -0,0 +1,12 @@ +export const resources = { + 'en': { + default: { + 'workflowLayoutName': 'Workflow Layout', + 'workflowLayoutDescription': 'Determines the directions cards are displayed in. Changed for every workflow.', + 'TopBottom': 'Top to Bottom', + 'LeftRight': 'Left to Right', + 'BottomTop': 'Bottom to Top', + 'RightLeft': 'Right to Left', + } + } +}; diff --git a/src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/readme.md b/src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/readme.md new file mode 100644 index 000000000..0b01f5d18 --- /dev/null +++ b/src/designer/elsa-workflows-studio/src/components/shared/elsa-designer-panel/readme.md @@ -0,0 +1,38 @@ +# elsa-designer-panel + + + + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| --------- | --------- | ----------- | -------- | ----------- | +| `culture` | `culture` | | `string` | `undefined` | + + +## Events + +| Event | Description | Type | +| ---------------------- | ----------- | --------------------- | +| `featureChanged` | | `CustomEvent` | +| `featureStatusChanged` | | `CustomEvent` | + + +## Dependencies + +### Used by + + - [elsa-workflow-definition-editor-screen](../../screens/workflow-definition-editor/elsa-workflow-definition-editor-screen) + +### Graph +```mermaid +graph TD; + elsa-workflow-definition-editor-screen --> elsa-designer-panel + style elsa-designer-panel fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/designer/elsa-workflows-studio/src/index.html b/src/designer/elsa-workflows-studio/src/index.html index ab0a97ebc..babcc27bd 100644 --- a/src/designer/elsa-workflows-studio/src/index.html +++ b/src/designer/elsa-workflows-studio/src/index.html @@ -14,7 +14,7 @@ - + diff --git a/src/designer/elsa-workflows-studio/src/models/services.ts b/src/designer/elsa-workflows-studio/src/models/services.ts index 4d79dfa70..1ee44a8bb 100644 --- a/src/designer/elsa-workflows-studio/src/models/services.ts +++ b/src/designer/elsa-workflows-studio/src/models/services.ts @@ -8,7 +8,7 @@ import {ActivityModel} from "./view"; export interface ElsaStudio { serverUrl: string; basePath: string; - featuresString: string; + features: any; serverFeatures: Array; pluginManager: PluginManager; propertyDisplayManager: PropertyDisplayManager; diff --git a/src/designer/elsa-workflows-studio/src/services/features-data-manager.ts b/src/designer/elsa-workflows-studio/src/services/features-data-manager.ts new file mode 100644 index 000000000..27654e552 --- /dev/null +++ b/src/designer/elsa-workflows-studio/src/services/features-data-manager.ts @@ -0,0 +1,73 @@ +import {ElsaStudio} from "../models/"; + +export interface FeatureConfig { + enabled: boolean; + ui: boolean; + defaultValue: string; + value?: string; +} + +type FeatureConfigMap = { + [key:string]: FeatureConfig; +} + +export class FeaturesDataManager { + + elsaStudio: ElsaStudio; + initialized: boolean; + features: FeatureConfigMap; + supportedFeatures = { + workflowLayout: 'workflowLayout' + } + + initialize(elsaStudio: ElsaStudio) { + if (this.initialized) + return; + + this.elsaStudio = elsaStudio; + this.initialized = true; + this.features = elsaStudio.features || {}; + } + + getFeatureList = () => { + return Object.keys(this.features); + } + + getUIFeatureList = () => { + return Object.keys(this.features).filter(feature => this.features[feature].ui); + } + + getFeatureConfig = (name: string) => { + const value = localStorage.getItem(`elsa.properties.${name}`); + const enabled = localStorage.getItem(`elsa.properties.${name}.enabled`); + const feature = this.features[name]; + + if (feature) { + return { + ...feature, + value: value === null ? feature.defaultValue : value, + 'enabled': enabled === null ? feature.enabled : enabled === 'true' + } + } + } + + setFeatureConfig = (name: string, value: string) => { + const feature = this.features[name]; + + if (feature) { + localStorage.setItem(`elsa.properties.${name}`, value); + } + } + + setEnableStatus = (name: string, value: boolean) => { + const feature = this.features[name]; + + if (feature) { + localStorage.setItem(`elsa.properties.${name}.enabled`, `${value}`); + console.log(`elsa.properties.${name}-enabled`, value); + } + } + +} + +export const featuresDataManager = new FeaturesDataManager(); diff --git a/src/designer/elsa-workflows-studio/src/services/index.ts b/src/designer/elsa-workflows-studio/src/services/index.ts index b7e0e6599..74b6f86e2 100644 --- a/src/designer/elsa-workflows-studio/src/services/index.ts +++ b/src/designer/elsa-workflows-studio/src/services/index.ts @@ -4,6 +4,7 @@ export * from './toast-notification-service'; export * from './elsa-plugin'; export * from './elsa-client'; export * from './event-bus'; +export * from './features-data-manager'; export * from './plugin-manager'; export * from './property-display-driver'; -export * from './property-display-manager'; \ No newline at end of file +export * from './property-display-manager';