wf composition 71/61271/8
authorStanislav Vishnevetskiy <shlomo-stanisla.vishnevetskiy@amdocs.com>
Mon, 27 Aug 2018 07:07:45 +0000 (10:07 +0300)
committerStanislav Vishnevetskiy <shlomo-stanisla.vishnevetskiy@amdocs.com>
Mon, 27 Aug 2018 07:08:09 +0000 (10:08 +0300)
Issue-ID: SDC-1591
Change-Id: I3d1c1e08094a2088b8e474b0c6f3616088ded4ee
Signed-off-by: Stanislav Vishnevetskiy <shlomo-stanisla.vishnevetskiy@amdocs.com>
41 files changed:
workflow-designer-ui/src/main/frontend/package.json
workflow-designer-ui/src/main/frontend/resources/scss/common/_customVariables.scss
workflow-designer-ui/src/main/frontend/resources/scss/features/_composition.scss
workflow-designer-ui/src/main/frontend/resources/scss/features/_overview.scss
workflow-designer-ui/src/main/frontend/src/config/Configuration.js
workflow-designer-ui/src/main/frontend/src/config/config.json
workflow-designer-ui/src/main/frontend/src/features/activities/activitiesActions.js
workflow-designer-ui/src/main/frontend/src/features/activities/activitiesApi.js
workflow-designer-ui/src/main/frontend/src/features/activities/activitiesConstants.js
workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSaga.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSelectors.js
workflow-designer-ui/src/main/frontend/src/features/version/composition/Composition.js
workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js
workflow-designer-ui/src/main/frontend/src/features/version/composition/bpmnUtils.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionConstants.js
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/descriptors/camunda.json [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/WorkflowPropertiesProvider.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/index.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputParameterProps.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputProps.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/WorkflowServiceTaskDelegateProps.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/createInputOutputTabGroups.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutput.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputHelper.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputParameter.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowActivity.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowImplementationType.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/implementationConstants.js [new file with mode: 0644]
workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputConstants.js
workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputSelectors.js
workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/VersionSelect.js
workflow-designer-ui/src/main/frontend/src/features/version/versionSaga.js
workflow-designer-ui/src/main/frontend/src/features/workflow/overview/OverviewView.jsx
workflow-designer-ui/src/main/frontend/src/features/workflow/overview/__tests__/__snapshots__/OverviewView_snapshot-test.js.snap
workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/WorkflowHeader.jsx
workflow-designer-ui/src/main/frontend/src/i18n/I18n.js
workflow-designer-ui/src/main/frontend/src/i18n/languages.json
workflow-designer-ui/src/main/frontend/src/rootSaga.js
workflow-designer-ui/src/main/frontend/src/shared/components/Select/index.js
workflow-designer-ui/src/main/frontend/tools/proxy-server.js
workflow-designer-ui/src/main/frontend/yarn.lock

index e3c657e..5271dc5 100644 (file)
@@ -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",
                "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",
index 1a532c8..5e5bef8 100644 (file)
@@ -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;
index 119bbf0..6554219 100644 (file)
@@ -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 {
                                
index 24f632d..e299fa3 100644 (file)
   }
 
   .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() {
index 3e558da..36ad33d 100644 (file)
@@ -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);
 
index f112144..eb7d181 100644 (file)
@@ -1,5 +1,6 @@
 {
        "version": "0.1",
        "appContextPath" : "/",
-       "defaultRestPrefix": "/wf"
+       "defaultRestPrefix": "/wf",
+       "activitiesRestPrefix": "/v1.0"
 }
index ab0a3c4..833f6e5 100644 (file)
@@ -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
+});
index 8e1afc1..10141e0 100644 (file)
 * 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`);
     }
 };
index 54aed6a..f99789c 100644 (file)
 * 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 (file)
index 0000000..2350b9c
--- /dev/null
@@ -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;
index 47a0975..fc0c55a 100644 (file)
@@ -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
+    }));
index d322207..ef48acd 100644 (file)
@@ -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')
                 })
             )
     };
index f47a6ec..012ee76 100644 (file)
@@ -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 (file)
index 0000000..adc4286
--- /dev/null
@@ -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)
+    );
+}
index 74cab0c..499e8ef 100644 (file)
 * 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 (file)
index 0000000..80e876a
--- /dev/null
@@ -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 (file)
index 0000000..98a5797
--- /dev/null
@@ -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 (file)
index 0000000..bc60c58
--- /dev/null
@@ -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 (file)
index 0000000..a1f1efb
--- /dev/null
@@ -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 (file)
index 0000000..df1e543
--- /dev/null
@@ -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 (file)
index 0000000..dbd12cb
--- /dev/null
@@ -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 (file)
index 0000000..f14e359
--- /dev/null
@@ -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 (file)
index 0000000..555b4af
--- /dev/null
@@ -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 (file)
index 0000000..e294351
--- /dev/null
@@ -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 (file)
index 0000000..da949dd
--- /dev/null
@@ -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 (file)
index 0000000..90fe84f
--- /dev/null
@@ -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 (file)
index 0000000..11e8fcb
--- /dev/null
@@ -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 (file)
index 0000000..054017f
--- /dev/null
@@ -0,0 +1,6 @@
+export const implementationType = {
+    ACTIVITY: 'implementation',
+    ACTIVITY_RESOURCE: 'resourses'
+};
+
+export const IMPLEMENTATION_TYPE_VALUE = 'activity';
index 6f29992..30f80a6 100644 (file)
@@ -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';
 
index db07bce..3a6c9e8 100644 (file)
 */
 
 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
index d8d7fd8..7ae5e1e 100644 (file)
@@ -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));
index d0bbdef..3166cad 100644 (file)
@@ -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}
index dea9c1c..4f9df72 100644 (file)
@@ -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"
index 06c67bc..f5bfc3d 100644 (file)
 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;
index f07ae17..fdf28ff 100644 (file)
@@ -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;
index 96e64ae..ea99452 100644 (file)
@@ -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",
                 "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": {
index c280010..0ea0782 100644 (file)
@@ -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)
     ]);
 }
index dcf11f2..df30fad 100644 (file)
@@ -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;
index 397b0ba..bdec886 100644 (file)
 * 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);
+};
index 86a6301..f156658 100644 (file)
@@ -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"