diff options
author | 2018-08-27 10:07:45 +0300 | |
---|---|---|
committer | 2018-08-27 10:08:09 +0300 | |
commit | a69951b9f9319f8e25d63384b2dbee851df24694 (patch) | |
tree | e99d724d3da2035990d6f936392234498f4383de /workflow-designer-ui/src/main | |
parent | 63cf9d516fc1dd77c339d188fa9852bb6a42f525 (diff) |
wf composition
Issue-ID: SDC-1591
Change-Id: I3d1c1e08094a2088b8e474b0c6f3616088ded4ee
Signed-off-by: Stanislav Vishnevetskiy <shlomo-stanisla.vishnevetskiy@amdocs.com>
Diffstat (limited to 'workflow-designer-ui/src/main')
41 files changed, 3116 insertions, 176 deletions
diff --git a/workflow-designer-ui/src/main/frontend/package.json b/workflow-designer-ui/src/main/frontend/package.json index e3c657e0..5271dc54 100644 --- a/workflow-designer-ui/src/main/frontend/package.json +++ b/workflow-designer-ui/src/main/frontend/package.json @@ -14,9 +14,8 @@ }, "dependencies": { "axios": "^0.18.0", - "bpmn-js": "^2.3.0", - "bpmn-js-properties-panel": "^0.20.0", - "camunda-bpmn-moddle": "^3.0.0", + "bpmn-js": "^2.4.1", + "bpmn-js-properties-panel": "^0.26.1", "classnames": "^2.2.6", "d3-hierarchy": "^1.1.6", "d3-selection": "^1.3.0", @@ -25,7 +24,12 @@ "enzyme-adapter-react-16": "^1.1.1", "file-saver": "^1.3.8", "http-proxy-middleware": "^0.17.4", - "lodash": "^3.0.1", + "inherits": "^2.0.3", + "lodash.assign": "^4.2.0", + "lodash.isempty": "^4.4.0", + "lodash.map": "^4.6.0", + "lodash.merge": "^4.6.1", + "lodash.set": "^4.3.2", "md5": "^2.2.1", "moment": "^2.18.1", "prop-types": "^15.6.1", diff --git a/workflow-designer-ui/src/main/frontend/resources/scss/common/_customVariables.scss b/workflow-designer-ui/src/main/frontend/resources/scss/common/_customVariables.scss index 1a532c88..5e5bef84 100644 --- a/workflow-designer-ui/src/main/frontend/resources/scss/common/_customVariables.scss +++ b/workflow-designer-ui/src/main/frontend/resources/scss/common/_customVariables.scss @@ -1,6 +1,9 @@ $cursor-disabled: not-allowed !default; $cursor-pointer: pointer; +$camunda-panel-error-border-color: #cc3333; +$camunda-panel-error-background-color: #f0c2c2; + @mixin body-1-emphasis() { @include base-font-semibold; font-size: $body-font-1; diff --git a/workflow-designer-ui/src/main/frontend/resources/scss/features/_composition.scss b/workflow-designer-ui/src/main/frontend/resources/scss/features/_composition.scss index 119bbf02..6554219c 100644 --- a/workflow-designer-ui/src/main/frontend/resources/scss/features/_composition.scss +++ b/workflow-designer-ui/src/main/frontend/resources/scss/features/_composition.scss @@ -7,19 +7,37 @@ flex-grow: 1 } .bpmn-sidebar { + background-color: $light-silver; height: 100%; width: 320px; + height: 100%; + label { + @include body-1; + } + .group-label { + @include heading-4-emphasis; + font-size: 110%; + } .properties-panel { + background-color: $light-silver; + max-height: 888px; + overflow-y: auto; &, .bpp-properties-panel { - height: 100%; + background-color: $light-silver; + #camunda-activitySelect-select { + &.invalid { + border-color: $camunda-panel-error-border-color; + background-color: $camunda-panel-error-background-color; + } + } } } .composition-buttons { position: fixed; - background-color: #fafafa; + background-color: $light-silver; left: 265px; bottom: 46px; - border: 1px solid lightgray; + border: 1px solid $light-gray; width: 189px; display: flex; flex-direction: row; @@ -29,7 +47,7 @@ padding: 10px; .divider { height: 35px; - border: 1px solid $silver; + border: 1px solid $light-gray; } .diagram-btn { diff --git a/workflow-designer-ui/src/main/frontend/resources/scss/features/_overview.scss b/workflow-designer-ui/src/main/frontend/resources/scss/features/_overview.scss index 24f632db..e299fa3d 100644 --- a/workflow-designer-ui/src/main/frontend/resources/scss/features/_overview.scss +++ b/workflow-designer-ui/src/main/frontend/resources/scss/features/_overview.scss @@ -59,10 +59,27 @@ } .overview-header { - @include heading-1; - text-transform: uppercase; - margin: 63px 0 35px 56px; + display: flex; + margin: 35px 60px 35px 60px; color: $blue; + justify-content: space-between; + .title { + @include heading-1; + text-transform: uppercase; + } + .go-catalog-btn { + fill: $blue; + @include heading-4; + &:hover { + fill: $light-blue; + color: $light-blue; + cursor: pointer; + } + .svg-icon { + width: 16px; + height: 16px; + } + } } @mixin version-page-box-shadow() { diff --git a/workflow-designer-ui/src/main/frontend/src/config/Configuration.js b/workflow-designer-ui/src/main/frontend/src/config/Configuration.js index 3e558dad..36ad33d7 100644 --- a/workflow-designer-ui/src/main/frontend/src/config/Configuration.js +++ b/workflow-designer-ui/src/main/frontend/src/config/Configuration.js @@ -53,6 +53,10 @@ const configuration = new Configuration(); 'restCatalogPrefix', configuration.get('defaultRestCatalogPrefix') ); + configuration.set( + 'activitiesRestPrefix', + configuration.get('activitiesRestPrefix') + ); configuration.set('appContextPath', configuration.get('appContextPath')); })(configuration); diff --git a/workflow-designer-ui/src/main/frontend/src/config/config.json b/workflow-designer-ui/src/main/frontend/src/config/config.json index f1121444..eb7d181b 100644 --- a/workflow-designer-ui/src/main/frontend/src/config/config.json +++ b/workflow-designer-ui/src/main/frontend/src/config/config.json @@ -1,5 +1,6 @@ { "version": "0.1", "appContextPath" : "/", - "defaultRestPrefix": "/wf" + "defaultRestPrefix": "/wf", + "activitiesRestPrefix": "/v1.0" } diff --git a/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesActions.js b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesActions.js index ab0a3c4c..833f6e5f 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesActions.js +++ b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesActions.js @@ -1,6 +1,25 @@ -import { SET_ACTIVITIES_LIST } from './activitiesConstants'; +/* +* Copyright © 2018 European Support Limited +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* + * http://www.apache.org/licenses/LICENSE-2.0 +* + * Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import { SET_ACTIVITIES_LIST, GET_ACTIVITIES } from './activitiesConstants'; export const setActivitiesList = payload => ({ type: SET_ACTIVITIES_LIST, payload }); + +export const getActivitiesList = () => ({ + type: GET_ACTIVITIES +}); diff --git a/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesApi.js b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesApi.js index 8e1afc15..10141e09 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesApi.js +++ b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesApi.js @@ -13,13 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import RestfulAPIUtil from 'services/restAPIUtil'; +import Configuration from 'config/Configuration.js'; +import { activityStatus } from './activitiesConstants'; -const mockActivities = { - results: [] -}; +function baseUrl() { + const restPrefix = Configuration.get('activitiesRestPrefix'); + return `${restPrefix}/activity-spec`; +} export default { fetchActivities: () => { - return Promise.resolve(mockActivities); + return RestfulAPIUtil.fetch( + `${baseUrl()}?status=${activityStatus.CERTIFIED}` + ); + }, + + fetchActivity: id => { + return RestfulAPIUtil.fetch(`${baseUrl()}/${id}/versions/latest`); } }; diff --git a/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesConstants.js b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesConstants.js index 54aed6a9..f99789c2 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesConstants.js +++ b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesConstants.js @@ -14,3 +14,11 @@ * limitations under the License. */ export const SET_ACTIVITIES_LIST = 'activites/SET_ACTIVITIES_LIST'; +export const GET_ACTIVITIES = 'activities/GET_ACTIVITIES'; + +export const activityStatus = { + CERTIFIED: 'Certified', + DRAFT: 'Draft', + DEPRICATED: 'Depricated', + DELETED: 'Deleted' +}; diff --git a/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSaga.js b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSaga.js new file mode 100644 index 00000000..2350b9c3 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSaga.js @@ -0,0 +1,41 @@ +/* +* Copyright © 2018 European Support Limited +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import { call, put, takeEvery, all } from 'redux-saga/effects'; +import { genericNetworkErrorAction } from 'src/appConstants'; +import { GET_ACTIVITIES } from './activitiesConstants'; +import activitiesApi from './activitiesApi'; +import { setActivitiesList } from './activitiesActions'; + +function* fetchActivities() { + try { + const activitiesList = yield call(activitiesApi.fetchActivities); + const updatedActivitiesList = yield all( + activitiesList.items.map(item => + call(activitiesApi.fetchActivity, item.id) + ) + ); + + yield put(setActivitiesList(updatedActivitiesList)); + } catch (error) { + yield put(genericNetworkErrorAction(error)); + } +} + +function* activitiesSaga() { + yield takeEvery(GET_ACTIVITIES, fetchActivities); +} + +export default activitiesSaga; diff --git a/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSelectors.js b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSelectors.js index 47a0975b..fc0c55ab 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSelectors.js +++ b/workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSelectors.js @@ -14,4 +14,9 @@ * limitations under the License. */ -export const activitiesSelector = state => state && state.activities; +export const activitiesSelector = state => + state && + state.activities.map(item => ({ + ...item, + value: item.name + })); diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/Composition.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/Composition.js index d322207d..ef48acd0 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/composition/Composition.js +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/Composition.js @@ -21,12 +21,14 @@ import { showErrorModalAction } from '../../../shared/modal/modalWrapperActions' import { getComposition } from './compositionSelectors'; import { getWorkflowName } from '../../workflow/workflowSelectors'; import { activitiesSelector } from 'features/activities/activitiesSelectors'; +import { getInputOutputForComposition } from 'features/version/inputOutput/inputOutputSelectors'; function mapStateToProps(state) { return { composition: getComposition(state), name: getWorkflowName(state), - activities: activitiesSelector(state) + activities: activitiesSelector(state), + inputOutput: getInputOutputForComposition(state) }; } @@ -40,7 +42,7 @@ function mapDispatchToProps(dispatch) { title: I18n.t('workflow.composition.bpmnError'), body: msg, withButtons: true, - closeButtonText: 'Ok' + closeButtonText: I18n.t('buttons.okBtn') }) ) }; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js index f47a6ecc..012ee769 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js @@ -17,23 +17,28 @@ import React, { Component } from 'react'; import fileSaver from 'file-saver'; import CustomModeler from './custom-modeler'; import propertiesPanelModule from 'bpmn-js-properties-panel'; -import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'; -import camundaModuleDescriptor from 'camunda-bpmn-moddle/resources/camunda'; +import propertiesProviderModule from './custom-properties-provider/provider/camunda'; +import camundaModuleDescriptor from './custom-properties-provider/descriptors/camunda'; import newDiagramXML from './newDiagram.bpmn'; import PropTypes from 'prop-types'; import CompositionButtons from './components/CompositionButtonsPanel'; +import { setElementInputsOutputs } from './bpmnUtils.js'; +import { I18n } from 'react-redux-i18n'; class CompositionView extends Component { static propTypes = { compositionUpdate: PropTypes.func, showErrorModal: PropTypes.func, - composition: PropTypes.bool, - name: PropTypes.string + composition: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), + name: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), + inputOutput: PropTypes.object, + activities: PropTypes.array }; constructor() { super(); this.generatedId = 'bpmn-container' + Date.now(); this.fileInput = React.createRef(); + this.selectedElement = false; this.state = { diagram: false }; @@ -52,44 +57,59 @@ class CompositionView extends Component { ], moddleExtensions: { camunda: camundaModuleDescriptor + }, + workflow: { + activities: this.props.activities, + onChange: this.onActivityChanged } }); - window.modeler = this.modeler; + this.modeler.attachTo('#' + this.generatedId); - this.setDiagram(composition ? composition : newDiagramXML); - var eventBus = this.modeler.get('eventBus'); - eventBus.on('element.out', () => { - this.exportDiagramToStore(); - }); + this.setDiagramToBPMN(composition ? composition : newDiagramXML); + this.modeler.on('element.out', () => this.exportDiagramToStore()); } - - setDiagram = diagram => { - this.setState( - { - diagram - }, - this.importXML + onActivityChanged = async (bo, selectedValue) => { + const selectedActivity = this.props.activities.find( + el => el.name === selectedValue ); + + if (selectedActivity) { + const inputsOutputs = { + inputs: selectedActivity.inputs, + outputs: selectedActivity.outputs + }; + setElementInputsOutputs( + bo, + inputsOutputs, + this.modeler.get('moddle') + ); + } }; - importXML = () => { - const { diagram } = this.state; + setDiagramToBPMN = diagram => { let modeler = this.modeler; this.modeler.importXML(diagram, err => { if (err) { - //TDOD add i18n - return this.props.showErrorModal('could not import diagram'); + return this.props.showErrorModal( + I18n.t('workflow.composition.importErrorMsg') + ); } let canvas = modeler.get('canvas'); canvas.zoom('fit-viewport'); + setElementInputsOutputs( + canvas._rootElement.businessObject, + this.props.inputOutput, + this.modeler.get('moddle') + ); }); }; exportDiagramToStore = () => { this.modeler.saveXML({ format: true }, (err, xml) => { if (err) { - //TODO add i18n - return this.props.showErrorModal('could not save diagram'); + return this.props.showErrorModal( + I18n.t('workflow.composition.saveErrorMsg') + ); } return this.props.compositionUpdate(xml); }); @@ -99,8 +119,9 @@ class CompositionView extends Component { const { name, showErrorModal } = this.props; this.modeler.saveXML({ format: true }, (err, xml) => { if (err) { - //TODO add i18n - return showErrorModal('could not save diagram'); + return showErrorModal( + I18n.t('workflow.composition.exportErrorMsg') + ); } const blob = new Blob([xml], { type: 'text/html;charset=utf-8' }); fileSaver.saveAs(blob, `${name}-diagram.bpmn`); @@ -108,7 +129,7 @@ class CompositionView extends Component { }; loadNewDiagram = () => { - this.setDiagram(newDiagramXML); + this.setDiagramToBPMN(newDiagramXML); }; uploadDiagram = () => { @@ -120,7 +141,7 @@ class CompositionView extends Component { const reader = new FileReader(); reader.onloadend = event => { var xml = event.target.result; - this.setDiagram(xml); + this.setDiagramToBPMN(xml); this.fileInput.value = ''; }; reader.readAsText(file); diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/bpmnUtils.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/bpmnUtils.js new file mode 100644 index 00000000..adc42868 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/bpmnUtils.js @@ -0,0 +1,77 @@ +/* +* Copyright © 2018 European Support Limited +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +*http://www.apache.org/licenses/LICENSE-2.0 +* + * Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import { bpmnElementsTypes } from './compositionConstants'; +function getExtension(element, type) { + if (!element.extensionElements || !element.extensionElements.values) { + return null; + } + + return element.extensionElements.values.filter(function(e) { + return e.$instanceOf(type); + })[0]; +} + +export function updatedData(moddle, inputData, existingArray, type) { + return inputData.map(item => { + const existingInput = existingArray.find(el => el.name === item.name); + return moddle.create( + type, + existingInput ? { ...item, value: existingInput.value } : item + ); + }); +} + +export function setElementInputsOutputs(businessObject, inputOutput, moddle) { + const { inputs = [], outputs = [] } = inputOutput; + + if (!businessObject.extensionElements) { + businessObject.extensionElements = moddle.create( + bpmnElementsTypes.EXTENSION_ElEMENTS + ); + } + + const existingInputOutput = getExtension( + businessObject, + bpmnElementsTypes.INPUT_OUTPUT + ); + + const processInputs = updatedData( + moddle, + inputs, + (existingInputOutput && existingInputOutput.inputParameters) || [], + bpmnElementsTypes.INPUT_PARAMETER + ); + + const processOutputs = updatedData( + moddle, + outputs, + (existingInputOutput && existingInputOutput.outputParameters) || [], + bpmnElementsTypes.OUTPUT_PARAMETER + ); + + const processInputOutput = moddle.create(bpmnElementsTypes.INPUT_OUTPUT); + processInputOutput.inputParameters = [...processInputs]; + processInputOutput.outputParameters = [...processOutputs]; + + const extensionElements = businessObject.extensionElements.get('values'); + + businessObject.extensionElements.set( + 'values', + extensionElements + .filter(item => item.$type !== bpmnElementsTypes.INPUT_OUTPUT) + .concat(processInputOutput) + ); +} diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionConstants.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionConstants.js index 74cab0cb..499e8ef9 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionConstants.js +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionConstants.js @@ -14,3 +14,10 @@ * limitations under the License. */ export const SET_COMPOSITION = 'composition/SET_COMPOSITION'; + +export const bpmnElementsTypes = { + EXTENSION_ElEMENTS: 'bpmn:ExtensionElements', + INPUT_OUTPUT: 'camunda:InputOutput', + INPUT_PARAMETER: 'camunda:InputParameter', + OUTPUT_PARAMETER: 'camunda:OutputParameter' +}; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/descriptors/camunda.json b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/descriptors/camunda.json new file mode 100644 index 00000000..80e876aa --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/descriptors/camunda.json @@ -0,0 +1,1020 @@ +{ + "name": "Camunda", + "uri": "http://camunda.org/schema/1.0/bpmn", + "prefix": "camunda", + "xml": { + "tagAlias": "lowerCase" + }, + "associations": [], + "types": [ + { + "name": "InOutBinding", + "superClass": ["Element"], + "isAbstract": true, + "properties": [ + { + "name": "source", + "isAttr": true, + "type": "String" + }, + { + "name": "sourceExpression", + "isAttr": true, + "type": "String" + }, + { + "name": "target", + "isAttr": true, + "type": "String" + }, + { + "name": "businessKey", + "isAttr": true, + "type": "String" + }, + { + "name": "local", + "isAttr": true, + "type": "Boolean", + "default": false + }, + { + "name": "variables", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "In", + "superClass": ["InOutBinding"], + "meta": { + "allowedIn": ["bpmn:CallActivity"] + } + }, + { + "name": "Out", + "superClass": ["InOutBinding"], + "meta": { + "allowedIn": ["bpmn:CallActivity"] + } + }, + { + "name": "AsyncCapable", + "isAbstract": true, + "extends": ["bpmn:Activity", "bpmn:Gateway", "bpmn:Event"], + "properties": [ + { + "name": "async", + "isAttr": true, + "type": "Boolean", + "default": false + }, + { + "name": "asyncBefore", + "isAttr": true, + "type": "Boolean", + "default": false + }, + { + "name": "asyncAfter", + "isAttr": true, + "type": "Boolean", + "default": false + }, + { + "name": "exclusive", + "isAttr": true, + "type": "Boolean", + "default": true + } + ] + }, + { + "name": "JobPriorized", + "isAbstract": true, + "extends": ["bpmn:Process", "camunda:AsyncCapable"], + "properties": [ + { + "name": "jobPriority", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "SignalEventDefinition", + "isAbstract": true, + "extends": ["bpmn:SignalEventDefinition"], + "properties": [ + { + "name": "async", + "isAttr": true, + "type": "Boolean", + "default": false + } + ] + }, + { + "name": "ErrorEventDefinition", + "isAbstract": true, + "extends": ["bpmn:ErrorEventDefinition"], + "properties": [ + { + "name": "errorCodeVariable", + "isAttr": true, + "type": "String" + }, + { + "name": "errorMessageVariable", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "PotentialStarter", + "superClass": ["Element"], + "properties": [ + { + "name": "resourceAssignmentExpression", + "type": "bpmn:ResourceAssignmentExpression" + } + ] + }, + { + "name": "FormSupported", + "isAbstract": true, + "extends": ["bpmn:StartEvent", "bpmn:UserTask"], + "properties": [ + { + "name": "formHandlerClass", + "isAttr": true, + "type": "String" + }, + { + "name": "formKey", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "TemplateSupported", + "isAbstract": true, + "extends": ["bpmn:Process", "bpmn:FlowElement"], + "properties": [ + { + "name": "modelerTemplate", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Initiator", + "isAbstract": true, + "extends": ["bpmn:StartEvent"], + "properties": [ + { + "name": "initiator", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "ScriptTask", + "isAbstract": true, + "extends": ["bpmn:ScriptTask"], + "properties": [ + { + "name": "resultVariable", + "isAttr": true, + "type": "String" + }, + { + "name": "resource", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Process", + "isAbstract": true, + "extends": ["bpmn:Process"], + "properties": [ + { + "name": "candidateStarterGroups", + "isAttr": true, + "type": "String" + }, + { + "name": "candidateStarterUsers", + "isAttr": true, + "type": "String" + }, + { + "name": "versionTag", + "isAttr": true, + "type": "String" + }, + { + "name": "historyTimeToLive", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "EscalationEventDefinition", + "isAbstract": true, + "extends": ["bpmn:EscalationEventDefinition"], + "properties": [ + { + "name": "escalationCodeVariable", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "FormalExpression", + "isAbstract": true, + "extends": ["bpmn:FormalExpression"], + "properties": [ + { + "name": "resource", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Assignable", + "extends": ["bpmn:UserTask"], + "properties": [ + { + "name": "assignee", + "isAttr": true, + "type": "String" + }, + { + "name": "candidateUsers", + "isAttr": true, + "type": "String" + }, + { + "name": "candidateGroups", + "isAttr": true, + "type": "String" + }, + { + "name": "dueDate", + "isAttr": true, + "type": "String" + }, + { + "name": "followUpDate", + "isAttr": true, + "type": "String" + }, + { + "name": "priority", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "CallActivity", + "extends": ["bpmn:CallActivity"], + "properties": [ + { + "name": "calledElementBinding", + "isAttr": true, + "type": "String", + "default": "latest" + }, + { + "name": "calledElementVersion", + "isAttr": true, + "type": "String" + }, + { + "name": "calledElementTenantId", + "isAttr": true, + "type": "String" + }, + { + "name": "caseRef", + "isAttr": true, + "type": "String" + }, + { + "name": "caseBinding", + "isAttr": true, + "type": "String", + "default": "latest" + }, + { + "name": "caseVersion", + "isAttr": true, + "type": "String" + }, + { + "name": "caseTenantId", + "isAttr": true, + "type": "String" + }, + { + "name": "variableMappingClass", + "isAttr": true, + "type": "String" + }, + { + "name": "variableMappingDelegateExpression", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "ServiceTaskLike", + "extends": [ + "bpmn:ServiceTask", + "bpmn:BusinessRuleTask", + "bpmn:SendTask", + "bpmn:MessageEventDefinition" + ], + "properties": [ + { + "name": "expression", + "isAttr": true, + "type": "String" + }, + { + "name": "class", + "isAttr": true, + "type": "String" + }, + { + "name": "workflowActivity", + "isAttr": true, + "type": "String" + }, + { + "name": "delegateExpression", + "isAttr": true, + "type": "String" + }, + { + "name": "resultVariable", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "DmnCapable", + "extends": ["bpmn:BusinessRuleTask"], + "properties": [ + { + "name": "decisionRef", + "isAttr": true, + "type": "String" + }, + { + "name": "decisionRefBinding", + "isAttr": true, + "type": "String", + "default": "latest" + }, + { + "name": "decisionRefVersion", + "isAttr": true, + "type": "String" + }, + { + "name": "mapDecisionResult", + "isAttr": true, + "type": "String", + "default": "resultList" + }, + { + "name": "decisionRefTenantId", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "ExternalCapable", + "extends": ["camunda:ServiceTaskLike"], + "properties": [ + { + "name": "type", + "isAttr": true, + "type": "String" + }, + { + "name": "topic", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "TaskPriorized", + "extends": ["bpmn:Process", "camunda:ExternalCapable"], + "properties": [ + { + "name": "taskPriority", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "Properties", + "superClass": ["Element"], + "meta": { + "allowedIn": ["*"] + }, + "properties": [ + { + "name": "values", + "type": "Property", + "isMany": true + } + ] + }, + { + "name": "Property", + "superClass": ["Element"], + "properties": [ + { + "name": "id", + "type": "String", + "isAttr": true + }, + { + "name": "name", + "type": "String", + "isAttr": true + }, + { + "name": "value", + "type": "String", + "isAttr": true + } + ] + }, + { + "name": "Connector", + "superClass": ["Element"], + "meta": { + "allowedIn": [ + "bpmn:ServiceTask", + "bpmn:BusinessRuleTask", + "bpmn:SendTask" + ] + }, + "properties": [ + { + "name": "inputOutput", + "type": "InputOutput" + }, + { + "name": "connectorId", + "type": "String" + } + ] + }, + { + "name": "WorkflowActivity", + "superClass": ["Element"], + "meta": { + "allowedIn": [ + "bpmn:ServiceTask", + "bpmn:BusinessRuleTask", + "bpmn:SendTask" + ] + }, + "properties": [ + { + "name": "activityId", + "type": "String" + } + ] + }, + { + "name": "InputOutput", + "superClass": ["Element"], + "meta": { + "allowedIn": [ + "bpmn:Task", + "bpmn:UserTask", + "bpmn:ServiceTask", + "bpmn:SendTask", + "bpmn:BusinessRuleTask", + "bpmn:ReceiveTask", + "bpmn:ScriptTask", + "bpmn:ManualTask", + "bpmn:GlobalUserTask", + "bpmn:GlobalScriptTask", + "bpmn:GlobalBusinessRuleTask", + "bpmn:GlobalTask", + "bpmn:GlobalManualTask", + "bpmn:SubProcess", + "bpmn:Transaction", + "bpmn:IntermediateCatchEvent", + "bpmn:IntermediateThrowEvent", + "bpmn:EndEvent", + "bpmn:ThrowEvent", + "bpmn:CatchEvent", + "bpmn:ImplicitThrowEvent", + "bpmn:CallActivity" + ] + }, + "properties": [ + { + "name": "inputOutput", + "type": "InputOutput" + }, + { + "name": "connectorId", + "type": "String" + }, + { + "name": "inputParameters", + "isMany": true, + "type": "InputParameter" + }, + { + "name": "outputParameters", + "isMany": true, + "type": "OutputParameter" + } + ] + }, + { + "name": "InputOutputParameter", + "properties": [ + { + "name": "name", + "isAttr": true, + "type": "String" + }, + { + "name": "value", + "isBody": true, + "type": "String" + }, + { + "name": "definition", + "type": "InputOutputParameterDefinition" + } + ] + }, + { + "name": "InputOutputParameterDefinition", + "isAbstract": true + }, + { + "name": "List", + "superClass": ["InputOutputParameterDefinition"], + "properties": [ + { + "name": "items", + "isMany": true, + "type": "InputOutputParameterDefinition" + } + ] + }, + { + "name": "Map", + "superClass": ["InputOutputParameterDefinition"], + "properties": [ + { + "name": "entries", + "isMany": true, + "type": "Entry" + } + ] + }, + { + "name": "Entry", + "properties": [ + { + "name": "key", + "isAttr": true, + "type": "String" + }, + { + "name": "value", + "isBody": true, + "type": "String" + }, + { + "name": "definition", + "type": "InputOutputParameterDefinition" + } + ] + }, + { + "name": "Value", + "superClass": ["InputOutputParameterDefinition"], + "properties": [ + { + "name": "id", + "isAttr": true, + "type": "String" + }, + { + "name": "name", + "isAttr": true, + "type": "String" + }, + { + "name": "value", + "isBody": true, + "type": "String" + } + ] + }, + { + "name": "Script", + "superClass": ["InputOutputParameterDefinition"], + "properties": [ + { + "name": "scriptFormat", + "isAttr": true, + "type": "String" + }, + { + "name": "resource", + "isAttr": true, + "type": "String" + }, + { + "name": "value", + "isBody": true, + "type": "String" + } + ] + }, + { + "name": "Field", + "superClass": ["Element"], + "meta": { + "allowedIn": [ + "bpmn:ServiceTask", + "bpmn:BusinessRuleTask", + "bpmn:SendTask" + ] + }, + "properties": [ + { + "name": "name", + "isAttr": true, + "type": "String" + }, + { + "name": "expression", + "type": "String" + }, + { + "name": "stringValue", + "isAttr": true, + "type": "String" + }, + { + "name": "string", + "type": "String" + } + ] + }, + { + "name": "InputParameter", + "superClass": ["InputOutputParameter"] + }, + { + "name": "OutputParameter", + "superClass": ["InputOutputParameter"] + }, + { + "name": "Collectable", + "isAbstract": true, + "extends": ["bpmn:MultiInstanceLoopCharacteristics"], + "superClass": ["camunda:AsyncCapable"], + "properties": [ + { + "name": "collection", + "isAttr": true, + "type": "String" + }, + { + "name": "elementVariable", + "isAttr": true, + "type": "String" + } + ] + }, + { + "name": "FailedJobRetryTimeCycle", + "superClass": ["Element"], + "meta": { + "allowedIn": [ + "bpmn:Task", + "bpmn:ServiceTask", + "bpmn:SendTask", + "bpmn:UserTask", + "bpmn:BusinessRuleTask", + "bpmn:ScriptTask", + "bpmn:ReceiveTask", + "bpmn:CallActivity", + "bpmn:TimerEventDefinition", + "bpmn:SignalEventDefinition", + "bpmn:MultiInstanceLoopCharacteristics" + ] + }, + "properties": [ + { + "name": "body", + "isBody": true, + "type": "String" + } + ] + }, + { + "name": "ExecutionListener", + "superClass": ["Element"], + "meta": { + "allowedIn": [ + "bpmn:Task", + "bpmn:ServiceTask", + "bpmn:UserTask", + "bpmn:BusinessRuleTask", + "bpmn:ScriptTask", + "bpmn:ReceiveTask", + "bpmn:ManualTask", + "bpmn:ExclusiveGateway", + "bpmn:SequenceFlow", + "bpmn:ParallelGateway", + "bpmn:InclusiveGateway", + "bpmn:EventBasedGateway", + "bpmn:StartEvent", + "bpmn:IntermediateCatchEvent", + "bpmn:IntermediateThrowEvent", + "bpmn:EndEvent", + "bpmn:BoundaryEvent", + "bpmn:CallActivity", + "bpmn:SubProcess" + ] + }, + "properties": [ + { + "name": "expression", + "isAttr": true, + "type": "String" + }, + { + "name": "class", + "isAttr": true, + "type": "String" + }, + { + "name": "delegateExpression", + "isAttr": true, + "type": "String" + }, + { + "name": "event", + "isAttr": true, + "type": "String" + }, + { + "name": "script", + "type": "Script" + }, + { + "name": "fields", + "type": "Field", + "isMany": true + } + ] + }, + { + "name": "TaskListener", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:UserTask"] + }, + "properties": [ + { + "name": "expression", + "isAttr": true, + "type": "String" + }, + { + "name": "class", + "isAttr": true, + "type": "String" + }, + { + "name": "delegateExpression", + "isAttr": true, + "type": "String" + }, + { + "name": "event", + "isAttr": true, + "type": "String" + }, + { + "name": "script", + "type": "Script" + }, + { + "name": "fields", + "type": "Field", + "isMany": true + } + ] + }, + { + "name": "FormProperty", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:StartEvent", "bpmn:UserTask"] + }, + "properties": [ + { + "name": "id", + "type": "String", + "isAttr": true + }, + { + "name": "name", + "type": "String", + "isAttr": true + }, + { + "name": "type", + "type": "String", + "isAttr": true + }, + { + "name": "required", + "type": "String", + "isAttr": true + }, + { + "name": "readable", + "type": "String", + "isAttr": true + }, + { + "name": "writable", + "type": "String", + "isAttr": true + }, + { + "name": "variable", + "type": "String", + "isAttr": true + }, + { + "name": "expression", + "type": "String", + "isAttr": true + }, + { + "name": "datePattern", + "type": "String", + "isAttr": true + }, + { + "name": "default", + "type": "String", + "isAttr": true + }, + { + "name": "values", + "type": "Value", + "isMany": true + } + ] + }, + { + "name": "FormData", + "superClass": ["Element"], + "meta": { + "allowedIn": ["bpmn:StartEvent", "bpmn:UserTask"] + }, + "properties": [ + { + "name": "fields", + "type": "FormField", + "isMany": true + }, + { + "name": "businessKey", + "type": "String", + "isAttr": true + } + ] + }, + { + "name": "FormField", + "superClass": ["Element"], + "properties": [ + { + "name": "id", + "type": "String", + "isAttr": true + }, + { + "name": "label", + "type": "String", + "isAttr": true + }, + { + "name": "type", + "type": "String", + "isAttr": true + }, + { + "name": "datePattern", + "type": "String", + "isAttr": true + }, + { + "name": "defaultValue", + "type": "String", + "isAttr": true + }, + { + "name": "properties", + "type": "Properties" + }, + { + "name": "validation", + "type": "Validation" + }, + { + "name": "values", + "type": "Value", + "isMany": true + } + ] + }, + { + "name": "Validation", + "superClass": ["Element"], + "properties": [ + { + "name": "constraints", + "type": "Constraint", + "isMany": true + } + ] + }, + { + "name": "Constraint", + "superClass": ["Element"], + "properties": [ + { + "name": "name", + "type": "String", + "isAttr": true + }, + { + "name": "config", + "type": "String", + "isAttr": true + } + ] + }, + { + "name": "ConditionalEventDefinition", + "isAbstract": true, + "extends": ["bpmn:ConditionalEventDefinition"], + "properties": [ + { + "name": "variableName", + "isAttr": true, + "type": "String" + }, + { + "name": "variableEvent", + "isAttr": true, + "type": "String" + } + ] + } + ], + "emumerations": [] +} diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/WorkflowPropertiesProvider.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/WorkflowPropertiesProvider.js new file mode 100644 index 00000000..98a5797d --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/WorkflowPropertiesProvider.js @@ -0,0 +1,301 @@ +import inherits from 'inherits'; +import CamundaPropertiesProvider from 'bpmn-js-properties-panel/lib/provider/camunda/CamundaPropertiesProvider'; + +import { is, getBusinessObject } from 'bpmn-js/lib/util/ModelUtil'; + +import asyncCapableHelper from 'bpmn-js-properties-panel/lib/helper/AsyncCapableHelper'; +import eventDefinitionHelper from 'bpmn-js-properties-panel/lib/helper/EventDefinitionHelper'; +import implementationTypeHelper from 'bpmn-js-properties-panel/lib/helper/ImplementationTypeHelper'; + +import idProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/IdProps'; +import nameProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/NameProps'; +import processProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/ProcessProps'; +import executableProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/ExecutableProps'; +import linkProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/LinkProps'; +import eventProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/EventProps'; +import documentationProps from 'bpmn-js-properties-panel/lib/provider/bpmn/parts/DocumentationProps'; + +import elementTemplateChooserProps from 'bpmn-js-properties-panel/lib/provider/camunda/element-templates/parts/ChooserProps'; +import elementTemplateCustomProps from 'bpmn-js-properties-panel/lib/provider/camunda/element-templates/parts/CustomProps'; + +import versionTag from 'bpmn-js-properties-panel/lib/provider/camunda/parts/VersionTagProps'; +import userTaskProps from 'bpmn-js-properties-panel/lib/provider/camunda/parts/UserTaskProps'; +import scriptProps from 'bpmn-js-properties-panel/lib/provider/camunda/parts/ScriptTaskProps'; +import callActivityProps from 'bpmn-js-properties-panel/lib/provider/camunda/parts/CallActivityProps'; +import conditionalProps from 'bpmn-js-properties-panel/lib/provider/camunda/parts/ConditionalProps'; +import startEventInitiator from 'bpmn-js-properties-panel/lib/provider/camunda/parts/StartEventInitiator'; +import multiInstanceProps from 'bpmn-js-properties-panel/lib/provider/camunda/parts/MultiInstanceLoopProps'; +import asynchronousContinuationProps from 'bpmn-js-properties-panel/lib/provider/camunda/parts/AsynchronousContinuationProps'; +import jobConfiguration from 'bpmn-js-properties-panel/lib/provider/camunda/parts/JobConfigurationProps'; +import externalTaskConfiguration from 'bpmn-js-properties-panel/lib/provider/camunda/parts/ExternalTaskConfigurationProps'; +import candidateStarter from 'bpmn-js-properties-panel/lib/provider/camunda/parts/CandidateStarterProps'; +import historyTimeToLive from 'bpmn-js-properties-panel/lib/provider/camunda/parts/HistoryTimeToLiveProps'; + +import createInputOutputTabGroups from './parts/createInputOutputTabGroups'; +import workflowServiceTaskDelegateProps from './parts/WorkflowServiceTaskDelegateProps'; + +const PROCESS_KEY_HINT = 'This maps to the process definition key.'; + +const isExternalTaskPriorityEnabled = function(element) { + const businessObject = getBusinessObject(element); + + // show only if element is a process, a participant ... + if ( + is(element, 'bpmn:Process') || + (is(element, 'bpmn:Participant') && businessObject.get('processRef')) + ) { + return true; + } + + const externalBo = implementationTypeHelper.getServiceTaskLikeBusinessObject( + element + ), + isExternalTask = + implementationTypeHelper.getImplementationType(externalBo) === + 'external'; + + // ... or an external task with selected external implementation type + return ( + !!implementationTypeHelper.isExternalCapable(externalBo) && + isExternalTask + ); +}; + +const isJobConfigEnabled = element => { + const businessObject = getBusinessObject(element); + + if ( + is(element, 'bpmn:Process') || + (is(element, 'bpmn:Participant') && businessObject.get('processRef')) + ) { + return true; + } + + // async behavior + const bo = getBusinessObject(element); + if ( + asyncCapableHelper.isAsyncBefore(bo) || + asyncCapableHelper.isAsyncAfter(bo) + ) { + return true; + } + + // timer definition + if (is(element, 'bpmn:Event')) { + return !!eventDefinitionHelper.getTimerEventDefinition(element); + } + + return false; +}; + +function createGeneralTabGroups( + element, + config, + bpmnFactory, + elementRegistry, + elementTemplates, + translate +) { + // refer to target element for external labels + element = element.labelTarget || element; + + const generalGroup = { + id: 'general', + label: translate('General'), + entries: [] + }; + + let idOptions; + let processOptions; + + if (is(element, 'bpmn:Process')) { + idOptions = { description: PROCESS_KEY_HINT }; + } + + if (is(element, 'bpmn:Participant')) { + processOptions = { processIdDescription: PROCESS_KEY_HINT }; + } + + idProps(generalGroup, element, translate, idOptions); + nameProps(generalGroup, element, translate); + processProps(generalGroup, element, translate, processOptions); + versionTag(generalGroup, element, translate); + executableProps(generalGroup, element, translate); + elementTemplateChooserProps( + generalGroup, + element, + elementTemplates, + translate + ); + + const customFieldsGroups = elementTemplateCustomProps( + element, + elementTemplates, + bpmnFactory, + translate + ); + + const detailsGroup = { + id: 'details', + label: translate('Details'), + entries: [] + }; + workflowServiceTaskDelegateProps( + detailsGroup, + element, + config, + bpmnFactory, + translate + ); + userTaskProps(detailsGroup, element, translate); + scriptProps(detailsGroup, element, bpmnFactory, translate); + linkProps(detailsGroup, element, translate); + callActivityProps(detailsGroup, element, bpmnFactory, translate); + eventProps(detailsGroup, element, bpmnFactory, elementRegistry, translate); + conditionalProps(detailsGroup, element, bpmnFactory, translate); + startEventInitiator(detailsGroup, element, translate); // this must be the last element of the details group! + + const multiInstanceGroup = { + id: 'multiInstance', + label: translate('Multi Instance'), + entries: [] + }; + multiInstanceProps(multiInstanceGroup, element, bpmnFactory, translate); + + const asyncGroup = { + id: 'async', + label: translate('Asynchronous Continuations'), + entries: [] + }; + asynchronousContinuationProps(asyncGroup, element, bpmnFactory, translate); + + const jobConfigurationGroup = { + id: 'jobConfiguration', + label: translate('Job Configuration'), + entries: [], + enabled: isJobConfigEnabled + }; + jobConfiguration(jobConfigurationGroup, element, bpmnFactory, translate); + + const externalTaskGroup = { + id: 'externalTaskConfiguration', + label: translate('External Task Configuration'), + entries: [], + enabled: isExternalTaskPriorityEnabled + }; + externalTaskConfiguration( + externalTaskGroup, + element, + bpmnFactory, + translate + ); + + const candidateStarterGroup = { + id: 'candidateStarterConfiguration', + label: translate('Candidate Starter Configuration'), + entries: [] + }; + candidateStarter(candidateStarterGroup, element, bpmnFactory, translate); + + const historyTimeToLiveGroup = { + id: 'historyConfiguration', + label: translate('History Configuration'), + entries: [] + }; + historyTimeToLive(historyTimeToLiveGroup, element, bpmnFactory, translate); + + const documentationGroup = { + id: 'documentation', + label: translate('Documentation'), + entries: [] + }; + documentationProps(documentationGroup, element, bpmnFactory, translate); + + const groups = []; + groups.push(generalGroup); + customFieldsGroups.forEach(function(group) { + groups.push(group); + }); + groups.push(detailsGroup); + groups.push(externalTaskGroup); + groups.push(multiInstanceGroup); + groups.push(asyncGroup); + groups.push(jobConfigurationGroup); + groups.push(candidateStarterGroup); + groups.push(historyTimeToLiveGroup); + groups.push(documentationGroup); + + return groups; +} + +function WorkflowPropertiesProvider( + config, + eventBus, + bpmnFactory, + elementRegistry, + elementTemplates, + translate +) { + CamundaPropertiesProvider.call( + this, + eventBus, + bpmnFactory, + elementRegistry, + elementTemplates, + translate + ); + + this.getTabs = function(element) { + const camundaPropertiesProvider = new CamundaPropertiesProvider( + eventBus, + bpmnFactory, + elementRegistry, + elementTemplates, + translate + ); + + const tabs = camundaPropertiesProvider + .getTabs(element) + .filter(tab => tab.id !== 'general' && tab.id !== 'input-output'); + + const generalTab = { + id: 'general', + label: translate('General'), + groups: createGeneralTabGroups( + element, + config, + bpmnFactory, + elementRegistry, + elementTemplates, + translate + ) + }; + + const inputOutputTab = { + id: 'input-output', + label: translate('Input/Output'), + groups: createInputOutputTabGroups( + element, + bpmnFactory, + elementRegistry, + translate + ) + }; + tabs.unshift(inputOutputTab); + tabs.unshift(generalTab); + return tabs; + }; +} + +WorkflowPropertiesProvider.$inject = [ + 'config.workflow', + 'eventBus', + 'bpmnFactory', + 'elementRegistry', + 'elementTemplates', + 'translate' +]; + +inherits(WorkflowPropertiesProvider, CamundaPropertiesProvider); + +export default WorkflowPropertiesProvider; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/index.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/index.js new file mode 100644 index 00000000..bc60c581 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/index.js @@ -0,0 +1,10 @@ +import ElementTemplates from 'bpmn-js-properties-panel/lib/provider/camunda/element-templates'; +import Translate from 'diagram-js/lib/i18n/translate'; + +import WorkflowPropertiesProvider from './WorkflowPropertiesProvider'; + +export default { + __depends__: [ElementTemplates, Translate], + __init__: ['propertiesProvider'], + propertiesProvider: ['type', WorkflowPropertiesProvider] +}; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputParameterProps.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputParameterProps.js new file mode 100644 index 00000000..a1f1efb0 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputParameterProps.js @@ -0,0 +1,15 @@ +'use strict'; + +import inputOutputParameter from './implementation/InputOutputParameter'; +import assign from 'lodash.assign'; + +module.exports = function(group, element, bpmnFactory, options, translate) { + group.entries = group.entries.concat( + inputOutputParameter( + element, + bpmnFactory, + assign({}, options), + translate + ) + ); +}; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputProps.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputProps.js new file mode 100644 index 00000000..df1e5432 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputProps.js @@ -0,0 +1,13 @@ +'use strict'; + +var inputOutput = require('./implementation/InputOutput'); + +module.exports = function(group, element, bpmnFactory, translate) { + var inputOutputEntry = inputOutput(element, bpmnFactory, {}, translate); + + group.entries = group.entries.concat(inputOutputEntry.entries); + + return { + getSelectedParameter: inputOutputEntry.getSelectedParameter + }; +}; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/WorkflowServiceTaskDelegateProps.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/WorkflowServiceTaskDelegateProps.js new file mode 100644 index 00000000..dbd12cb6 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/WorkflowServiceTaskDelegateProps.js @@ -0,0 +1,85 @@ +import inherits from 'inherits'; + +import ImplementationTypeHelper from 'bpmn-js-properties-panel/lib/helper/ImplementationTypeHelper'; +import ServiceTaskDelegateProps from 'bpmn-js-properties-panel/lib/provider/camunda/parts/ServiceTaskDelegateProps'; +import workflowImplementationType from './implementation/WorkflowImplementationType'; +import workflowActivity from './implementation/WorkflowActivity'; +import { implementationType as implementationTypeConst } from './implementation/implementationConstants'; + +const getImplementationType = element => { + let implementationType = ImplementationTypeHelper.getImplementationType( + element + ); + + if (!implementationType) { + const bo = getBusinessObject(element); + if (bo) { + if ( + typeof bo.get(implementationTypeConst.ACTIVITY) !== 'undefined' + ) { + return 'workflowActivity'; + } + } + } + + return implementationType; +}; + +const getBusinessObject = element => + ImplementationTypeHelper.getServiceTaskLikeBusinessObject(element); + +const isDmnCapable = element => ImplementationTypeHelper.isDmnCapable(element); + +const isExternalCapable = element => + ImplementationTypeHelper.isExternalCapable(element); + +const isServiceTaskLike = element => + ImplementationTypeHelper.isServiceTaskLike(element); + +function WorkflowServiceTaskDelegateProps( + group, + element, + config, + bpmnFactory, + translate +) { + ServiceTaskDelegateProps.call(this, group, element, bpmnFactory, translate); + + if (isServiceTaskLike(getBusinessObject(element))) { + group.entries = group.entries.filter( + entry => entry.id !== 'implementation' + ); + + group.entries = [ + ...workflowImplementationType( + element, + bpmnFactory, + { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType, + hasDmnSupport: isDmnCapable(element), + hasExternalSupport: isExternalCapable( + getBusinessObject(element) + ), + hasServiceTaskLikeSupport: true + }, + translate + ), + ...group.entries, + ...workflowActivity( + element, + config, + bpmnFactory, + { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType + }, + translate + ) + ]; + } +} + +inherits(WorkflowServiceTaskDelegateProps, ServiceTaskDelegateProps); + +export default WorkflowServiceTaskDelegateProps; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/createInputOutputTabGroups.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/createInputOutputTabGroups.js new file mode 100644 index 00000000..f14e359f --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/createInputOutputTabGroups.js @@ -0,0 +1,57 @@ +let inputOutputParameter = require('./InputOutputParameterProps'); +let inputOutput = require('./InputOutputProps'); +var is = require('bpmn-js/lib/util/ModelUtil').is; + +var getInputOutputParameterLabel = function(param, translate) { + if (is(param, 'camunda:InputParameter')) { + return translate('Input Parameter'); + } + + if (is(param, 'camunda:OutputParameter')) { + return translate('Output Parameter'); + } + + return ''; +}; + +export default function createInputOutputTabGroups( + element, + bpmnFactory, + elementRegistry, + translate +) { + var inputOutputGroup = { + id: 'input-output', + label: translate('Parameters'), + entries: [] + }; + + var options = inputOutput( + inputOutputGroup, + element, + bpmnFactory, + translate + ); + + var inputOutputParameterGroup = { + id: 'input-output-parameter', + entries: [], + enabled: function(element, node) { + return options.getSelectedParameter(element, node); + }, + label: function(element, node) { + var param = options.getSelectedParameter(element, node); + return getInputOutputParameterLabel(param, translate); + } + }; + + inputOutputParameter( + inputOutputParameterGroup, + element, + bpmnFactory, + options, + translate + ); + + return [inputOutputGroup, inputOutputParameterGroup]; +} diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutput.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutput.js new file mode 100644 index 00000000..555b4af7 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutput.js @@ -0,0 +1,297 @@ +'use strict'; +import { + IMPLEMENTATION_TYPE_VALUE, + implementationType +} from './implementationConstants'; +var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject; + +var elementHelper = require('bpmn-js-properties-panel/lib/helper/ElementHelper'), + extensionElementsHelper = require('bpmn-js-properties-panel/lib/helper/ExtensionElementsHelper'), + inputOutputHelper = require('./InputOutputHelper'), + cmdHelper = require('bpmn-js-properties-panel/lib/helper/CmdHelper'); + +var extensionElementsEntry = require('bpmn-js-properties-panel/lib/provider/camunda/parts/implementation//ExtensionElements'); + +function isCreateDeleteSupported(element) { + const bo = getBusinessObject(element); + return ( + (element.type !== 'bpmn:ServiceTask' || + bo[implementationType.ACTIVITY] !== IMPLEMENTATION_TYPE_VALUE) && + element.type !== 'bpmn:Process' + ); +} + +function getInputOutput(element, insideConnector) { + return inputOutputHelper.getInputOutput(element, insideConnector); +} + +function getConnector(element) { + return inputOutputHelper.getConnector(element); +} + +function getInputParameters(element, insideConnector) { + return inputOutputHelper.getInputParameters(element, insideConnector); +} + +function getOutputParameters(element, insideConnector) { + return inputOutputHelper.getOutputParameters(element, insideConnector); +} + +function getInputParameter(element, insideConnector, idx) { + return inputOutputHelper.getInputParameter(element, insideConnector, idx); +} + +function getOutputParameter(element, insideConnector, idx) { + return inputOutputHelper.getOutputParameter(element, insideConnector, idx); +} + +function createElement(type, parent, factory, properties) { + const el = elementHelper.createElement(type, properties, parent, factory); + return el; +} + +function createInputOutput(parent, bpmnFactory, properties) { + return createElement( + 'camunda:InputOutput', + parent, + bpmnFactory, + properties + ); +} + +function createParameter(type, parent, bpmnFactory, properties) { + return createElement(type, parent, bpmnFactory, properties); +} + +function ensureInputOutputSupported(element, insideConnector) { + return inputOutputHelper.isInputOutputSupported(element, insideConnector); +} + +function ensureOutparameterSupported(element, insideConnector) { + return inputOutputHelper.areOutputParametersSupported( + element, + insideConnector + ); +} + +module.exports = function(element, bpmnFactory, options, translate) { + var TYPE_LABEL = { + 'camunda:Map': translate('Map'), + 'camunda:List': translate('List'), + 'camunda:Script': translate('Script') + }; + + options = options || {}; + + var insideConnector = !!options.insideConnector, + idPrefix = options.idPrefix || ''; + + var getSelected = function(element, node) { + var selection = (inputEntry && + inputEntry.getSelected(element, node)) || { idx: -1 }; + + var parameter = getInputParameter( + element, + insideConnector, + selection.idx + ); + if (!parameter && outputEntry) { + selection = outputEntry.getSelected(element, node); + parameter = getOutputParameter( + element, + insideConnector, + selection.idx + ); + } + return parameter; + }; + + var result = { + getSelectedParameter: getSelected + }; + + var entries = (result.entries = []); + + if (!ensureInputOutputSupported(element)) { + return result; + } + + var newElement = function(type, prop, elementData) { + return function(element, extensionElements, value) { + var commands = []; + + var inputOutput = getInputOutput(element, insideConnector); + if (!inputOutput) { + var parent = !insideConnector + ? extensionElements + : getConnector(element); + + inputOutput = createInputOutput(parent, bpmnFactory, { + inputParameters: [], + outputParameters: [] + }); + + if (!insideConnector) { + commands.push( + cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + 'extensionElements', + [inputOutput], + [] + ) + ); + } else { + commands.push( + cmdHelper.updateBusinessObject(element, parent, { + inputOutput: inputOutput + }) + ); + } + } + + var newElem = elementData + ? createParameter(type, inputOutput, bpmnFactory, elementData) + : createParameter(type, inputOutput, bpmnFactory, { + name: value + }); + + console.log(newElem); + + commands.push( + cmdHelper.addElementsTolist(element, inputOutput, prop, [ + newElem + ]) + ); + + return commands; + }; + }; + + var removeElement = function(getter, prop, otherProp) { + return function(element, extensionElements, value, idx) { + var inputOutput = getInputOutput(element, insideConnector); + var parameter = getter(element, insideConnector, idx); + + var commands = []; + commands.push( + cmdHelper.removeElementsFromList( + element, + inputOutput, + prop, + null, + [parameter] + ) + ); + + var firstLength = inputOutput.get(prop).length - 1; + var secondLength = (inputOutput.get(otherProp) || []).length; + + if (!firstLength && !secondLength) { + if (!insideConnector) { + commands.push( + extensionElementsHelper.removeEntry( + getBusinessObject(element), + element, + inputOutput + ) + ); + } else { + var connector = getConnector(element); + commands.push( + cmdHelper.updateBusinessObject(element, connector, { + inputOutput: undefined + }) + ); + } + } + + return commands; + }; + }; + + var setOptionLabelValue = function(getter) { + return function(element, node, option, property, value, idx) { + var parameter = getter(element, insideConnector, idx); + + var suffix = 'Text'; + + var definition = parameter.get('definition'); + if (typeof definition !== 'undefined') { + var type = definition.$type; + suffix = TYPE_LABEL[type]; + } + + option.text = (value || '') + ' : ' + suffix; + }; + }; + + // input parameters /////////////////////////////////////////////////////////////// + + var inputEntry = extensionElementsEntry(element, bpmnFactory, { + id: idPrefix + 'inputs', + label: translate('Input Parameters'), + modelProperty: 'name', + prefix: 'Input', + resizable: true, + + createExtensionElement: isCreateDeleteSupported(element) + ? newElement('camunda:InputParameter', 'inputParameters') + : undefined, + removeExtensionElement: isCreateDeleteSupported(element) + ? removeElement( + getInputParameter, + 'inputParameters', + 'outputParameters' + ) + : undefined, + + getExtensionElements: function(element) { + return getInputParameters(element, insideConnector); + }, + + onSelectionChange: function(element, node) { + outputEntry && outputEntry.deselect(element, node); + }, + + setOptionLabelValue: setOptionLabelValue(getInputParameter) + }); + entries.push(inputEntry); + + // output parameters /////////////////////////////////////////////////////// + + if (ensureOutparameterSupported(element, insideConnector)) { + var outputEntry = extensionElementsEntry(element, bpmnFactory, { + id: idPrefix + 'outputs', + label: translate('Output Parameters'), + modelProperty: 'name', + prefix: 'Output', + resizable: true, + + createExtensionElement: isCreateDeleteSupported(element) + ? newElement('camunda:OutputParameter', 'outputParameters') + : undefined, + removeExtensionElement: isCreateDeleteSupported(element) + ? removeElement( + getOutputParameter, + 'outputParameters', + 'inputParameters' + ) + : isCreateDeleteSupported(element), + + getExtensionElements: function(element) { + return getOutputParameters(element, insideConnector); + }, + + onSelectionChange: function(element, node) { + inputEntry.deselect(element, node); + }, + + setOptionLabelValue: setOptionLabelValue(getOutputParameter) + }); + entries.push(outputEntry); + } + + return result; +}; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputHelper.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputHelper.js new file mode 100644 index 00000000..e2943517 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputHelper.js @@ -0,0 +1,153 @@ +'use strict'; + +var ModelUtil = require('bpmn-js/lib/util/ModelUtil'), + is = ModelUtil.is, + getBusinessObject = ModelUtil.getBusinessObject; + +var extensionElementsHelper = require('bpmn-js-properties-panel/lib/helper/ExtensionElementsHelper'), + implementationTypeHelper = require('bpmn-js-properties-panel/lib/helper/ImplementationTypeHelper'); + +var InputOutputHelper = {}; + +module.exports = InputOutputHelper; + +function getElements(bo, type, prop) { + var elems = extensionElementsHelper.getExtensionElements(bo, type) || []; + return !prop ? elems : (elems[0] || {})[prop] || []; +} + +function getParameters(element, prop, insideConnector) { + var inputOutput = InputOutputHelper.getInputOutput( + element, + insideConnector + ); + return (inputOutput && inputOutput.get(prop)) || []; +} + +/** + * Get a inputOutput from the business object + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {ModdleElement} the inputOutput object + */ +InputOutputHelper.getInputOutput = function(element, insideConnector) { + if (!insideConnector) { + var bo = getBusinessObject(element); + return (getElements(bo, 'camunda:InputOutput') || [])[0]; + } + var connector = this.getConnector(element); + + return connector && connector.get('inputOutput'); +}; + +/** + * Get a connector from the business object + * + * @param {djs.model.Base} element + * + * @return {ModdleElement} the connector object + */ +InputOutputHelper.getConnector = function(element) { + var bo = implementationTypeHelper.getServiceTaskLikeBusinessObject(element); + return bo && (getElements(bo, 'camunda:Connector') || [])[0]; +}; + +/** + * Return all input parameters existing in the business object, and + * an empty array if none exist. + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {Array} a list of input parameter objects + */ +InputOutputHelper.getInputParameters = function(element, insideConnector) { + return getParameters.apply(this, [ + element, + 'inputParameters', + insideConnector + ]); +}; + +/** + * Return all output parameters existing in the business object, and + * an empty array if none exist. + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {Array} a list of output parameter objects + */ +InputOutputHelper.getOutputParameters = function(element, insideConnector) { + return getParameters.apply(this, [ + element, + 'outputParameters', + insideConnector + ]); +}; + +/** + * Get a input parameter from the business object at given index + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * @param {number} idx + * + * @return {ModdleElement} input parameter + */ +InputOutputHelper.getInputParameter = function(element, insideConnector, idx) { + return this.getInputParameters(element, insideConnector)[idx]; +}; + +/** + * Get a output parameter from the business object at given index + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * @param {number} idx + * + * @return {ModdleElement} output parameter + */ +InputOutputHelper.getOutputParameter = function(element, insideConnector, idx) { + return this.getOutputParameters(element, insideConnector)[idx]; +}; + +/** + * Returns 'true' if the given element supports inputOutput + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {boolean} a boolean value + */ +InputOutputHelper.isInputOutputSupported = function(element, insideConnector) { + var bo = getBusinessObject(element); + return ( + insideConnector || + is(bo, 'bpmn:Process') || + (is(bo, 'bpmn:FlowNode') && + !is(bo, 'bpmn:StartEvent') && + !is(bo, 'bpmn:BoundaryEvent') && + !(is(bo, 'bpmn:SubProcess') && bo.get('triggeredByEvent'))) + ); +}; + +/** + * Returns 'true' if the given element supports output parameters + * + * @param {djs.model.Base} element + * @param {boolean} insideConnector + * + * @return {boolean} a boolean value + */ +InputOutputHelper.areOutputParametersSupported = function( + element, + insideConnector +) { + var bo = getBusinessObject(element); + return ( + insideConnector || (!is(bo, 'bpmn:EndEvent') && !bo.loopCharacteristics) + ); +}; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputParameter.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputParameter.js new file mode 100644 index 00000000..da949dd9 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputParameter.js @@ -0,0 +1,433 @@ +'use strict'; + +var is = require('bpmn-js/lib/util/ModelUtil').is; + +var elementHelper = require('bpmn-js-properties-panel/lib/helper/ElementHelper'), + inputOutputHelper = require('./InputOutputHelper'), + cmdHelper = require('bpmn-js-properties-panel/lib/helper/CmdHelper'), + utils = require('bpmn-js-properties-panel/lib/Utils'); + +var entryFactory = require('bpmn-js-properties-panel/lib/factory/EntryFactory'), + script = require('bpmn-js-properties-panel/lib/provider/camunda/parts/implementation/Script')( + 'scriptFormat', + 'value', + true + ); + +function isElementDisabled(element) { + return ( + (element.type === 'bpmn:ServiceTask' && + element.businessObject.workflowActivity) || + element.type === 'bpmn:Process' + ); +} + +function createElement(type, parent, factory, properties) { + return elementHelper.createElement(type, properties, parent, factory); +} + +function isScript(elem) { + return is(elem, 'camunda:Script'); +} + +function isList(elem) { + return is(elem, 'camunda:List'); +} + +function isMap(elem) { + return is(elem, 'camunda:Map'); +} + +function ensureInputOutputSupported(element, insideConnector) { + return inputOutputHelper.isInputOutputSupported(element, insideConnector); +} + +module.exports = function(element, bpmnFactory, options, translate) { + var typeInfo = { + 'camunda:Map': { + value: 'map', + label: translate('Map') + }, + 'camunda:List': { + value: 'list', + label: translate('List') + }, + 'camunda:Script': { + value: 'script', + label: translate('Script') + } + }; + + options = options || {}; + + var insideConnector = !!options.insideConnector, + idPrefix = options.idPrefix || ''; + + var getSelected = options.getSelectedParameter; + + if (!ensureInputOutputSupported(element, insideConnector)) { + return []; + } + + var entries = []; + + var isSelected = function(element, node) { + return getSelected(element, node); + }; + + // parameter name //////////////////////////////////////////////////////// + + entries.push( + entryFactory.validationAwareTextField({ + id: idPrefix + 'parameterName', + label: 'Name', + modelProperty: 'name', + + getProperty: function(element, node) { + return (getSelected(element, node) || {}).name; + }, + + setProperty: function(element, values, node) { + var param = getSelected(element, node); + return cmdHelper.updateBusinessObject(element, param, values); + }, + + validate: function(element, values, node) { + var bo = getSelected(element, node); + + var validation = {}; + if (bo) { + var nameValue = values.name; + + if (nameValue) { + if (utils.containsSpace(nameValue)) { + validation.name = 'Name must not contain spaces'; + } + } else { + validation.name = 'Parameter must have a name'; + } + } + + return validation; + }, + + hidden: function(element, node) { + return !isSelected(element, node); + }, + disabled: function(element) { + return isElementDisabled(element); + } + }) + ); + + // parameter type ////////////////////////////////////////////////////// + + var selectOptions = [ + { value: 'text', name: 'Text' }, + { value: 'script', name: 'Script' }, + { value: 'list', name: 'List' }, + { value: 'map', name: 'Map' } + ]; + + entries.push( + entryFactory.selectBox({ + id: idPrefix + 'parameterType', + label: 'Type', + selectOptions: selectOptions, + modelProperty: 'parameterType', + + get: function(element, node) { + var bo = getSelected(element, node); + + var parameterType = 'text'; + + if (typeof bo !== 'undefined') { + var definition = bo.get('definition'); + if (typeof definition !== 'undefined') { + var type = definition.$type; + parameterType = typeInfo[type].value; + } + } + + return { + parameterType: parameterType + }; + }, + + set: function(element, values, node) { + var bo = getSelected(element, node); + + var properties = { + value: undefined, + definition: undefined + }; + + var createParameterTypeElem = function(type) { + return createElement(type, bo, bpmnFactory); + }; + + var parameterType = values.parameterType; + + if (parameterType === 'script') { + properties.definition = createParameterTypeElem( + 'camunda:Script' + ); + } else if (parameterType === 'list') { + properties.definition = createParameterTypeElem( + 'camunda:List' + ); + } else if (parameterType === 'map') { + properties.definition = createParameterTypeElem( + 'camunda:Map' + ); + } + + return cmdHelper.updateBusinessObject(element, bo, properties); + }, + + show: function(element, node) { + return isSelected(element, node); + }, + disabled: function(element) { + return isElementDisabled(element); + } + }) + ); + + // parameter value (type = text) /////////////////////////////////////////////////////// + + entries.push( + entryFactory.textBox({ + id: idPrefix + 'parameterType-text', + label: 'Value', + modelProperty: 'value', + get: function(element, node) { + return { + value: (getSelected(element, node) || {}).value + }; + }, + + set: function(element, values, node) { + var param = getSelected(element, node); + values.value = values.value || undefined; + return cmdHelper.updateBusinessObject(element, param, values); + }, + + show: function(element, node) { + var bo = getSelected(element, node); + return bo && !bo.definition; + } + }) + ); + + // parameter value (type = script) /////////////////////////////////////////////////////// + + entries.push({ + id: idPrefix + 'parameterType-script', + html: '<div data-show="isScript">' + script.template + '</div>', + get: function(element, node) { + var bo = getSelected(element, node); + return bo && isScript(bo.definition) + ? script.get(element, bo.definition) + : {}; + }, + + set: function(element, values, node) { + var bo = getSelected(element, node); + var update = script.set(element, values); + return cmdHelper.updateBusinessObject( + element, + bo.definition, + update + ); + }, + + validate: function(element, values, node) { + var bo = getSelected(element, node); + return bo && isScript(bo.definition) + ? script.validate(element, bo.definition) + : {}; + }, + + isScript: function(element, node) { + var bo = getSelected(element, node); + return bo && isScript(bo.definition); + }, + + script: script + }); + + // parameter value (type = list) /////////////////////////////////////////////////////// + + entries.push( + entryFactory.table({ + id: idPrefix + 'parameterType-list', + modelProperties: ['value'], + labels: ['Value'], + + getElements: function(element, node) { + var bo = getSelected(element, node); + + if (bo && isList(bo.definition)) { + return bo.definition.items; + } + + return []; + }, + + updateElement: function(element, values, node, idx) { + var bo = getSelected(element, node); + var item = bo.definition.items[idx]; + return cmdHelper.updateBusinessObject(element, item, values); + }, + + addElement: function(element, node) { + var bo = getSelected(element, node); + var newValue = createElement( + 'camunda:Value', + bo.definition, + bpmnFactory, + { value: undefined } + ); + return cmdHelper.addElementsTolist( + element, + bo.definition, + 'items', + [newValue] + ); + }, + + removeElement: function(element, node, idx) { + var bo = getSelected(element, node); + return cmdHelper.removeElementsFromList( + element, + bo.definition, + 'items', + null, + [bo.definition.items[idx]] + ); + }, + + editable: function(element, node, prop, idx) { + var bo = getSelected(element, node); + var item = bo.definition.items[idx]; + return !isMap(item) && !isList(item) && !isScript(item); + }, + + setControlValue: function(element, node, input, prop, value, idx) { + var bo = getSelected(element, node); + var item = bo.definition.items[idx]; + + if (!isMap(item) && !isList(item) && !isScript(item)) { + input.value = value; + } else { + input.value = typeInfo[item.$type].label; + } + }, + + show: function(element, node) { + var bo = getSelected(element, node); + return bo && bo.definition && isList(bo.definition); + } + }) + ); + + // parameter value (type = map) /////////////////////////////////////////////////////// + + entries.push( + entryFactory.table({ + id: idPrefix + 'parameterType-map', + modelProperties: ['key', 'value'], + labels: ['Key', 'Value'], + addLabel: 'Add Entry', + + getElements: function(element, node) { + var bo = getSelected(element, node); + + if (bo && isMap(bo.definition)) { + return bo.definition.entries; + } + + return []; + }, + + updateElement: function(element, values, node, idx) { + var bo = getSelected(element, node); + var entry = bo.definition.entries[idx]; + + if ( + isMap(entry.definition) || + isList(entry.definition) || + isScript(entry.definition) + ) { + values = { + key: values.key + }; + } + + return cmdHelper.updateBusinessObject(element, entry, values); + }, + + addElement: function(element, node) { + var bo = getSelected(element, node); + var newEntry = createElement( + 'camunda:Entry', + bo.definition, + bpmnFactory, + { key: undefined, value: undefined } + ); + return cmdHelper.addElementsTolist( + element, + bo.definition, + 'entries', + [newEntry] + ); + }, + + removeElement: function(element, node, idx) { + var bo = getSelected(element, node); + return cmdHelper.removeElementsFromList( + element, + bo.definition, + 'entries', + null, + [bo.definition.entries[idx]] + ); + }, + + editable: function(element, node, prop, idx) { + var bo = getSelected(element, node); + var entry = bo.definition.entries[idx]; + return ( + prop === 'key' || + (!isMap(entry.definition) && + !isList(entry.definition) && + !isScript(entry.definition)) + ); + }, + + setControlValue: function(element, node, input, prop, value, idx) { + var bo = getSelected(element, node); + var entry = bo.definition.entries[idx]; + + if ( + prop === 'key' || + (!isMap(entry.definition) && + !isList(entry.definition) && + !isScript(entry.definition)) + ) { + input.value = value; + } else { + input.value = typeInfo[entry.definition.$type].label; + } + }, + + show: function(element, node) { + var bo = getSelected(element, node); + return bo && bo.definition && isMap(bo.definition); + } + }) + ); + + return entries; +}; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowActivity.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowActivity.js new file mode 100644 index 00000000..90fe84fc --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowActivity.js @@ -0,0 +1,58 @@ +import entryFactory from 'bpmn-js-properties-panel/lib/factory/EntryFactory'; +import cmdHelper from 'bpmn-js-properties-panel/lib/helper/CmdHelper'; +import { + implementationType, + IMPLEMENTATION_TYPE_VALUE +} from './implementationConstants'; + +const workflowActivity = (element, config, bpmnFactory, options, translate) => { + const { getImplementationType, getBusinessObject } = options; + + const isWorkflowActivity = element => + getImplementationType(element) === 'workflowActivity'; + + const workflowActivityEntry = entryFactory.selectBox({ + id: 'activitySelect', + label: translate('Activity Spec'), + selectOptions: config.activities, + emptyParameter: true, + modelProperty: 'workflowActivity', + + get: function(element) { + var bo = getBusinessObject(element); + return { + workflowActivity: bo.get(implementationType.ACTIVITY_RESOURCE) + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + config.onChange(bo, values.workflowActivity); + const commands = []; + const dataForUpdate = {}; + dataForUpdate[implementationType.ACTIVITY_RESOURCE] = + values.workflowActivity; + dataForUpdate[ + implementationType.ACTIVITY + ] = IMPLEMENTATION_TYPE_VALUE; + commands.push( + cmdHelper.updateBusinessObject(element, bo, dataForUpdate) + ); + return commands; + }, + + validate: function(element, values) { + return isWorkflowActivity(element) && !values.workflowActivity + ? { workflowActivity: 'Must provide a value' } + : {}; + }, + + hidden: function(element) { + return !isWorkflowActivity(element); + } + }); + + return [workflowActivityEntry]; +}; + +export default workflowActivity; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowImplementationType.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowImplementationType.js new file mode 100644 index 00000000..11e8fcba --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowImplementationType.js @@ -0,0 +1,227 @@ +var entryFactory = require('bpmn-js-properties-panel/lib/factory/EntryFactory'), + cmdHelper = require('bpmn-js-properties-panel/lib/helper/CmdHelper'), + extensionElementsHelper = require('bpmn-js-properties-panel/lib/helper/ExtensionElementsHelper'), + elementHelper = require('bpmn-js-properties-panel/lib/helper/ElementHelper'); + +var assign = require('lodash.assign'); +var map = require('lodash.map'); +import { implementationType } from './implementationConstants'; + +var DEFAULT_DELEGATE_PROPS = ['class', 'expression', 'delegateExpression']; + +var DELEGATE_PROPS = { + 'camunda:class': undefined, + 'camunda:expression': undefined, + 'camunda:delegateExpression': undefined, + 'camunda:resultVariable': undefined +}; + +var DMN_CAPABLE_PROPS = { + 'camunda:decisionRef': undefined, + 'camunda:decisionRefBinding': 'latest', + 'camunda:decisionRefVersion': undefined, + 'camunda:mapDecisionResult': 'resultList', + 'camunda:decisionRefTenantId': undefined +}; + +var EXTERNAL_CAPABLE_PROPS = { + 'camunda:type': undefined, + 'camunda:topic': undefined +}; + +const ACTIVITY_PROPS = {}; + +ACTIVITY_PROPS[implementationType] = undefined; + +module.exports = function(element, bpmnFactory, options, translate) { + var DEFAULT_OPTIONS = [ + { value: 'class', name: translate('Java Class') }, + { value: 'expression', name: translate('Expression') }, + { value: 'delegateExpression', name: translate('Delegate Expression') } + ]; + + var DMN_OPTION = [{ value: 'dmn', name: translate('DMN') }]; + + var EXTERNAL_OPTION = [{ value: 'external', name: translate('External') }]; + + var CONNECTOR_OPTION = [ + { value: 'connector', name: translate('Connector') } + ]; + + var SCRIPT_OPTION = [{ value: 'script', name: translate('Script') }]; + + var ACTIVITY_OPTION = [ + { value: 'workflowActivity', name: translate('Activity') } + ]; + + var getType = options.getImplementationType, + getBusinessObject = options.getBusinessObject; + + var hasDmnSupport = options.hasDmnSupport, + hasExternalSupport = options.hasExternalSupport, + hasServiceTaskLikeSupport = options.hasServiceTaskLikeSupport, + hasScriptSupport = options.hasScriptSupport; + + var entries = []; + + var selectOptions = DEFAULT_OPTIONS.concat([]); + + if (hasDmnSupport) { + selectOptions = selectOptions.concat(DMN_OPTION); + } + + if (hasExternalSupport) { + selectOptions = selectOptions.concat(EXTERNAL_OPTION); + } + + if (hasServiceTaskLikeSupport) { + selectOptions = selectOptions.concat(CONNECTOR_OPTION); + } + + if (hasScriptSupport) { + selectOptions = selectOptions.concat(SCRIPT_OPTION); + } + + selectOptions = selectOptions.concat(ACTIVITY_OPTION); + + selectOptions.push({ value: '' }); + + entries.push( + entryFactory.selectBox({ + id: 'implementation', + label: translate('Implementation'), + selectOptions: selectOptions, + modelProperty: 'implType', + + get: function(element) { + return { + implType: getType(element) || '' + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + var oldType = getType(element); + var newType = values.implType; + + var props = assign({}, DELEGATE_PROPS); + + if (DEFAULT_DELEGATE_PROPS.indexOf(newType) !== -1) { + var newValue = ''; + if (DEFAULT_DELEGATE_PROPS.indexOf(oldType) !== -1) { + newValue = bo.get('camunda:' + oldType); + } + + props['camunda:' + newType] = newValue; + } + + if (hasDmnSupport) { + props = assign(props, DMN_CAPABLE_PROPS); + if (newType === 'dmn') { + props['camunda:decisionRef'] = ''; + } + } + + if (hasExternalSupport) { + props = assign(props, EXTERNAL_CAPABLE_PROPS); + if (newType === 'external') { + props['camunda:type'] = 'external'; + props['camunda:topic'] = ''; + } + } + + if (hasScriptSupport) { + props['camunda:script'] = undefined; + + if (newType === 'script') { + props['camunda:script'] = elementHelper.createElement( + 'camunda:Script', + {}, + bo, + bpmnFactory + ); + } + } + + props = assign(props, ACTIVITY_PROPS); + props[implementationType.ACTIVITY] = undefined; + var commands = []; + if (newType === 'workflowActivity') { + props[implementationType.ACTIVITY] = ''; + props[implementationType.ACTIVITY_RESOURCE] = ''; + } else { + var inputsOutputs = extensionElementsHelper.getExtensionElements( + bo, + 'camunda:InputOutput' + ); + commands.push( + map(inputsOutputs, function(inputOutput) { + return extensionElementsHelper.removeEntry( + bo, + element, + inputOutput + ); + }) + ); + } + + commands.push( + cmdHelper.updateBusinessObject(element, bo, props) + ); + + if (hasServiceTaskLikeSupport) { + var connectors = extensionElementsHelper.getExtensionElements( + bo, + 'camunda:Connector' + ); + commands.push( + map(connectors, function(connector) { + return extensionElementsHelper.removeEntry( + bo, + element, + connector + ); + }) + ); + + if (newType === 'connector') { + var extensionElements = bo.get('extensionElements'); + if (!extensionElements) { + extensionElements = elementHelper.createElement( + 'bpmn:ExtensionElements', + { values: [] }, + bo, + bpmnFactory + ); + commands.push( + cmdHelper.updateBusinessObject(element, bo, { + extensionElements: extensionElements + }) + ); + } + var connector = elementHelper.createElement( + 'camunda:Connector', + {}, + extensionElements, + bpmnFactory + ); + commands.push( + cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + 'extensionElements', + [connector], + [] + ) + ); + } + } + + return commands; + } + }) + ); + + return entries; +}; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/implementationConstants.js b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/implementationConstants.js new file mode 100644 index 00000000..054017f3 --- /dev/null +++ b/workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/implementationConstants.js @@ -0,0 +1,6 @@ +export const implementationType = { + ACTIVITY: 'implementation', + ACTIVITY_RESOURCE: 'resourses' +}; + +export const IMPLEMENTATION_TYPE_VALUE = 'activity'; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputConstants.js b/workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputConstants.js index 6f299926..30f80a6b 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputConstants.js +++ b/workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputConstants.js @@ -19,11 +19,11 @@ export const NAME_MAX_LEN = 50; export const INPUTS = 'inputs'; export const OUTPUTS = 'outputs'; -export const STRING = 'String'; +export const STRING = 'string'; export const DEFAULT_STRING = 'STRING'; -export const BOOLEAN = 'Boolean'; -export const INTEGER = 'Integer'; -export const FLOAT = 'Float'; +export const BOOLEAN = 'boolean'; +export const INTEGER = 'integer'; +export const FLOAT = 'float'; export const NAMESPACE = 'inputOutput'; diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputSelectors.js b/workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputSelectors.js index db07bce7..3a6c9e8f 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputSelectors.js +++ b/workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputSelectors.js @@ -15,13 +15,23 @@ */ import { createSelector } from 'reselect'; -import { isEmpty } from 'lodash'; +import isEmpty from 'lodash.isempty'; import { INPUTS } from 'features/version/inputOutput/inputOutputConstants'; export const getInputOutput = state => state.currentVersion.inputOutput; export const getInputs = createSelector(getInputOutput, data => data.inputs); export const getOutputs = createSelector(getInputOutput, data => data.outputs); +export const getInputOutputForComposition = state => ({ + inputs: getInputs(state).map(item => ({ + ...item, + type: item.type.toLowerCase() + })), + outputs: getOutputs(state).map(item => ({ + ...item, + type: item.type.toLowerCase() + })) +}); export const getCurrent = createSelector( getInputOutput, inputOutput => inputOutput.current diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/VersionSelect.js b/workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/VersionSelect.js index 2c67946b..d8a6d02e 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/VersionSelect.js +++ b/workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/VersionSelect.js @@ -16,7 +16,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { isEmpty } from 'lodash'; +import isEmpty from 'lodash.isempty'; const VersionSelect = props => { const { diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/versionSaga.js b/workflow-designer-ui/src/main/frontend/src/features/version/versionSaga.js index d8d7fd82..7ae5e1eb 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/versionSaga.js +++ b/workflow-designer-ui/src/main/frontend/src/features/version/versionSaga.js @@ -33,11 +33,11 @@ import { versionState } from 'features/version/versionConstants'; import overviewApi from '../workflow/overview/overviewApi'; import { versionListFetchAction } from '../workflow/overview/overviewConstansts'; import { updateComposition } from 'features/version/composition/compositionActions'; -import activitiesApi from 'features/activities/activitiesApi'; -import { setActivitiesList } from 'features/activities/activitiesActions'; +import { getActivitiesList } from 'features/activities/activitiesActions'; function* fetchVersion(action) { try { + yield put(getActivitiesList()); const data = yield call(versionApi.fetchVersion, action.payload); const { inputs, outputs, ...rest } = data; let composition = false; @@ -48,12 +48,11 @@ function* fetchVersion(action) { action.payload ); } - const activitiesList = yield call(activitiesApi.fetchActivities); + yield all([ put(setWorkflowVersionAction(rest)), put(setInputsOutputs({ inputs, outputs })), - put(updateComposition(composition)), - put(setActivitiesList(activitiesList.results)) + put(updateComposition(composition)) ]); } catch (error) { yield put(genericNetworkErrorAction(error)); diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/OverviewView.jsx b/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/OverviewView.jsx index d0bbdef5..3166cade 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/OverviewView.jsx +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/OverviewView.jsx @@ -78,16 +78,18 @@ class OverviewView extends Component { versions, selectedVersion, workflow, - isVersionsCertifies + isVersionsCertifies, + history } = this.props; const nodeVersions = versions.map(version => ({ id: version.id, name: version.name, parent: version.baseId || '' })); + return ( <div className="overview-page"> - <WorkflowHeader name={workflow.name} /> + <WorkflowHeader history={history} name={workflow.name} /> <div className="overview-content"> <WorkflowDetails name={workflow.name} diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/__tests__/__snapshots__/OverviewView_snapshot-test.js.snap b/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/__tests__/__snapshots__/OverviewView_snapshot-test.js.snap index dea9c1c5..4f9df72e 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/__tests__/__snapshots__/OverviewView_snapshot-test.js.snap +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/__tests__/__snapshots__/OverviewView_snapshot-test.js.snap @@ -7,9 +7,27 @@ exports[`OverviewView Snapshot renders correctly 1`] = ` <div className="overview-header" > - wf1 - - - title + <div + className="title" + > + wf1 + - + title + </div> + <div + className="svg-icon-wrapper go-catalog-btn clickable right" + disabled={undefined} + onClick={[Function]} + > + <test-file-stub + className="svg-icon __back" + /> + <span + className="svg-icon-label " + > + backBtnLabel + </span> + </div> </div> <div className="overview-content" diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/WorkflowHeader.jsx b/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/WorkflowHeader.jsx index 06c67bc0..f5bfc3db 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/WorkflowHeader.jsx +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/WorkflowHeader.jsx @@ -16,17 +16,43 @@ import React from 'react'; import PropTypes from 'prop-types'; import { I18n } from 'react-redux-i18n'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon'; -const WorkflowHeader = ({ name }) => { +const BackBtn = ({ history }) => ( + <SVGIcon + onClick={() => history.push('/')} + label={I18n.t('workflow.overview.backBtnLabel')} + className="go-catalog-btn" + labelPosition="right" + name="back" + /> +); + +BackBtn.propTypes = { + history: PropTypes.object +}; + +const Title = ({ name }) => ( + <div className="title"> + {name} - {I18n.t('workflow.overview.title')} + </div> +); +Title.propTypes = { + name: PropTypes.string +}; + +const WorkflowHeader = ({ name, history }) => { return ( <div className="overview-header"> - {name} - {I18n.t('workflow.overview.title')} + <Title name={name} /> + <BackBtn history={history} /> </div> ); }; WorkflowHeader.propTypes = { - name: PropTypes.string + name: PropTypes.string, + history: PropTypes.object }; export default WorkflowHeader; diff --git a/workflow-designer-ui/src/main/frontend/src/i18n/I18n.js b/workflow-designer-ui/src/main/frontend/src/i18n/I18n.js index f07ae173..fdf28ffd 100644 --- a/workflow-designer-ui/src/main/frontend/src/i18n/I18n.js +++ b/workflow-designer-ui/src/main/frontend/src/i18n/I18n.js @@ -15,8 +15,8 @@ */ import languagesData from 'wfapp/i18n/languages.json'; -import merge from 'lodash/object/merge.js'; -import setPath from 'lodash/object/set.js'; +import merge from 'lodash.merge'; +import setPath from 'lodash.set'; let languagesObj = {}; let language = null; diff --git a/workflow-designer-ui/src/main/frontend/src/i18n/languages.json b/workflow-designer-ui/src/main/frontend/src/i18n/languages.json index 96e64ae6..ea994526 100644 --- a/workflow-designer-ui/src/main/frontend/src/i18n/languages.json +++ b/workflow-designer-ui/src/main/frontend/src/i18n/languages.json @@ -19,7 +19,8 @@ "cancelBtn": "Cancel", "certifyBtn": "Certify", "undoBtn": "Undo", - "closeBtn": "Close" + "closeBtn": "Close", + "okBtn": "Ok" }, "form": { "name": "Name", @@ -44,7 +45,8 @@ "versionList": "Versions", "newVersion": "Create New Version", "title": "Overview", - "lastEdited": "Last Edited On" + "lastEdited": "Last Edited On", + "backBtnLabel": "WORKFLOW CATALOG" }, "inputOutput": { "name": "Name", @@ -65,7 +67,10 @@ "emptyName": "Field is required" }, "composition": { - "bpmnError" : "BPMN.IO Error" + "bpmnError" : "BPMN.IO Error", + "exportErrorMsg": "Could not export diagram", + "saveErrorMsg": "Could not save diagram", + "importErrorMsg": "Could not import diagram" } }, "version": { diff --git a/workflow-designer-ui/src/main/frontend/src/rootSaga.js b/workflow-designer-ui/src/main/frontend/src/rootSaga.js index c280010f..0ea0782a 100644 --- a/workflow-designer-ui/src/main/frontend/src/rootSaga.js +++ b/workflow-designer-ui/src/main/frontend/src/rootSaga.js @@ -21,6 +21,8 @@ import catalogSaga from 'features/catalog/catalogSagas'; import { watchWorkflow } from 'features/workflow/create/createWorkflowSaga'; import { watchNotifications } from 'shared/notifications/notificationsSagas'; import versionSaga from 'features/version/versionSaga'; +import activitiesSaga from 'features/activities/activitiesSaga'; + import { watchOverview } from 'features/workflow/overview/overviewSagas'; export default function* rootSaga() { @@ -30,6 +32,7 @@ export default function* rootSaga() { fork(watchWorkflow), fork(watchNotifications), fork(versionSaga), - fork(watchOverview) + fork(watchOverview), + fork(activitiesSaga) ]); } diff --git a/workflow-designer-ui/src/main/frontend/src/shared/components/Select/index.js b/workflow-designer-ui/src/main/frontend/src/shared/components/Select/index.js index dcf11f2f..df30fad9 100644 --- a/workflow-designer-ui/src/main/frontend/src/shared/components/Select/index.js +++ b/workflow-designer-ui/src/main/frontend/src/shared/components/Select/index.js @@ -15,7 +15,7 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import { isEmpty } from 'lodash'; +import isEmpty from 'lodash.isempty'; const Select = props => { const { dataObj, selectedItemValue, disabled, label } = props; diff --git a/workflow-designer-ui/src/main/frontend/tools/proxy-server.js b/workflow-designer-ui/src/main/frontend/tools/proxy-server.js index 397b0ba6..bdec886c 100644 --- a/workflow-designer-ui/src/main/frontend/tools/proxy-server.js +++ b/workflow-designer-ui/src/main/frontend/tools/proxy-server.js @@ -13,29 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict' +'use strict'; -const proxy = require('http-proxy-middleware') -const devConfig = require('./getDevConfig') +const proxy = require('http-proxy-middleware'); +const devConfig = require('./getDevConfig'); module.exports = function(server) { let proxyConfigDefaults = { changeOrigin: true, secure: false, onProxyReq: (proxyReq, req, res) => { - proxyReq.setHeader('USER_ID', devConfig.proxyConfig.cookies.USER_ID) - }, - } + proxyReq.setHeader( + 'USER_ID', + devConfig.proxyConfig.cookies.USER_ID + ); + } + }; - let middlewares = [] + let middlewares = []; middlewares.push( proxy( - ['/wf'], + ['/wf', '/v1.0/activity-spec'], Object.assign({}, proxyConfigDefaults, { - target: devConfig.proxyTarget, - }), - ), - ) - server.use(middlewares) -} + target: devConfig.proxyTarget + }) + ) + ); + server.use(middlewares); +}; diff --git a/workflow-designer-ui/src/main/frontend/yarn.lock b/workflow-designer-ui/src/main/frontend/yarn.lock index 86a6301c..f1566580 100644 --- a/workflow-designer-ui/src/main/frontend/yarn.lock +++ b/workflow-designer-ui/src/main/frontend/yarn.lock @@ -2065,25 +2065,25 @@ bpmn-font@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/bpmn-font/-/bpmn-font-0.8.0.tgz#85b18715faede345cd33c8a48f50bbe557ff76c2" -bpmn-js-properties-panel@^0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/bpmn-js-properties-panel/-/bpmn-js-properties-panel-0.20.0.tgz#0d1c3d46bde968d97f02e662a73e781efbda1263" +bpmn-js-properties-panel@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/bpmn-js-properties-panel/-/bpmn-js-properties-panel-0.26.1.tgz#893d9fe7027958a719a5d3973ec2d2e2c68a65eb" dependencies: - ids "^0.2.0" + ids "^0.2.2" inherits "^2.0.1" - lodash "^3.0.1" - min-dom "^0.2.0" - scroll-tabs "^0.2.1" + lodash "^4.17.10" + min-dom "^3.1.0" + scroll-tabs "^1.0.0" selection-update "^0.1.2" -bpmn-js@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/bpmn-js/-/bpmn-js-2.3.1.tgz#1374c466f7c19ae4652dca52979200c293241863" +bpmn-js@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/bpmn-js/-/bpmn-js-2.4.1.tgz#7e1530f54e0848959ec84789ca11eaac672eab6f" dependencies: bpmn-font "^0.8.0" bpmn-moddle "^5.1.5" css.escape "^1.5.1" - diagram-js "^2.4.0" + diagram-js "^2.5.1" diagram-js-direct-editing "^1.3.0" ids "^0.2.0" inherits "^2.0.1" @@ -2390,12 +2390,6 @@ camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" -camunda-bpmn-moddle@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camunda-bpmn-moddle/-/camunda-bpmn-moddle-3.0.0.tgz#8ffcc44856643a6a4f85bec9cc6653bd97f342dd" - dependencies: - min-dash "^3.0.0" - caniuse-api@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" @@ -2852,31 +2846,6 @@ compare-versions@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.2.0.tgz#f36f23aacc539da0e3e0f71af46ce5b953a6ae76" -component-classes@^1.2.3: - version "1.2.6" - resolved "https://registry.yarnpkg.com/component-classes/-/component-classes-1.2.6.tgz#c642394c3618a4d8b0b8919efccbbd930e5cd691" - dependencies: - component-indexof "0.0.3" - -component-closest@*: - version "1.0.1" - resolved "https://registry.yarnpkg.com/component-closest/-/component-closest-1.0.1.tgz#1ed0464132fc88a3510a2dabec079695789fb1b5" - dependencies: - component-matches-selector "~0.1.6" - -component-closest@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/component-closest/-/component-closest-0.1.4.tgz#5b72fc52d90607e75115cafdc3b07e27348de71b" - dependencies: - component-matches-selector "~0.1.5" - -component-delegate@^0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/component-delegate/-/component-delegate-0.2.4.tgz#dc5028759ea681bea84a3d6bbd650207c3beb138" - dependencies: - component-closest "*" - component-event "*" - component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" @@ -2889,20 +2858,6 @@ component-event@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/component-event/-/component-event-0.1.4.tgz#3de78fc28782381787e24bf2a7c536bf0142c9b4" -component-indexof@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24" - -component-matches-selector@^0.1.5, component-matches-selector@~0.1.5, component-matches-selector@~0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/component-matches-selector/-/component-matches-selector-0.1.6.tgz#7b630e04e7e0c3b0019f31749fd70af5ed8b972e" - dependencies: - component-query "*" - -component-query@*, component-query@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/component-query/-/component-query-0.0.3.tgz#07f49dab7071fa9606725df53e607f468acdaacf" - compressible@~2.0.13: version "2.0.13" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9" @@ -3544,9 +3499,9 @@ diagram-js-direct-editing@^1.3.0: min-dash "^3.0.0" min-dom "^3.0.0" -diagram-js@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/diagram-js/-/diagram-js-2.4.0.tgz#f067fd956641297e3d540885fc5065046b3064c9" +diagram-js@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/diagram-js/-/diagram-js-2.5.1.tgz#51c828f132da18a04f233a686495244ce0c2f42b" dependencies: css.escape "^1.5.1" didi "^4.0.0" @@ -4187,7 +4142,7 @@ eventemitter3@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" -events@^1.0.0, events@^1.1.0: +events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -5551,7 +5506,7 @@ identity-obj-proxy@^3.0.0: dependencies: harmony-reflect "^1.4.6" -ids@^0.2.0: +ids@^0.2.0, ids@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/ids/-/ids-0.2.2.tgz#c23140dd06f5e5e95b1a5e5e98877ea734965540" dependencies: @@ -7050,6 +7005,10 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" +lodash.isempty@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" + lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" @@ -7062,10 +7021,18 @@ lodash.keys@^3.1.2: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash.map@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" +lodash.merge@^4.6.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" + lodash.mergewith@^4.6.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" @@ -7074,6 +7041,10 @@ lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" +lodash.set@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" + lodash.some@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" @@ -7108,7 +7079,7 @@ lodash.words@^3.0.0: dependencies: lodash._root "^3.0.0" -lodash@^3.0.1, lodash@^3.10.1: +lodash@^3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -7465,7 +7436,7 @@ mimic-response@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" -min-dash@^3.0.0: +min-dash@^3.0.0, min-dash@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/min-dash/-/min-dash-3.1.0.tgz#ba1d0f06dd233f163ac8041f115e3bb08ba7fda9" @@ -7475,21 +7446,9 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" -min-dom@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/min-dom/-/min-dom-0.2.0.tgz#7f1a3f8ac85c05adee7b3f40e00c52803075cd5d" - dependencies: - component-classes "^1.2.3" - component-closest "^0.1.4" - component-delegate "^0.2.3" - component-event "^0.1.4" - component-matches-selector "^0.1.5" - component-query "^0.0.3" - domify "^1.3.1" - -min-dom@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/min-dom/-/min-dom-3.1.0.tgz#9f8075423e6f8799d642d9bdd65622dd3589f6d5" +min-dom@^3.0.0, min-dom@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/min-dom/-/min-dom-3.1.1.tgz#53440d23d32a0a8bb6b2e657ca4cfd39d998a29a" dependencies: closest "0.0.1" component-event "^0.1.4" @@ -7592,6 +7551,10 @@ mississippi@^3.0.0: stream-each "^1.1.0" through2 "^2.0.0" +mitt@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.1.3.tgz#528c506238a05dce11cd914a741ea2cc332da9b8" + mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" @@ -10371,14 +10334,13 @@ scoped-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8" -scroll-tabs@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/scroll-tabs/-/scroll-tabs-0.2.1.tgz#770d462b40f633b9cae6eee3521f785c49da8f6f" +scroll-tabs@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/scroll-tabs/-/scroll-tabs-1.0.1.tgz#bac04e4a1725e8a03344bae644dd6d7cdc192452" dependencies: - events "^1.1.0" - inherits "^2.0.1" - lodash "^3.10.1" - min-dom "^0.2.0" + min-dash "^3.1.0" + min-dom "^3.1.0" + mitt "^1.1.3" scss-tokenizer@^0.2.3: version "0.2.3" @@ -11304,12 +11266,12 @@ tiny-relative-date@^1.3.0: resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" tiny-stack@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/tiny-stack/-/tiny-stack-1.0.0.tgz#e058ed1daff2e733da2dcc8879d6b01d26e2c1f6" + version "1.1.0" + resolved "https://registry.yarnpkg.com/tiny-stack/-/tiny-stack-1.1.0.tgz#a5d65c5753709ea43b29e903e6f6323185b9ac21" tiny-svg@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tiny-svg/-/tiny-svg-2.1.0.tgz#2323a150874c6702c6927a62ab17198402aeb886" + version "2.1.2" + resolved "https://registry.yarnpkg.com/tiny-svg/-/tiny-svg-2.1.2.tgz#607c73004d3c807ba7d69ba9616d433190d2baf7" tmp@^0.0.33: version "0.0.33" |