From 9182af3d1f0182677efab0466ae970b248ca928f Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 27 Jul 2021 08:21:03 +0200 Subject: [PATCH] Refactor activity editor modal with customizable tabs model --- .../elsa-activity-editor-modal.tsx | 151 ++++++++++-------- .../src/models/events.ts | 1 + 2 files changed, 88 insertions(+), 64 deletions(-) diff --git a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-activity-editor-modal/elsa-activity-editor-modal.tsx b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-activity-editor-modal/elsa-activity-editor-modal.tsx index 8ed31863e..c052a0384 100644 --- a/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-activity-editor-modal/elsa-activity-editor-modal.tsx +++ b/src/designer/elsa-workflows-studio/src/components/screens/workflow-definition-editor/elsa-activity-editor-modal/elsa-activity-editor-modal.tsx @@ -7,6 +7,20 @@ import {i18n} from "i18next"; import {loadTranslations} from "../../../i18n/i18n-loader"; import {resources} from "./localizations"; +export interface TabModel { + tabName: string; + renderContent: () => any; +} + +export interface ActivityEditorRenderProps { + activityDescriptor?: ActivityDescriptor; + activityModel?: ActivityModel; + propertyCategories?: Array; + defaultProperties?: Array; + tabs?: Array; + selectedTabName?: string; +} + @Component({ tag: 'elsa-activity-editor-modal', shadow: false, @@ -16,12 +30,12 @@ export class ElsaActivityEditorModal { @State() workflowStorageDescriptors: Array = []; @State() activityModel: ActivityModel; @State() activityDescriptor: ActivityDescriptor; - @State() selectedTab: string = 'Properties'; + @State() selectedTabName: string = 'Properties'; i18next: i18n; dialog: HTMLElsaModalDialogElement; form: HTMLFormElement; formContext: FormContext; - renderProps: any; + renderProps: ActivityEditorRenderProps = {}; propertyElements: Array = []; // Force a new key every time we show the editor to make sure Stencil creates new components. @@ -52,6 +66,60 @@ export class ElsaActivityEditorModal { propertyDisplayManager.update(activity, property, formData); } + componentWillRender() { + const activityDescriptor: ActivityDescriptor = this.activityDescriptor || {displayName: '', type: '', outcomes: [], category: '', traits: 0, browsable: false, inputProperties: [], outputProperties: [], description: ''}; + const propertyCategories = activityDescriptor.inputProperties.filter(x => x.category).map(x => x.category).distinct(); + const defaultProperties = activityDescriptor.inputProperties.filter(x => !x.category || x.category.length == 0); + const activityModel: ActivityModel = this.activityModel || {type: '', activityId: '', outcomes: [], properties: [], propertyStorageProviders: {}}; + const t = this.t; + let tabs: Array = []; + + if (defaultProperties.length > 0) { + tabs.push({ + tabName: t('Tabs.Properties.Name'), + renderContent: () => this.renderPropertiesTab(activityModel) + }); + } + + for (const category of propertyCategories) { + const categoryTab: TabModel = { + tabName: category, + renderContent: () => this.renderCategoryTab(activityModel, activityDescriptor, category) + }; + + tabs.push(categoryTab); + } + + tabs.push({ + tabName: t('Tabs.Common.Name'), + renderContent: () => this.renderCommonTab(activityModel) + }); + + tabs.push({ + tabName: t('Tabs.Storage.Name'), + renderContent: () => this.renderStorageTab(activityModel, activityDescriptor) + }); + + let selectedTabName = this.selectedTabName; + + if (tabs.findIndex(x => x.tabName === selectedTabName) < 0) { + this.selectedTabName = selectedTabName = tabs[0].tabName; + } + + this.renderProps = { + activityDescriptor, + activityModel, + propertyCategories, + defaultProperties, + tabs, + selectedTabName, + }; + + eventBus.emit(EventTypes.ActivityEditorDisplaying, this, this.renderProps); + + this.propertyElements = []; + } + async onCancelClick() { await this.dialog.hide(true); } @@ -65,9 +133,9 @@ export class ElsaActivityEditorModal { await this.dialog.hide(true); }; - onTabClick = (e: Event, tab: string) => { + onTabClick = (e: Event, tab: TabModel) => { e.preventDefault(); - this.selectedTab = tab; + this.selectedTabName = tab.tabName; }; onShowActivityEditor = async (activity: ActivityModel, animate: boolean) => { @@ -76,45 +144,11 @@ export class ElsaActivityEditorModal { this.activityDescriptor = state.activityDescriptors.find(x => x.type == activity.type); this.workflowStorageDescriptors = state.workflowStorageDescriptors; this.formContext = new FormContext(this.activityModel, newValue => this.activityModel = newValue); - this.selectedTab = t('Properties'); + this.selectedTabName = t('Properties'); this.timestamp = new Date(); await this.dialog.show(animate); }; - componentWillRender() { - const activityDescriptor: ActivityDescriptor = this.activityDescriptor || {displayName: '', type: '', outcomes: [], category: '', traits: 0, browsable: false, inputProperties: [], outputProperties: [], description: ''}; - const propertyCategories = activityDescriptor.inputProperties.filter(x => x.category).map(x => x.category).distinct(); - const defaultProperties = activityDescriptor.inputProperties.filter(x => !x.category || x.category.length == 0); - const t = this.t; - let tabs: Array = []; - - if (defaultProperties.length > 0) { - tabs.push(t('Tabs.Properties.Name')); - } - - tabs = [...tabs, ...propertyCategories]; - tabs.push(t('Tabs.Common.Name')); - tabs.push(t('Tabs.Storage.Name')); - - let selectedTab = this.selectedTab; - - if (tabs.findIndex(x => x === selectedTab) < 0) - selectedTab = tabs[0]; - - const activityModel: ActivityModel = this.activityModel || {type: '', activityId: '', outcomes: [], properties: [], propertyStorageProviders: {}}; - - this.renderProps = { - activityDescriptor, - propertyCategories, - defaultProperties, - tabs, - selectedTab, - activityModel - } - - this.propertyElements = []; - } - componentDidRender() { for (const item of this.propertyElements) { const container: HTMLDivElement = item.host; @@ -127,10 +161,8 @@ export class ElsaActivityEditorModal { render() { const renderProps = this.renderProps; const activityDescriptor: ActivityDescriptor = renderProps.activityDescriptor; - const propertyCategories = renderProps.propertyCategories; const tabs = renderProps.tabs; - const selectedTab = renderProps.selectedTab; - const activityModel: ActivityModel = renderProps.activityModel; + const selectedTabName = renderProps.selectedTabName; const inactiveClass = 'elsa-border-transparent elsa-text-gray-500 hover:elsa-text-gray-700 hover:elsa-border-gray-300'; const selectedClass = 'elsa-border-blue-500 elsa-text-blue-600'; const t = this.t; @@ -156,15 +188,15 @@ export class ElsaActivityEditorModal {
- {this.renderSelectedTab(activityModel, activityDescriptor, propertyCategories)} + {this.renderTabs(tabs)}
@@ -192,13 +224,8 @@ export class ElsaActivityEditorModal { ); } - renderSelectedTab(activityModel: ActivityModel, activityDescriptor: ActivityDescriptor, categories: Array) { - return [ - this.renderStorageTab(activityModel, activityDescriptor), - this.renderCommonTab(activityModel), - this.renderPropertiesTab(activityModel, activityDescriptor), - this.renderCategoryTabs(activityModel, activityDescriptor, categories), - ]; + renderTabs(tabs: Array) { + return tabs.map(x => x.renderContent()); } renderStorageTab(activityModel: ActivityModel, activityDescriptor: ActivityDescriptor) { @@ -254,7 +281,7 @@ export class ElsaActivityEditorModal { ); } - renderPropertiesTab(activityModel: ActivityModel, activityDescriptor: ActivityDescriptor) { + renderPropertiesTab(activityModel: ActivityModel) { const propertyDescriptors: Array = this.renderProps.defaultProperties; if (propertyDescriptors.length == 0) @@ -270,18 +297,14 @@ export class ElsaActivityEditorModal { ); } - renderCategoryTabs(activityModel: ActivityModel, activityDescriptor: ActivityDescriptor, categories: Array) { + renderCategoryTab(activityModel: ActivityModel, activityDescriptor: ActivityDescriptor, category: string) { const propertyDescriptors: Array = activityDescriptor.inputProperties; + const descriptors = propertyDescriptors.filter(x => x.category == category); + const key = `activity-settings:${activityModel.activityId}:${category}`; - return ( - categories.map(category => { - const descriptors = propertyDescriptors.filter(x => x.category == category); - const key = `activity-settings:${activityModel.activityId}:${category}`; - return
- {descriptors.map(property => this.renderPropertyEditor(activityModel, property))} -
- }) - ); + return
+ {descriptors.map(property => this.renderPropertyEditor(activityModel, property))} +
; } renderPropertyEditor(activity: ActivityModel, property: ActivityPropertyDescriptor) { @@ -299,6 +322,6 @@ export class ElsaActivityEditorModal { } getHiddenClass(tab: string) { - return this.renderProps.selectedTab == tab ? '' : 'hidden'; + return this.renderProps.selectedTabName == tab ? '' : 'hidden'; } } diff --git a/src/designer/elsa-workflows-studio/src/models/events.ts b/src/designer/elsa-workflows-studio/src/models/events.ts index 5266a8536..b7cb0d302 100644 --- a/src/designer/elsa-workflows-studio/src/models/events.ts +++ b/src/designer/elsa-workflows-studio/src/models/events.ts @@ -6,6 +6,7 @@ export const EventTypes = { ShowWorkflowSettings: 'show-workflow-settings', ActivityPicked: 'activity-picked', ShowActivityEditor: 'show-activity-editor', + ActivityEditorDisplaying: 'activity-editor-displaying', UpdateActivity: 'update-activity', UpdateWorkflowSettings: 'update-workflow-settings', WorkflowModelChanged: 'workflow-model-changed',