From 6dc58fd625279f8ffe1060170418686034db0af4 Mon Sep 17 00:00:00 2001 From: vasraz Date: Wed, 2 Oct 2019 12:08:49 +0100 Subject: Fix name convention issue Rename modules: workflow-designer-init to sdc-workflow-designer-init workflow-designer-be to sdc-workflow-designer-be workflow-designer-ui to sdc-workflow-designer-ui Rename docker images: onap/workflow-init to onap/sdc-workflow-init onap/workflow-backend to onap/sdc-workflow-backend onap/workflow-frontend to onap/sdc-workflow-frontend List of changed files: modified: README.md modified: docker-compose/debug.yml modified: docker-compose/docker-compose.yml modified: pom.xml modified: sdc-workflow-bdd/pom.xml modified: sdc-workflow-designer-be/pom.xml modified: sdc-workflow-designer-init/pom.xml modified: sdc-workflow-designer-ui/pom.xml modified: sdc-workflow-designer-ui/src/main/frontend/yarn.lock modified: version.properties All others changes are relaited to rename/move. Change-Id: Ic989b6347b815f85e77e23fc8d7884c05b650a27 Issue-ID: SDC-2334 Issue-ID: SDC-2335 Signed-off-by: Vasyl Razinkov --- .../src/main/frontend/.babelrc | 21 + .../src/main/frontend/.eslintignore | 3 + .../src/main/frontend/.eslintrc.json | 48 + .../src/main/frontend/.gitignore | 19 + .../src/main/frontend/.prettierignore | 1 + .../src/main/frontend/.prettierrc.json | 5 + .../src/main/frontend/__mocks__/fileMock.js | 19 + .../frontend/__mocks__/sdc-ui/lib/react/SVGIcon.js | 51 + .../src/main/frontend/external-resources/ping/ping | 11 + .../src/main/frontend/index.html | 10 + .../src/main/frontend/jest.config.js | 48 + .../src/main/frontend/jsconfig.json | 12 + .../src/main/frontend/package.json | 107 + .../resources/fonts/open-sans-v15-latin-600.woff | Bin 0 -> 18296 bytes .../resources/fonts/open-sans-v15-latin-600.woff2 | Bin 0 -> 14544 bytes .../fonts/open-sans-v15-latin-italic.woff | Bin 0 -> 17068 bytes .../fonts/open-sans-v15-latin-italic.woff2 | Bin 0 -> 13416 bytes .../fonts/open-sans-v15-latin-regular.woff | Bin 0 -> 17704 bytes .../fonts/open-sans-v15-latin-regular.woff2 | Bin 0 -> 14048 bytes .../src/main/frontend/resources/scss/_common.scss | 5 + .../main/frontend/resources/scss/_components.scss | 12 + .../main/frontend/resources/scss/_features.scss | 6 + .../resources/scss/common/_customVariables.scss | 51 + .../frontend/resources/scss/common/_fonts.scss | 26 + .../frontend/resources/scss/common/_utils.scss | 317 + .../resources/scss/components/_archiveLabel.scss | 10 + .../resources/scss/components/_customModal.scss | 24 + .../scss/components/_expandableInput.scss | 56 + .../resources/scss/components/_inputOptions.scss | 48 + .../resources/scss/components/_layout.scss | 34 + .../resources/scss/components/_loader.scss | 159 + .../scss/components/_navigationSideBar.scss | 60 + .../resources/scss/components/_notifications.scss | 8 + .../resources/scss/components/_scrollbars.scss | 63 + .../resources/scss/components/_searchInput.scss | 59 + .../frontend/resources/scss/components/_tree.scss | 56 + .../resources/scss/components/_validationForm.scss | 117 + .../scss/components/_versionController.scss | 196 + .../frontend/resources/scss/features/_catalog.scss | 102 + .../resources/scss/features/_composition.scss | 94 + .../frontend/resources/scss/features/_general.scss | 39 + .../resources/scss/features/_inputOutput.scss | 155 + .../resources/scss/features/_overview.scss | 337 + .../resources/scss/features/_workflow.scss | 4 + .../src/main/frontend/resources/scss/style.scss | 7 + .../src/main/frontend/src/App.js | 106 + .../src/main/frontend/src/appConstants.js | 37 + .../src/main/frontend/src/appSelectors.js | 16 + .../src/main/frontend/src/config/Configuration.js | 63 + .../src/main/frontend/src/config/config.json | 6 + .../src/features/activities/activitiesActions.js | 25 + .../src/features/activities/activitiesApi.js | 35 + .../src/features/activities/activitiesConstants.js | 24 + .../src/features/activities/activitiesReducer.js | 26 + .../src/features/activities/activitiesSaga.js | 41 + .../src/features/activities/activitiesSelectors.js | 22 + .../main/frontend/src/features/catalog/Catalog.js | 53 + .../frontend/src/features/catalog/CatalogView.jsx | 182 + .../catalog/__tests__/catalogActions-test.js | 65 + .../catalog/__tests__/catalogReducer-test.js | 112 + .../catalog/__tests__/catalogSagas-test.js | 109 + .../src/features/catalog/catalogActions.js | 48 + .../frontend/src/features/catalog/catalogApi.js | 45 + .../src/features/catalog/catalogConstants.js | 31 + .../src/features/catalog/catalogReducer.js | 60 + .../frontend/src/features/catalog/catalogSagas.js | 56 + .../src/features/catalog/views/AddWorkflow.jsx | 45 + .../frontend/src/features/catalog/views/Header.jsx | 46 + .../frontend/src/features/catalog/views/Main.jsx | 79 + .../src/features/catalog/views/StatusSelector.js | 24 + .../src/features/catalog/views/Workflows.jsx | 47 + .../main/frontend/src/features/version/Version.js | 19 + .../frontend/src/features/version/VersionView.jsx | 127 + .../features/version/composition/Composition.js | 62 + .../version/composition/CompositionUpdate.js | 131 + .../version/composition/CompositionView.js | 284 + .../src/features/version/composition/bpmnUtils.js | 93 + .../composition/components/CompositionButton.js | 36 + .../components/CompositionButtonsPanel.js | 56 + .../version/composition/compositionActions.js | 34 + .../version/composition/compositionConstants.js | 38 + .../version/composition/compositionReducer.js | 44 + .../version/composition/compositionSelectors.js | 32 + .../custom/CustomContextPadProvider.js | 43 + .../custom-modeler/custom/CustomElementFactory.js | 101 + .../custom-modeler/custom/CustomPalette.js | 151 + .../custom-modeler/custom/CustomRenderer.js | 176 + .../custom-modeler/custom/CustomRules.js | 136 + .../custom-modeler/custom/CustomUpdater.js | 136 + .../composition/custom-modeler/custom/index.js | 22 + .../version/composition/custom-modeler/index.js | 99 + .../descriptors/camunda.json | 1025 ++ .../provider/camunda/WorkflowPropertiesProvider.js | 300 + .../provider/camunda/index.js | 10 + .../camunda/parts/InputOutputParameterProps.js | 21 + .../provider/camunda/parts/InputOutputProps.js | 13 + .../parts/WorkflowServiceTaskDelegateProps.js | 123 + .../camunda/parts/createInputOutputTabGroups.js | 58 + .../camunda/parts/implementation/Delegate.js | 78 + .../camunda/parts/implementation/InputOutput.js | 289 + .../parts/implementation/InputOutputHelper.js | 173 + .../parts/implementation/InputOutputParameter.js | 424 + .../parts/implementation/InputOutputUpdater.js | 74 + .../camunda/parts/implementation/ResultVariable.js | 52 + .../parts/implementation/WorkflowActivity.js | 89 + .../implementation/WorkflowImplementationType.js | 226 + .../implementation/implementationConstants.js | 34 + .../features/version/composition/newDiagram.bpmn | 9 + .../src/features/version/composition/readOnly.js | 134 + .../src/features/version/create/CreateVersion.js | 53 + .../features/version/create/CreateVersionView.jsx | 95 + .../__tests__/CreateVersionView_snapshot-test.js | 28 + .../CreateVersionView_snapshot-test.js.snap | 81 + .../version/create/createVersionConstants.js | 30 + .../version/create/views/NewVersionContainer.jsx | 45 + .../src/features/version/general/General.js | 39 + .../src/features/version/general/GeneralView.js | 61 + .../features/version/general/generalSelectors.js | 33 + .../features/version/inputOutput/InputOutput.js | 83 + .../version/inputOutput/InputOutputView.jsx | 234 + .../__tests__/inputOutputActions-test.js | 150 + .../__tests__/inputOutputReducer-test.js | 191 + .../__tests__/inputOutputSelectors-test.js | 149 + .../version/inputOutput/inputOutputActions.js | 53 + .../version/inputOutput/inputOutputConstants.js | 39 + .../version/inputOutput/inputOutputReducer.js | 130 + .../version/inputOutput/inputOutputSelectors.js | 106 + .../version/inputOutput/inputOutputValidations.js | 64 + .../features/version/inputOutput/views/DataRow.jsx | 87 + .../version/inputOutput/views/NoDataRow.jsx | 32 + .../src/features/version/inputOutput/views/Tab.js | 43 + .../version/inputOutput/views/TableBody.jsx | 50 + .../version/inputOutput/views/TableHead.jsx | 41 + .../frontend/src/features/version/versionApi.js | 82 + .../src/features/version/versionConstants.js | 59 + .../version/versionController/VersionController.js | 73 + .../versionController/VersionControllerView.jsx | 171 + .../VersionControllerView_snapshot-test.js | 59 + .../VersionControllerView_snapshot-test.js.snap | 39 + .../versionControllerConstants.js | 29 + .../versionControllerSelectors.js | 36 + .../versionController/views/ActionButtons.js | 92 + .../views/OperationModeButtons.js | 70 + .../version/versionController/views/SvgButton.js | 62 + .../versionController/views/VersionButton.js | 38 + .../versionController/views/VersionSelect.js | 69 + .../versionController/views/VersionsContainer.js | 60 + .../versionController/views/WorkflowTitle.js | 34 + .../src/features/version/versionModeReducer.js | 10 + .../src/features/version/versionReducer.js | 51 + .../frontend/src/features/version/versionSaga.js | 167 + .../src/features/workflow/create/CreateWorkflow.js | 61 + .../workflow/create/CreateWorkflowView.jsx | 101 + .../__tests__/CreateWorkflowView_snapshot-test.js | 36 + .../CreateWorkflowView_snapshot-test.js.snap | 83 + .../create/__tests__/createWorkflowSaga-test.js | 76 + .../__tests__/createWorkflowSelector-test.js | 51 + .../features/workflow/create/createWorkflowApi.js | 30 + .../workflow/create/createWorkflowConstants.js | 44 + .../features/workflow/create/createWorkflowSaga.js | 79 + .../workflow/create/createWorkflowSelector.js | 31 + .../src/features/workflow/overview/Overview.js | 86 + .../features/workflow/overview/OverviewView.jsx | 142 + .../__tests__/OverviewView_snapshot-test.js | 39 + .../OverviewView_snapshot-test.js.snap | 217 + .../overview/__tests__/overviewReducer-test.js | 96 + .../src/features/workflow/overview/overviewApi.js | 46 + .../workflow/overview/overviewConstansts.js | 55 + .../features/workflow/overview/overviewReducer.js | 26 + .../features/workflow/overview/overviewSagas.js | 104 + .../workflow/overview/overviewSelectors.js | 62 + .../overview/views/VersionList/VersionListItem.jsx | 74 + .../workflow/overview/views/VersionList/index.js | 51 + .../workflow/overview/views/VersionTree.jsx | 43 + .../workflow/overview/views/WorkflowDetails.jsx | 75 + .../workflow/overview/views/WorkflowHeader.jsx | 106 + .../workflow/overview/views/WorkflowVersions.jsx | 67 + .../src/features/workflow/workflowConstants.js | 27 + .../src/features/workflow/workflowReducer.js | 60 + .../src/features/workflow/workflowSelectors.js | 34 + .../src/main/frontend/src/i18n/I18n.js | 31 + .../frontend/src/i18n/i18next-scanner.config.js | 44 + .../src/main/frontend/src/i18n/languages.json | 97 + .../src/main/frontend/src/i18n/translationSaga.js | 24 + .../src/main/frontend/src/index.js | 40 + .../src/pluginContext/pluginContextActions.js | 21 + .../src/pluginContext/pluginContextConstants.js | 22 + .../src/pluginContext/pluginContextReducer.js | 25 + .../src/pluginContext/pluginContextSelector.js | 16 + .../src/main/frontend/src/rootReducers.js | 51 + .../src/main/frontend/src/rootSaga.js | 38 + .../src/main/frontend/src/routes.js | 59 + .../src/main/frontend/src/services/restAPIUtil.js | 150 + .../src/shared/archiveLabel/ArchiveLabel.js | 8 + .../src/shared/components/Description/index.js | 50 + .../frontend/src/shared/components/Select/index.js | 54 + .../src/shared/components/VersionInfo/index.js | 43 + .../errorResponseHandler/errorResponseHandler.js | 31 + .../src/main/frontend/src/shared/loader/Loader.jsx | 50 + .../frontend/src/shared/loader/LoaderConstants.js | 38 + .../frontend/src/shared/loader/LoaderReducer.js | 49 + .../shared/loader/__tests__/loaderReducer-test.js | 56 + .../main/frontend/src/shared/modal/ModalWrapper.js | 35 + .../frontend/src/shared/modal/ModalWrapperView.jsx | 99 + .../modal/__tests__/modalWrapperActions-test.js | 85 + .../modal/__tests__/modalWrapperReducer-test.js | 61 + .../src/shared/modal/modalWrapperActions.js | 46 + .../src/shared/modal/modalWrapperComponents.js | 27 + .../src/shared/modal/modalWrapperReducer.js | 32 + .../shared/navigationSideBar/NavigationLink.jsx | 48 + .../shared/navigationSideBar/NavigationMenu.jsx | 39 + .../navigationSideBar/NavigationMenuItem.jsx | 44 + .../navigationSideBar/NavigationMenuItems.jsx | 47 + .../frontend/src/shared/navigationSideBar/index.js | 73 + .../src/shared/notifications/Notifications.js | 36 + .../src/shared/notifications/NotificationsView.jsx | 56 + .../__tests__/NotificationView_snapshot-test.js | 30 + .../NotificationView_snapshot-test.js.snap | 9 + .../__tests__/notificationsReducer-test.js | 61 + .../shared/notifications/notificationsActions.js | 60 + .../shared/notifications/notificationsConstants.js | 21 + .../shared/notifications/notificationsReducer.js | 30 + .../src/shared/notifications/notificationsSagas.js | 33 + .../main/frontend/src/shared/pubsub/base-pubsub.ts | 127 + .../frontend/src/shared/pubsub/plugin-pubsub.ts | 30 + .../frontend/src/shared/scroll/InfiniteScroll.js | 161 + .../main/frontend/src/shared/scroll/Scrollbars.js | 58 + .../src/shared/searchInput/SearchInput.jsx | 131 + .../src/main/frontend/src/shared/tree/Tree.jsx | 231 + .../src/main/frontend/src/store.js | 42 + .../src/main/frontend/testSetup/fileTransform.js | 25 + .../main/frontend/tools/ModuleRedirectPlugin.js | 44 + .../main/frontend/tools/devConfig.defaults.json | 27 + .../src/main/frontend/tools/getDevConfig.js | 25 + .../src/main/frontend/tools/mocks/mock.js | 209 + .../src/main/frontend/tools/proxy-server.js | 44 + .../src/main/frontend/tsconfig.json | 12 + .../src/main/frontend/webpack.config.js | 164 + .../src/main/frontend/yarn.lock | 12476 +++++++++++++++++++ 239 files changed, 29650 insertions(+) create mode 100644 sdc-workflow-designer-ui/src/main/frontend/.babelrc create mode 100644 sdc-workflow-designer-ui/src/main/frontend/.eslintignore create mode 100644 sdc-workflow-designer-ui/src/main/frontend/.eslintrc.json create mode 100644 sdc-workflow-designer-ui/src/main/frontend/.gitignore create mode 100644 sdc-workflow-designer-ui/src/main/frontend/.prettierignore create mode 100644 sdc-workflow-designer-ui/src/main/frontend/.prettierrc.json create mode 100644 sdc-workflow-designer-ui/src/main/frontend/__mocks__/fileMock.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/__mocks__/sdc-ui/lib/react/SVGIcon.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/external-resources/ping/ping create mode 100644 sdc-workflow-designer-ui/src/main/frontend/index.html create mode 100644 sdc-workflow-designer-ui/src/main/frontend/jest.config.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/jsconfig.json create mode 100644 sdc-workflow-designer-ui/src/main/frontend/package.json create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-600.woff create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-600.woff2 create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-italic.woff create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-italic.woff2 create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-regular.woff create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-regular.woff2 create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/_common.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/_components.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/_features.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_customVariables.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_fonts.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_utils.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_archiveLabel.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_customModal.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_expandableInput.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_inputOptions.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_layout.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_loader.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_navigationSideBar.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_notifications.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_scrollbars.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_searchInput.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_tree.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_validationForm.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_versionController.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_catalog.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_composition.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_general.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_inputOutput.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_overview.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_workflow.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/resources/scss/style.scss create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/App.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/appConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/appSelectors.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/config/Configuration.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/config/config.json create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesActions.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesApi.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSaga.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSelectors.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/Catalog.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/CatalogView.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogActions-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogReducer-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogSagas-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogActions.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogApi.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogSagas.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/AddWorkflow.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Header.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Main.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/StatusSelector.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Workflows.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/Version.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/VersionView.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/Composition.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionUpdate.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/bpmnUtils.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/components/CompositionButton.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/components/CompositionButtonsPanel.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionActions.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionSelectors.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomContextPadProvider.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomElementFactory.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomPalette.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomRenderer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomRules.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomUpdater.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/index.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/index.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/descriptors/camunda.json create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/WorkflowPropertiesProvider.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/index.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputParameterProps.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputProps.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/WorkflowServiceTaskDelegateProps.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/createInputOutputTabGroups.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/Delegate.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutput.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputHelper.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputParameter.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputUpdater.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/ResultVariable.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowActivity.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowImplementationType.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/implementationConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/newDiagram.bpmn create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/readOnly.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersion.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersionView.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/CreateVersionView_snapshot-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/__snapshots__/CreateVersionView_snapshot-test.js.snap create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/createVersionConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/views/NewVersionContainer.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/general/General.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/general/GeneralView.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/general/generalSelectors.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/InputOutput.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/InputOutputView.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/__tests__/inputOutputActions-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/__tests__/inputOutputReducer-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/__tests__/inputOutputSelectors-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputActions.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputSelectors.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/inputOutputValidations.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/views/DataRow.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/views/NoDataRow.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/views/Tab.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/views/TableBody.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/inputOutput/views/TableHead.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionApi.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/VersionController.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/VersionControllerView.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/__tests__/VersionControllerView_snapshot-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/__tests__/__snapshots__/VersionControllerView_snapshot-test.js.snap create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/versionControllerConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/versionControllerSelectors.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/ActionButtons.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/OperationModeButtons.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/SvgButton.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/VersionButton.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/VersionSelect.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/VersionsContainer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionController/views/WorkflowTitle.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionModeReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/version/versionSaga.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflow.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflowView.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/CreateWorkflowView_snapshot-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/__snapshots__/CreateWorkflowView_snapshot-test.js.snap create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/createWorkflowSaga-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/createWorkflowSelector-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowApi.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowSaga.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowSelector.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/Overview.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/OverviewView.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/__tests__/OverviewView_snapshot-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/__tests__/__snapshots__/OverviewView_snapshot-test.js.snap create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/__tests__/overviewReducer-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/overviewApi.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/overviewConstansts.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/overviewReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/overviewSagas.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/overviewSelectors.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/VersionList/VersionListItem.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/VersionList/index.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/VersionTree.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/WorkflowDetails.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/WorkflowHeader.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/overview/views/WorkflowVersions.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/workflowConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/workflowReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/features/workflow/workflowSelectors.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/i18n/I18n.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/i18n/i18next-scanner.config.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/i18n/languages.json create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/i18n/translationSaga.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/index.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/pluginContext/pluginContextActions.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/pluginContext/pluginContextConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/pluginContext/pluginContextReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/pluginContext/pluginContextSelector.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/rootReducers.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/rootSaga.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/routes.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/services/restAPIUtil.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/archiveLabel/ArchiveLabel.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/components/Description/index.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/components/Select/index.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/components/VersionInfo/index.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/errorResponseHandler/errorResponseHandler.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/loader/Loader.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/loader/LoaderConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/loader/LoaderReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/loader/__tests__/loaderReducer-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/modal/ModalWrapper.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/modal/ModalWrapperView.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/modal/__tests__/modalWrapperActions-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/modal/__tests__/modalWrapperReducer-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/modal/modalWrapperActions.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/modal/modalWrapperComponents.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/modal/modalWrapperReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/navigationSideBar/NavigationLink.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/navigationSideBar/NavigationMenu.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/navigationSideBar/NavigationMenuItem.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/navigationSideBar/NavigationMenuItems.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/navigationSideBar/index.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/notifications/Notifications.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/notifications/NotificationsView.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/notifications/__tests__/NotificationView_snapshot-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/notifications/__tests__/__snapshots__/NotificationView_snapshot-test.js.snap create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/notifications/__tests__/notificationsReducer-test.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/notifications/notificationsActions.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/notifications/notificationsConstants.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/notifications/notificationsReducer.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/notifications/notificationsSagas.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/pubsub/base-pubsub.ts create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/pubsub/plugin-pubsub.ts create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/scroll/InfiniteScroll.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/scroll/Scrollbars.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/searchInput/SearchInput.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/shared/tree/Tree.jsx create mode 100644 sdc-workflow-designer-ui/src/main/frontend/src/store.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/testSetup/fileTransform.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/tools/ModuleRedirectPlugin.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/tools/devConfig.defaults.json create mode 100644 sdc-workflow-designer-ui/src/main/frontend/tools/getDevConfig.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/tools/mocks/mock.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/tools/proxy-server.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/tsconfig.json create mode 100644 sdc-workflow-designer-ui/src/main/frontend/webpack.config.js create mode 100644 sdc-workflow-designer-ui/src/main/frontend/yarn.lock (limited to 'sdc-workflow-designer-ui/src/main/frontend') diff --git a/sdc-workflow-designer-ui/src/main/frontend/.babelrc b/sdc-workflow-designer-ui/src/main/frontend/.babelrc new file mode 100644 index 00000000..6a58a5a1 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/.babelrc @@ -0,0 +1,21 @@ +{ + "presets": [ + [ + "env", + { + "targets": { + "browsers": ["last 2 versions", "Firefox >= 47"] + } + } + ], + "react" + ], + "plugins": [ + "react-hot-loader/babel", + "transform-object-rest-spread", + "transform-class-properties", + "transform-runtime", + "transform-decorators-legacy" + ], + "sourceMap": "inline" +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/.eslintignore b/sdc-workflow-designer-ui/src/main/frontend/.eslintignore new file mode 100644 index 00000000..2410c0ec --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/.eslintignore @@ -0,0 +1,3 @@ +webpack.i18next-scanner.config.js +tools +common diff --git a/sdc-workflow-designer-ui/src/main/frontend/.eslintrc.json b/sdc-workflow-designer-ui/src/main/frontend/.eslintrc.json new file mode 100644 index 00000000..0ce8aa4c --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/.eslintrc.json @@ -0,0 +1,48 @@ +{ + "root": true, + + "parser": "babel-eslint", + + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:jest/recommended", + "prettier" + ], + + "plugins": ["prettier", "react"], + + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "jest": true, + "node": true + }, + + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true, + "generators": true, + "experimentalObjectRestSpread": true + } + }, + + "rules": { + "no-console": 0, + "prettier/prettier": [ + "error", + { + "singleQuote": true, + "jsxBracketSameLine": true, + "tabWidth": 4 + } + ] + }, + + "globals": { + "DEBUG": false + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/.gitignore b/sdc-workflow-designer-ui/src/main/frontend/.gitignore new file mode 100644 index 00000000..3491fa20 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/.gitignore @@ -0,0 +1,19 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules +/node-install +.idea/ +.vscode/ +# testing +/coverage + +# production +/target +/dist + +# misc +npm-debug.log* +yarn-debug.log* +yarn-error.log* +/tools/devConfig.json diff --git a/sdc-workflow-designer-ui/src/main/frontend/.prettierignore b/sdc-workflow-designer-ui/src/main/frontend/.prettierignore new file mode 100644 index 00000000..ec6d3cdd --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/.prettierignore @@ -0,0 +1 @@ +package.json diff --git a/sdc-workflow-designer-ui/src/main/frontend/.prettierrc.json b/sdc-workflow-designer-ui/src/main/frontend/.prettierrc.json new file mode 100644 index 00000000..37d2cddb --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "jsxBracketSameLine": true, + "tabWidth": 4 +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/__mocks__/fileMock.js b/sdc-workflow-designer-ui/src/main/frontend/__mocks__/fileMock.js new file mode 100644 index 00000000..2297d426 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/__mocks__/fileMock.js @@ -0,0 +1,19 @@ +/* +* 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. +*/ + +'use strict'; + +module.exports = 'test-file-stub'; diff --git a/sdc-workflow-designer-ui/src/main/frontend/__mocks__/sdc-ui/lib/react/SVGIcon.js b/sdc-workflow-designer-ui/src/main/frontend/__mocks__/sdc-ui/lib/react/SVGIcon.js new file mode 100644 index 00000000..2136c492 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/__mocks__/sdc-ui/lib/react/SVGIcon.js @@ -0,0 +1,51 @@ +/* +* 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 React from 'react'; + +const SVGIcon = ({ + name, + onClick, + label, + className, + iconClassName, + labelClassName, + labelPosition, + color, + disabled, + ...other +}) => { + let colorClass = color !== '' ? '__' + color : ''; + let classes = `svg-icon-wrapper ${iconClassName} ${className} ${colorClass} ${ + onClick ? 'clickable' : '' + } ${disabled ? 'disabled' : ''} ${labelPosition}`; + + let iconMock = ( +
+ + {label && ( + + {label} + + )} +
+ ); + + return iconMock; +}; +export default SVGIcon; diff --git a/sdc-workflow-designer-ui/src/main/frontend/external-resources/ping/ping b/sdc-workflow-designer-ui/src/main/frontend/external-resources/ping/ping new file mode 100644 index 00000000..1829c212 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/external-resources/ping/ping @@ -0,0 +1,11 @@ +{ + "workflowVersion": "${version}", + "componentsInfo": [ + { + "healthCheckComponent": "FE", + "healthCheckStatus": "UP", + "version": "${version}", + "description": "OK" + } + ] +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/index.html b/sdc-workflow-designer-ui/src/main/frontend/index.html new file mode 100644 index 00000000..f0d2b573 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/index.html @@ -0,0 +1,10 @@ + + + + + SDC Workflow App + + +
+ + diff --git a/sdc-workflow-designer-ui/src/main/frontend/jest.config.js b/sdc-workflow-designer-ui/src/main/frontend/jest.config.js new file mode 100644 index 00000000..43c12ef2 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/jest.config.js @@ -0,0 +1,48 @@ +/* +* 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. +*/ + +module.exports = { + collectCoverageFrom: ['src/**/*.{js,jsx,mjs}'], + setupFiles: ['jest-localstorage-mock'], + testMatch: [ + '/src/**/__tests__/**/*.{js,jsx,mjs}', + '/src/**/?(*.)(spec|test).{js,jsx,mjs}' + ], + testEnvironment: 'node', + testURL: 'http://localhost', + globals: { + DEBUG: false + }, + transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$'], + moduleNameMapper: { + '\\.(css|scss)$': 'identity-obj-proxy', + '\\.(gif|ttf|eot|svg)$': '/__mocks__/fileMock.js', + '^src(.*)$': '/src$1', + '^config(.*)$': '/src/config$1', + '^features(.*)$': '/src/features$1', + '^wfapp(.*)$': '/src$1', + '^common(.*)$': '/common$1', + '^services(.*)$': '/src/services$1', + '^shared(.*)$': '/src/shared$1', + '^i18n(.*)$': '/src/i18n$1' + }, + transform: { + '^.+\\.(js|jsx|mjs)$': '/node_modules/babel-jest', + '^(?!.*\\.(js|jsx|mjs|css|json)$)': + '/testSetup/fileTransform.js' + }, + roots: ['/src/features', '/src/shared'] +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/jsconfig.json b/sdc-workflow-designer-ui/src/main/frontend/jsconfig.json new file mode 100644 index 00000000..cb990650 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/jsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "config/*": ["./src/config/*"], + "features/*": ["./src/features/*"], + "shared/*": ["./src/shared/*"], + "services/*": ["./src/services/*"] + } + }, + "include": ["src"] +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/package.json b/sdc-workflow-designer-ui/src/main/frontend/package.json new file mode 100644 index 00000000..bc43db1b --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/package.json @@ -0,0 +1,107 @@ +{ + "name": "sdc-workflow", + "license": "Apache-2.0", + "scripts": { + "start": "webpack-dev-server --mode=development --progress --hot --inline", + "start-mock": "webpack-dev-server --mode=development --progress --hot --inline --env=mock", + "build": "webpack --mode=production", + "test": "jest --env=jsdom", + "test-dev": "jest --env=jsdom --watch", + "test-coverage": "jest --coverage --env=jsdom && start ./coverage/lcov-report/index.html", + "test-build": "jest --coverage --env=jsdom", + "lint-fix": "eslint --fix --ext .js --ext .jsx src", + "scan-for-i18n-keys": "i18next-scanner --config ./src/i18n/i18next-scanner.config.js 'src/**/*.{js,jsx }' --output dist" + }, + "dependencies": { + "axios": "^0.18.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", + "dateformat": "^3.0.3", + "enzyme": "^3.3.0", + "enzyme-adapter-react-16": "^1.1.1", + "file-saver": "^1.3.8", + "http-proxy-middleware": "^0.17.4", + "inherits": "^2.0.3", + "lodash.assign": "^4.2.0", + "lodash.foreach": "^4.5.0", + "lodash.isempty": "^4.4.0", + "lodash.isequal": "^4.5.0", + "lodash.map": "^4.6.0", + "lodash.merge": "^4.6.1", + "lodash.set": "^4.3.2", + "md5": "^2.2.1", + "moment": "^2.18.1", + "onap-ui-common": "^1.0.101", + "onap-ui-react": "^1.0.0", + "perfect-scrollbar": "^1.4.0", + "prop-types": "^15.6.1", + "qs": "^6.5.2", + "react": "^16.2.0", + "react-datepicker": "^0.48.0", + "react-dom": "^16.3.2", + "react-hot-loader": "^4.3.3", + "react-redux": "^5.0.6", + "react-redux-i18n": "^1.9.2", + "react-router": "^4.3.1", + "react-router-dom": "^4.2.2", + "react-select": "^1.2.1", + "react-transition-group": "^2.3.1", + "redux": "^3.7.2", + "redux-actions": "^2.4.0", + "redux-saga": "^0.16.0", + "redux-thunk": "^2.3.0", + "reselect": "^3.0.1", + "uuid-js": "^0.7.5", + "validator": "^10.2.0" + }, + "devDependencies": { + "awesome-typescript-loader": "^5.2.0", + "babel-core": "^6.24.0", + "babel-eslint": "^9.0.0", + "babel-jest": "^22.1.0", + "babel-loader": "7.1.4", + "babel-plugin-transform-class-properties": "^6.10.2", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-plugin-transform-object-rest-spread": "^6.8.0", + "babel-plugin-transform-runtime": "^6.22.0", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.23.0", + "clean-webpack-plugin": "^0.1.19", + "css-loader": "^0.23.1", + "eslint": "^5.4.0", + "eslint-config-prettier": "^3.0.1", + "eslint-loader": "^2.1.0", + "eslint-plugin-import": "^2.14.0", + "eslint-plugin-jest": "^21.22.0", + "eslint-plugin-prettier": "^2.6.2", + "eslint-plugin-react": "^7.11.1", + "file-loader": "^1.1.11", + "html-webpack-plugin": "^3.2.0", + "i18next-scanner": "^2.4.6", + "identity-obj-proxy": "^3.0.0", + "install": "^0.11.0", + "jest": "^22.0.5", + "jest-localstorage-mock": "^2.2.0", + "less": "^3.0.4", + "less-loader": "^4.1.0", + "node-sass": "^4.7.2", + "npm": "^6.0.1", + "prettier": "1.14.2", + "raw-loader": "^0.5.1", + "react-test-renderer": "^16.4.1", + "sass-loader": "^6.0.6", + "source-map-loader": "^0.1.5", + "typescript": "^2.9.2", + "uglifyjs-webpack-plugin": "^1.1.6", + "webpack": "^4.5.0", + "webpack-api-mocker": "^1.4.3", + "webpack-cli": "^2.0.14", + "webpack-dev-server": "^3.1.3", + "webpack-glob-entry": "^2.1.1", + "webpack-sass-loaders": "^1.0.0", + "webpack-shell-plugin": "^0.5.0" + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-600.woff b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-600.woff new file mode 100644 index 00000000..5a604b3a Binary files /dev/null and b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-600.woff differ diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-600.woff2 b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-600.woff2 new file mode 100644 index 00000000..a0965b7a Binary files /dev/null and b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-600.woff2 differ diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-italic.woff b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-italic.woff new file mode 100644 index 00000000..cf8b191c Binary files /dev/null and b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-italic.woff differ diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-italic.woff2 b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-italic.woff2 new file mode 100644 index 00000000..bad9292b Binary files /dev/null and b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-italic.woff2 differ diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-regular.woff b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-regular.woff new file mode 100644 index 00000000..e495e6f0 Binary files /dev/null and b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-regular.woff differ diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-regular.woff2 b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-regular.woff2 new file mode 100644 index 00000000..c8050c25 Binary files /dev/null and b/sdc-workflow-designer-ui/src/main/frontend/resources/fonts/open-sans-v15-latin-regular.woff2 differ diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/_common.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/_common.scss new file mode 100644 index 00000000..825609d7 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/_common.scss @@ -0,0 +1,5 @@ +@import '~onap-ui-common/lib/scss/_typography.scss'; +@import '~onap-ui-common/lib/scss/variables.scss'; +@import 'common/fonts'; +@import 'common/utils'; +@import 'common/customVariables'; diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/_components.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/_components.scss new file mode 100644 index 00000000..3baac0b0 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/_components.scss @@ -0,0 +1,12 @@ +@import 'components/layout'; +@import 'components/inputOptions'; +@import 'components/navigationSideBar'; +@import 'components/versionController'; +@import 'components/expandableInput'; +@import 'components/notifications'; +@import 'components/searchInput'; +@import 'components/loader'; +@import 'components/tree'; +@import 'components/customModal'; +@import 'components/scrollbars'; +@import 'components/archiveLabel'; \ No newline at end of file diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/_features.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/_features.scss new file mode 100644 index 00000000..c83b6e75 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/_features.scss @@ -0,0 +1,6 @@ +@import "features/general"; +@import "features/workflow"; +@import "features/catalog"; +@import "features/composition"; +@import "features/overview"; +@import "features/inputOutput"; diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_customVariables.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_customVariables.scss new file mode 100644 index 00000000..5e5bef84 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_customVariables.scss @@ -0,0 +1,51 @@ +$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; +} + +@mixin heading-1-emphasis() { + @include base-font-semibold; + font-size: $heading-font-1; +} + +.flex { + display: flex; + flex: 1; +} + +.flex-column { + @extend .flex; + flex-direction: column; +} + +.text-uppercase { + text-transform: uppercase; +} + +.content-area { + padding: 30px 60px 70px 60px; + overflow-y: auto; + overflow-x: hidden; + height: 100%; + &.no-padding-content-area { + padding: 0; + } +} + +.page-title { + @include heading-1; + @extend .text-uppercase !optional; + margin-bottom: 20px; + color: $blue; +} + +.disabled { + opacity: 0.7 !important; + cursor: $cursor-disabled; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_fonts.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_fonts.scss new file mode 100644 index 00000000..f367c23b --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_fonts.scss @@ -0,0 +1,26 @@ +@font-face { + font-family: 'OpenSans-Regular'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), + url('../fonts/open-sans-v15-latin-regular.woff2') format('woff2'), + url('../fonts/open-sans-v15-latin-regular.woff') format('woff'); +} + +@font-face { + font-family: 'OpenSans-Italic'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), + url('../fonts/open-sans-v15-latin-italic.woff2') format('woff2'), + url('../fonts/open-sans-v15-latin-italic.woff') format('woff'); +} + +@font-face { + font-family: 'OpenSans-SemiBold'; + font-style: normal; + font-weight: 600; + src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), + url('../fonts/open-sans-v15-latin-600.woff2') format('woff2'), + url('../fonts/open-sans-v15-latin-600.woff') format('woff'); +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_utils.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_utils.scss new file mode 100644 index 00000000..7a35b38c --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/common/_utils.scss @@ -0,0 +1,317 @@ + +/* Prefix */ + +$box-sizing-prefix: webkit moz spec; +$border-radius-prefix: webkit spec; +$box-shadow-radius-prefix: webkit moz spec; +$text-shadow-radius-prefix: spec; +$text-shadow-prefix: spec; +$box-shadow-prefix: all; +$linear-gradient-prefix: all; +$transition-prefix: webkit moz o spec; +$flex-prefix: webkit spec; +$browserPrefixes: webkit moz o ms; + +@mixin prefix($property, $value, $prefixeslist: 'all') { + @if $prefixeslist == all { + -webkit-#{$property}: $value; + -moz-#{$property}: $value; + -ms-#{$property}: $value; + -o-#{$property}: $value; + #{$property}: $value; + } @else { + @each $prefix in $prefixeslist { + @if $prefix == webkit { + -webkit-#{$property}: $value; + } @else if $prefix == moz { + -moz-#{$property}: $value; + } @else if $prefix == ms { + -ms-#{$property}: $value; + } @else if $prefix == o { + -o-#{$property}: $value; + } @else if $prefix == spec { + #{$property}: $value; + } @else { + @warn "No such prefix: #{$prefix}"; + } + } + } +} + +/* Value Prefix*/ +@mixin value-suffix-with-range($property, $valuesuffix, $from, $to, $prefixeslist) { + + @if $prefixeslist == all { + #{property} : -webkit-#{$valuesuffix}($from, $to); + #{property} : -moz-#{$valuesuffix}($from, $to); + #{property} : -o-#{$valuesuffix}($from, $to); + #{property} : -ms-#{$valuesuffix}($from, $to); + + } @else { + @each $prefix in $prefixeslist { + @if $prefix == webkit { + #{property} : -webkit-#{$valuesuffix}($from, $to); + } @else if $prefix == moz { + #{property} : -moz-#{$valuesuffix}($from, $to); + } @else if $prefix == ms { + #{property} : -ms-#{$valuesuffix}($from, $to); + } @else if $prefix == o { + #{property} : -o-#{$valuesuffix}($from, $to); + } @else { + @warn "No such prefix: #{$prefix}"; + } + } + } +} + +/* Box sizing */ +@mixin box-sizing($value: border-box) { + @include prefix(box-sizing, $value, $box-sizing-prefix); +} + +/* Borders & Shadows */ +@mixin box-shadow($value) { + @include prefix(box-shadow, $value, $box-shadow-radius-prefix); +} + +@mixin sticky($value) { + position: sticky; + top: $value; +} + +@mixin text-shadow($value) { + @include prefix(text-shadow, $value, $text-shadow-radius-prefix); +} + +@mixin border-radius($value, $positions: all) { + @if ($positions == all) { + @include prefix(border-radius, $value, $border-radius-prefix); + } @else { + @each $position in $positions { + @include prefix(border-#{$position}-radius, $value, $border-radius-prefix); + } + } + +} + +@mixin transition($value) { + @include prefix(transition, $value, $transition-prefix); +} + +/* Opacity */ +@mixin opacity($alpha) { + $ie-opacity: round($alpha * 100); + opacity: $alpha; + filter: unquote("alpha(opacity = #{$ie-opacity})"); +} + +/* Ellipsis */ +@mixin ellipsis($width: 100%, $display: inline-block, $max-width: none) { + overflow: hidden; + text-overflow: ellipsis; + width: $width; + white-space: nowrap; + display: $display; + max-width: $max-width; +} + +@mixin multiline-ellipsis($lineHeight: 1.3em, $lineCount: 2, $bgColor: $white){ + overflow: hidden; + position: relative; + line-height: $lineHeight; + max-height: $lineHeight * $lineCount; + text-align: justify; + word-break: break-all; + // margin-right: -1em; + padding-right: 1em; + &:before { + content: '...'; + position: absolute; + right: 3px; + bottom: 0; + } + &:after { + content: ''; + position: absolute; + right: 0; + width: 1em; + height: 1em; + margin-top: 0.2em; + background: $bgColor; + } +} + +@mixin gradient($from, $to) { + /* fallback/image non-cover color */ + background-color: $from; + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from($from), to($to)); + @include value-suffix-with-range(background-color, linear-gradient, $from, $to, $linear-gradient-prefix); +} + +/* Vertical placement of multuple lines of text */ +@mixin vertical-text($height) { + position: absolute; + top: 50%; + margin-top: -$height/2; +} + +@mixin text-vertical-align($align: middle) { + display: table; + width: 100%; + + & > * { + vertical-align: $align; + display: table-cell; + } +} + +@mixin center-element($width) { + width: $width; + margin-left: auto; + margin-right: auto; +} + +@mixin center-content($width) { + & > * { + @include center-element($width); + } +} + +/* transform-rotate */ +// @mixin +// Defines a 2D rotation, the angle is specified in the parameter +// @param +// $deg - angle in degrees +@mixin transform-rotate($deg) { + transform: rotate($deg + deg); /* IE10 and Mozilla */ + -ms-transform: rotate($deg + deg); /* IE 9 */ + -webkit-transform: rotate($deg + deg); /* Safari and Chrome */ +} + +/* transform-translate */ +// @mixin +// Defines a 2D rotation, the angle is specified in the parameter +// @param +// $deg - angle in degrees +@mixin transform-translate($x, $y) { + transform: translate($x, $y); /* IE10 and Mozilla */ + -ms-transform: translate($x, $y); /* IE 9 */ + -webkit-transform: translate($x, $y); /* Safari and Chrome */ +} + +/* transform-scale */ +// @mixin +// Defines a 2D scale transformation, changing the elements width and height +// @param +// $width - width +// @param +// $height - height +@mixin transform-scale($width, $height) { + transform: scale($width, $height); /* IE10 and Mozilla */ + -ms-transform: scale($width, $height); /* IE 9 */ + -webkit-transform: scale($width, $height); /* Safari and Chrome */ +} + +@mixin scrollable() { + ::-webkit-scrollbar { + width: 8px; + } +} + +@mixin create-circle($size, $bgcolor) { + border-radius: 50%; + width: $size; + height: $size; + background: $bgcolor; + border: 3px solid $bgcolor; + display: flex; + align-items: center; + justify-content: center; +} + +/**/ +@mixin keyframe-animation($animationType, $properties, $fromValue, $toValue) { + + @keyframes #{$animationType} { + from { + $startIndex: 1; + @each $property in $properties { + #{$property}: nth($fromValue, $startIndex); + $startIndex: $startIndex + 1; + } + } + to { + $startIndex: 1; + @each $property in $properties { + #{$property}: nth($toValue, $startIndex); + $startIndex: $startIndex + 1; + } + } + } + @-moz-keyframes #{$animationType}{ + /* Firefox */ + from { + $startIndex: 1; + @each $property in $properties { + #{$property}: nth($fromValue, $startIndex); + $startIndex: $startIndex + 1; + } + } + to { + $startIndex: 1; + @each $property in $properties { + #{$property}: nth($toValue, $startIndex); + $startIndex: $startIndex + 1; + } + } + } + @-webkit-keyframes #{$animationType} { + /* Safari and Chrome */ + from { + $startIndex: 1; + @each $property in $properties { + #{$property}: nth($fromValue, $startIndex); + $startIndex: $startIndex + 1; + } + } + to { + $startIndex: 1; + @each $property in $properties { + #{$property}: nth($toValue, $startIndex); + $startIndex: $startIndex + 1; + } + } + } + @-o-keyframes #{$animationType} { + /* Opera */ + from { + $startIndex: 1; + @each $property in $properties { + #{$property}: nth($fromValue, $startIndex); + $startIndex: $startIndex + 1; + } + } + to { + $startIndex: 1; + @each $property in $properties { + #{$property}: nth($toValue, $startIndex); + $startIndex: $startIndex + 1; + } + } + } +} + + +/**/ +@mixin border-shadow($xShadow: 0.545px, $yShadow: 0.839px, $blur: 4px, $spread: 0, $color: $light-gray, $opacity: 0.2) { + @include box-shadow($xShadow $yShadow $blur $spread rgba($color, $opacity)); +} + +/* percent-plus-value */ +// @mixin +// Calculate length property (e.g. width, margin) by adding a value (e.g. in pixels) +// to a percentage of container height/width +@mixin percent-plus-value($property, $value, $percent: 100%) { + $string: 'calc(' + $percent + ' + ' + $value + ')'; + #{$property}: unquote($string); +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_archiveLabel.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_archiveLabel.scss new file mode 100644 index 00000000..a3fa8479 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_archiveLabel.scss @@ -0,0 +1,10 @@ +.archive-label { + @include body-3; + color: $white; + background-color: $dark-purple; + margin-left: 20px; + border-radius: 3px; + padding: 1px 10px; + align-self: center; + text-transform: none; +} \ No newline at end of file diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_customModal.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_customModal.scss new file mode 100644 index 00000000..fe8bd0cf --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_customModal.scss @@ -0,0 +1,24 @@ +.sdc-modal { + .custom-modal-wrapper { + width: auto; + } + + .form-custom-modal { + padding: 30px 35px 20px 35px; + + .sdc-input { + margin-bottom: 15px; + } + } + +} + +.modal-action-bar { + display: flex; + justify-content: flex-end; +} + +textarea.field-section.sdc-input__input { + height: 75px; + padding-top: 5px; +} \ No newline at end of file diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_expandableInput.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_expandableInput.scss new file mode 100644 index 00000000..2484a73e --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_expandableInput.scss @@ -0,0 +1,56 @@ +.expandable-input-top { + display: flex; + height: 22px; + .expandable-input-wrapper { + display: flex; + &.closed { + .svg-icon + { + &.__search { + height: 17px; + width: 17px; + transition: fill 0.5s ease-in; + fill: $blue; + cursor: pointer; + &:hover { + transition: fill 0.5s ease-in; + fill: $dark-blue; + } + } + } + } + &.opened { + .svg-icon-wrapper { + margin-left: 3px; + } + .svg-icon { + &.__search { + height: 17px; + width: 17px; + fill: $dark-blue; + } + } + .svg-icon { + &.__close { + margin-left: 7px; + opacity: 0.6; + fill: $dark-gray; + &:hover { + opacity: 1; + } + } + } + } + .expandable-input-control { + .form-control { + border: none; + background-color: transparent; + border-radius: 0; + border-bottom: 1px solid $gray; + height: 22px; + padding: 0 5px; + } + margin: 0; + } + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_inputOptions.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_inputOptions.scss new file mode 100644 index 00000000..4f7e309a --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_inputOptions.scss @@ -0,0 +1,48 @@ +.disabled { + .Select-control { + background-color: $silver; + .Select-placeholder { + color: $dark-gray; + } + } +} + +.input-options { + display: flex; + border: 1px solid $light-gray; + border-radius: 2px; + height: 30px; + &:hover { + border-color: $gray; + } + .input-options-select { + float: left; + border: none; + transition-property: width; + transition-duration: 300ms; + padding-top:0px; + padding-bottom: 0px; + height:28px; + + } + + .input-options-other{ + float: left; + height: 30px; + border: none; + padding-top:0px; + padding-bottom: 0px; + height:28px; + } + .input-options-separator { + width: 1px; + height: 24px; + margin-top: 2px; + margin-bottom: 2px; + border:1px solid $light-gray; + } +} + +.input-options.has-error { + border-color: $red; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_layout.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_layout.scss new file mode 100644 index 00000000..6862d554 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_layout.scss @@ -0,0 +1,34 @@ +.workflow-app { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + + * { + box-sizing: border-box; + } + + .custom-textarea { + resize: none; + } + + .version-wrapper { + display: grid; + grid-template-rows: 70px 1fr; + height: 100vh; + } + + .disabled { + pointer-events: none; + opacity: 0.4; + } + + .selectable { + user-select: text; + } + + .separator { + border-left: 1px solid $silver; + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_loader.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_loader.scss new file mode 100644 index 00000000..36488e93 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_loader.scss @@ -0,0 +1,159 @@ +.onboarding-loader { + .onboarding-loader-backdrop { + top: 0; + right: 0; + bottom: 0; + left: 0; + position: absolute; + background-color: #E1E4E6; + opacity: 0.5; + z-index: 99999; + } + .tlv-loader { + height: 63px; + width: 63px; + position: absolute; + top: 30%; + left: 50%; + margin-top: -10.5px; + margin-left: -10.5px; + } + .tlv-loader.large { + transform: scale(1); + } + .tlv-loader::before { + background-color: $gray; + border-radius: 50%; + box-shadow: 21px 21px 0px 0px $gray, 0px 42px 0px 0px $gray, -21px 21px 0px 0px $gray; + content: ''; + display: block; + height: 21px; + width: 21px; + position: absolute; + left: 50%; + margin-left: -10.5px; + } + .tlv-loader::after { + border-radius: 50%; + content: ''; + display: block; + position: absolute; + height: 21px; + width: 21px; + animation: dot-move-2 4.5s infinite ease-in; + } + @keyframes dot-move { + 0% { + background-color: $blue; + left: 21px; + top: 0; + } + 25% { + background-color: $yellow; + left: 42px; + top: 21px; + } + 50% { + background-color: $light-purple; + left: 21px; + top: 42px; + } + 75% { + background-color: $light-green; + left: 0; + top: 21px; + } + 100% { + background-color: $blue; + left: 21px; + top: 0; + } + } + @keyframes dot-move-2 { + 0% { + background-color: $blue; + left: 21px; + top: 0; + } + 6.25% { + background-color: $blue; + left: 42px; + top: 21px; + } + 12.5% { + background-color: $blue; + left: 21px; + top: 42px; + } + 18.75% { + background-color: $blue; + left: 0; + top: 21px; + } + 25% { + background-color: $yellow; + left: 21px; + top: 0; + } + 31.25% { + background-color: $yellow; + left: 42px; + top: 21px; + } + 37.5% { + background-color: $yellow; + left: 21px; + top: 42px; + } + 43.75% { + background-color: $yellow; + left: 0; + top: 21px; + } + 50% { + background-color: $light-purple; + left: 21px; + top: 0; + } + 56.25% { + background-color: $light-purple; + left: 42px; + top: 21px; + } + 62.5% { + background-color: $light-purple; + left: 21px; + top: 42px; + } + 68.75% { + background-color: $light-purple; + left: 0; + top: 21px; + } + 75% { + background-color: $light-green; + left: 21px; + top: 0; + } + 81.25% { + background-color: $light-green; + left: 42px; + top: 21px; + } + 87.5% { + background-color: $light-green; + left: 21px; + top: 42px; + } + 93.75% { + background-color: $light-green; + left: 0; + top: 21px; + } + 100% { + background-color: $blue; + left: 21px; + top: 0; + } + } + } diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_navigationSideBar.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_navigationSideBar.scss new file mode 100644 index 00000000..c830c028 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_navigationSideBar.scss @@ -0,0 +1,60 @@ +.workflow-navigation-side-bar { + width: 245px; + height: 100%; + background-color: $white; + border-right: 1px solid $light-gray; + @include box-shadow(1px -1px 3px 0px $silver); + border-bottom: 0; + + .navigation-side-content { + overflow: hidden; + height: 100%; + + .navigation-group { + height: 100%; + display: flex; + flex-direction: column; + background-color: $light-silver; + .group-name { + @include heading-4-emphasis; + @include ellipsis; + display: block; + padding: 24px 12px 13px 40px; + background-color: $white; + border-bottom: 1px solid $silver; + } + } + + .navigation-group-items { + padding-left: 20px; + + .navigation-group-item { + @include body-1; + cursor: pointer; + margin: 18px 0; + padding-left: 20px; + color: $dark-gray; + line-height: 17px; + &.selected-item { + padding-left: 0; + .collapse.in { + padding-left: 20px; + } + } + .navigation-group-item-name { + @include ellipsis; + white-space: normal; + &.selected { + @include body-1-emphasis; + border-left: 4px solid $blue; + padding-left: 18px; + color: $blue; + } + &.bold-name { + @include body-1-emphasis; + } + } + } + } + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_notifications.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_notifications.scss new file mode 100644 index 00000000..855c372e --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_notifications.scss @@ -0,0 +1,8 @@ +.workflow-notifications-container { + position: absolute; + z-index: 99999; + &.position-top-right { + right: 30px; + top: 50px; + } +} \ No newline at end of file diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_scrollbars.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_scrollbars.scss new file mode 100644 index 00000000..d036c714 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_scrollbars.scss @@ -0,0 +1,63 @@ +.ps__rail-x { + opacity: 1; + height: 4px; + /* there must be 'bottom' or 'top' for ps__rail-x */ + bottom: 0px; +} + +.ps__rail-y { + opacity: 1; + width: 4px; + /* there must be 'right' or 'left' for ps__rail-y */ + right: 0; +} + +.ps__thumb-x { + background-color: $light-gray; + border-radius: 0px; + height: 4px; + /* there must be 'bottom' for ps__thumb-x */ + bottom: 0px; +} + +.ps__thumb-y { + background-color: $light-gray; + border-radius: 0px; + width: 4px; + /* there must be 'right' for ps__thumb-y */ + right: 0px; +} + +.ps:hover > .ps__rail-x, +.ps:hover > .ps__rail-y, +.ps--focus > .ps__rail-x, +.ps--focus > .ps__rail-y, +.ps--scrolling-x > .ps__rail-x, +.ps--scrolling-y > .ps__rail-y { + opacity: 1; + background-color: transparent; +} + +.ps .ps__rail-x:hover, +.ps .ps__rail-y:hover, +.ps .ps__rail-x:focus, +.ps .ps__rail-y:focus, +.ps .ps__rail-x.ps--clicking, +.ps .ps__rail-y.ps--clicking { + opacity: 1; + background-color: transparent; +} + +.ps__rail-x:hover > .ps__thumb-x, +.ps__rail-x:focus > .ps__thumb-x, +.ps__rail-x.ps--clicking .ps__thumb-x { + background-color: $light-gray; + height: 4px; +} + +.ps__rail-y:hover > .ps__thumb-y, +.ps__rail-y:focus > .ps__thumb-y, +.ps__rail-y.ps--clicking .ps__thumb-y { + background-color: $light-gray; + width: 4px; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_searchInput.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_searchInput.scss new file mode 100644 index 00000000..efd68496 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_searchInput.scss @@ -0,0 +1,59 @@ +.search-input-top { + display: flex; + height: 22px; + .search-input-wrapper { + display: flex; + &.closed { + .svg-icon { + &.__search { + height: 17px; + width: 17px; + transition: fill 0.5s ease-in; + fill: $blue; + cursor: pointer; + &:hover { + transition: fill 0.5s ease-in; + fill: $dark-blue; + } + } + } + } + &.opened { + .svg-icon-wrapper { + margin-left: 3px; + } + .svg-icon { + &.__search { + height: 17px; + width: 17px; + fill: $dark-blue; + } + } + .svg-icon { + &.__close { + margin-left: 7px; + opacity: 0.6; + fill: $dark-gray; + &:hover { + opacity: 1; + } + } + } + } + .search-input-control { + .input-control { + border: none; + background-color: transparent; + border-radius: 0; + border-bottom: 1px solid $gray; + height: 22px; + padding: 0 5px; + outline: 0; + box-shadow: none; + transition: border-color ease-in-out 0.95s, + box-shadow ease-in-out 0.95s; + } + margin: 0; + } + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_tree.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_tree.scss new file mode 100644 index 00000000..58f1f995 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_tree.scss @@ -0,0 +1,56 @@ + +.tree-view { + overflow: hidden; + + &.scrollable { + overflow: auto; + } + + .node { + text-shadow: none; + stroke: none; + + .outer-circle { + stroke: $blue; + stroke-width: 2px; + fill: $white; + } + + .inner-circle { + fill: $blue; + } + + text { + text-anchor: end; + @include body-2-emphasis; + fill: $blue; + } + + &.clickable { + cursor: pointer; + } + + &.selectedNode { + .outer-circle { + fill: $blue; + } + + .inner-circle { + fill: $blue; + } + + text { + fill: $blue; + } + } + } + + + .link { + fill: none; + stroke: $dark-gray; + stroke-opacity: 0.4; + stroke-width: 1.5px; + } + +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_validationForm.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_validationForm.scss new file mode 100644 index 00000000..176e5469 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_validationForm.scss @@ -0,0 +1,117 @@ +form { + .validation-form-content { + .validation-input-wrapper { + position: relative; + flex: 1; + } + .validation-radio-wrapper { + position: relative; + } + .sdc-tabs { + position: relative; + .invalid-tab:not(.sdc-tab-active) { + color: $red; + } + } + .validation-error-message { + &.bottom { + .tooltip-arrow { + border-bottom-color: $red; + } + } + &.right { + .tooltip-arrow { + border-right-color: $red; + } + } + &.left { + .tooltip-arrow { + border-left-color: $red; + } + } + .tooltip-inner { + background-color: $red; + } + } + .input-row { + padding-bottom: 32px; + &:only-child { + padding-bottom: 0; + } + &:last-child { + padding-bottom: 0; + } + .form-group { + margin-bottom: 0; + } + } + + .rows-section { + .row-flex-components { + display: flex; + } + .validation-input-wrapper { + flex: 1; + } + .empty-col { + flex: 1.2; + content: ' '; + } + .empty-two-col { + flex: 2.4; + content: ' '; + } + + .two-col { + flex: 2.2; + } + .three-col { + flex: 3.4; + } + .single-col { + flex: 1.2; + display: flex; + &:after { + flex: 0.2; + content: ' '; + } + @media (min-width: 1389px) { + &.add-line-break { + .control-label { + &:after { + content: "\00a0"; + display: block; + } + } + } + } + + } + } + } + + .validation-buttons { + padding: 20px 0; + text-align: right; + button:first-child { + margin-right: 15px; + } + .svg-icon { + height: 14px; + width: 14px; + } + .svg-icon.check { + fill: $white; + } + .svg-icon.close { + fill: $blue; + } + } +} + +.modal-body { + .validation-buttons { + padding: 20px 15px; + background-color: $light-silver; + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_versionController.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_versionController.scss new file mode 100644 index 00000000..3cf9b05e --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/components/_versionController.scss @@ -0,0 +1,196 @@ +.version-controller-bar { + display: flex; + height: 70px; + border-bottom: 1px solid $silver; + background-color: transparent; + justify-content: space-between; + .group-name-wrapper { + width: 245px; + .group-name { + @include heading-4-emphasis; + @include ellipsis; + display: block; + padding: 24px 12px 13px 20px; + background-color: $white; + } + } + + .vc-container { + display: flex; + flex: 1; + align-self: center; + background-color: transparent; + justify-content: space-between; + align-items: center; + padding-left: 16px; + padding-right: 100px; + border-left: 1px solid #eaeaea; + height: 45px; + &.vs-container-operation { + flex: inherit; + } + .vc-separator { + border-left: 1px solid $silver; + height: 37px; + } + + .version-status-container { + display: flex; + align-items: center; + .version-selector-more-versions { + @include body-1-emphasis; + color: $blue; + cursor: pointer; + } + + .version-selector { + margin-top: 0; + padding-right: 10px; + margin-right: 15px; + margin-left: 10px; + border-color: $light-gray; + border-radius: 2px; + width: 243px; + height: 30px; + @include body-1; + } + + .version-section { + .form-group { + margin-right: 20px; + + .input-options { + border: none; + + .input-options-select { + padding-top: 4px; + } + } + } + } + + .vc-status { + display: flex; + padding-left: 20px; + border-left: $light-gray thin solid; + + .status-text { + align-self: center; + margin-top: 2px; + @include heading-5; + color: $dark-gray; + } + } + } + + .save-submit-cancel-container { + display: flex; + align-items: center; + height: 100%; + + .action-buttons, + .select-action-buttons, + .vc-save-section, + .vc-submit-section { + display: flex; + align-items: center; + height: 100%; + cursor: $cursor-pointer; + + .vc-submit-button { + border: 1px solid $dark-gray; + width: 94px; + height: 30px; + border-radius: 2px; + padding-top: 5px; + padding-left: 10px; + margin-left: 10px; + margin-right: 10px; + + &:hover:not(.disabled) { + cursor: pointer; + background-color: $silver; + } + + &.disabled { + border-color: $light-gray; + } + + .vc-v-submit { + width: 11px; + height: 8px; + margin-right: 10px; + position: relative; + top: -1px; + } + } + + .certifyBtn { + margin-left: 20px; + } + + .version-control-buttons { + display: flex; + } + + .action-button-wrapper { + display: flex; + align-items: center; + height: 70px; + padding: 10px; + + &:hover { + background-color: $silver; + } + + &:active { + background-color: $light-gray; + } + + .action-buttons-svg { + padding-left: 10px; + padding-right: 10px; + + .svg-icon { + fill: $text-black; + height: 20px; + + &, + &.__version-controller-save { + width: 20px; + } + &.__version-controller-permissions { + width: 32px; + } + &.__version-controller-undo, + &.__version-controller-revert { + width: 20px; + } + &.__version-controller-sync, + &.__version-controller-commit { + width: 28px; + } + } + .vs-back-btn { + height: '35px'; + width: '35px'; + .svg-icon { + height: '35px'; + width: '35px'; + transform: rotate(90deg); + } + } + } + } + + .action-button-label { + @include body-4; + display: block; + height: 1em; + margin-top: 5px; + margin-bottom: 0; + } + } + } + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_catalog.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_catalog.scss new file mode 100644 index 00000000..c5c32030 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_catalog.scss @@ -0,0 +1,102 @@ +.wf-catalog { + overflow: auto; + background-color: $light-silver; + grid-template-rows: 35px 1fr; + height: 100vh; + padding-bottom: 20px; + .header { + align-items: center; + display: flex; + justify-content: space-between; + background-color: $silver; + margin-bottom: 2px; + @include box-shadow(0px 1px 3px 0 rgba(0, 0, 0, 0.2)); + padding: 8px 60px 0 0px; + .wf-status-select { + + display: grid; + width: 200px; + height: 34px; + margin-top: -8px; + background-color: $light-silver; + color: $blue; + } + &__search { + height: 25px; + } + } + .main { + &__header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 25px 60px; + &__total { + @include body-1; + color: $dark-gray; + } + &__order { + display: flex; + &__label { + @include body-1; + color: $dark-gray; + } + &__alphabetical { + cursor: pointer; + display: flex; + &__label { + margin-left: 5px; + @include body-1; + color: $blue; + } + &__icon { + display: flex; + align-items: center; + margin-left: 5px; + .svg-icon { + width: 9px; + height: 9px; + } + &--flip { + transform: rotate(180deg); + } + } + } + } + } + &__content { + display: grid; + grid-template-columns: repeat(auto-fit, 204px); + grid-gap: 20px; + padding: 0 60px; + } + .add-workflow { + border: 2px dashed #a8b3b9; + width: 204px; + height: 204px; + padding: 10px; + box-sizing: border-box; + cursor: pointer; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: $gray; + &__icon { + color: $gray; + fill: $gray; + } + &__label { + text-transform: uppercase; + @include body-1-emphasis; + } + &:hover { + color: $blue; + .svg-icon-wrapper { + color: $blue; + fill: $blue; + } + } + } + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_composition.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_composition.scss new file mode 100644 index 00000000..b2b701b2 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_composition.scss @@ -0,0 +1,94 @@ +.composition-view { + display: flex; + width: 100%; + + .bpmn-container { + flex-basis: 100%; + flex-grow: 1; + .djs-palette.open { + border: none; + } + .djs-palette-entries { + border: solid 1px $light-gray; + &:empty { + border: none; + } + } + } + .bpmn-sidebar { + background-color: $light-silver; + height: 100%; + width: 320px; + + label { + @include body-1; + } + .group-label { + @include heading-4-emphasis; + font-size: 110%; + } + .properties-panel { + background-color: $light-silver; + overflow-y: auto; + max-height: calc(100vh - 70px); + &, .bpp-properties-panel { + [disabled], [editable-readonly=false] { + background-color: $light-gray; + color: $dark-gray; + pointer-events: none; + } + label[for] { + cursor: default; + background: transparent; + } + background-color: $light-silver; + #camunda-activitySelect-select { + &.invalid { + border-color: $camunda-panel-error-border-color; + background-color: $camunda-panel-error-background-color; + } + } + } + } + [editable-readonly] { + font-family: OpenSans-Regular, Arial, sans-serif; + font-style: normal; + font-weight: 400; + font-size: 14px; + box-sizing: border-box; + } + + .composition-buttons { + position: fixed; + background-color: $light-silver; + left: 265px; + bottom: 46px; + border: 1px solid $light-gray; + width: 189px; + display: flex; + flex-direction: row; + justify-content: space-around; + height: 57px; + align-items: center; + padding: 10px; + .divider { + height: 35px; + border: 1px solid $light-gray; + } + .diagram-btn { + + &:hover { + fill: $blue; + cursor: pointer; + } + &.disabled { + fill: $gray; + } + .svg-icon { + width: 25px; + height: 23px; + } + } + } + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_general.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_general.scss new file mode 100644 index 00000000..f11c2c0a --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_general.scss @@ -0,0 +1,39 @@ +.general-page { + @include body-1; + padding: 35px 90px 0 50px; + background-color: #fff; + + .general-page-title { + height: 110px; + line-height: 110px; + @include heading-1-emphasis; + color: $dark-gray; + } + + .general-page-content { + display: grid; + grid-template-columns: 60% 40%; + grid-gap: 40px; + color: #444; + + .description-part textarea { + height: 200px; + padding-top: 5px; + } + + .version-info-part { + background-color: $light-silver; + height: 200px; + margin-top: 22px; + padding: 20px; + box-sizing: border-box; + .label { + @include body-3; + margin-bottom: 5px; + } + .value { + margin-bottom: 10px; + } + } + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_inputOutput.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_inputOutput.scss new file mode 100644 index 00000000..56a8dd6b --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_inputOutput.scss @@ -0,0 +1,155 @@ +.input-output { + @mixin border($top: 1px, $right: 1px, $bottom: 1px, $left: 1px) { + border-width: $top $right $bottom $left; + border-style: solid; + border-color: $light-gray; + } + padding: 44px; + max-width: 1567px; + + &__title { + height: 110px; + line-height: 110px; + @include heading-1-emphasis; + color: $dark-gray; + } + + &__header { + display: flex; + &__right { + flex: 1; + display: flex; + justify-content: flex-end; + align-items: center; + } + } + + &__tab { + padding: 12px; + @include body-1-emphasis; + @include border(1px, 1px, 0, 1px); + background-color: $light-silver; + color: $gray; + min-width: 128px; + text-align: center; + cursor: pointer; + &--active { + color: $blue; + padding-top: 9px; + border-top: 4px solid $blue; + background-color: $white; + } + & + & { + border-left: none; + } + } + + &__table { + &__thead { + background-color: $silver; + @include body-1-emphasis; + } + .scrollbars { + min-height: 102px; + max-height: calc(100vh - 243px); + overflow: auto; + position: relative; + } + + &__tbody { + } + } + + &__tr { + display: flex; + @include border(); + &:hover:not(&--no-hover) { + background-color: $light-silver; + } + & + & { + border-top: none; + } + } + + &__th { + flex: 1; + padding: 10px; + color: $black; + display: flex; + align-items: center; + } + + &__td { + flex: 1; + display: flex; + align-items: center; + padding: 22px 17px; + &--empty { + padding: 20px; + color: $dark-gray; + @include body-1; + text-transform: uppercase; + justify-content: center; + } + + .input-output-select { + width: 100%; + height: 32px; + @include border(); + border-radius: 2px; + padding-left: 5px; + color: $text-black; + } + + .sdc-input { + width: 100%; + position: relative; + margin: unset; + .sdc-input__label { + display: none; + } + .sdc-input__input { + height: 32px; + } + .sdc-label__error { + margin: unset; + position: absolute; + bottom: -22px; + } + } + } + + &__add { + cursor: pointer; + @include body-1; + text-transform: uppercase; + @include border(0, 0, 0, 1px); + padding-left: 10px; + margin-left: 10px; + } + + &__td, + &__th { + .sdc-checkbox { + height: 14px; + } + &--unflex { + flex: unset; + justify-content: center; + text-align: center; + width: 127px; + } + &--icon { + width: 98px; + .svg-icon-wrapper { + cursor: pointer; + &:hover { + fill: $blue; + } + } + } + & + & { + @include border(0, 0, 0, 1px); + } + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_overview.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_overview.scss new file mode 100644 index 00000000..c1c371fd --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_overview.scss @@ -0,0 +1,337 @@ +.overview-page { + @include body-1; + color: $dark-gray; + overflow-y: auto; + height: 100vh; + + .overview-content { + display: flex; + flex-wrap: wrap; + min-height: 775px; + + .overview-separator { + border-left: 1px solid $silver; + } + + .workflow-details { + @extend .flex; + @media (min-width: 1076px) { + @include sticky(30px); + } + max-height: 600px; + padding: 0 45px 0 56px; + flex-direction: column; + + .description-part { + padding-top: 20px; + textarea{ + height: 200px; + } + } + + .save-description { + display: flex; + justify-content: flex-end; + } + + .version-info-part { + background-color: $light-silver; + margin-top: 25px; + padding: 20px; + box-sizing: border-box; + .label { + @include body-1; + margin-bottom: 5px; + } + .value { + margin-bottom: 20px; + &:last-child { + margin-bottom: 0; + } + } + } + } + + .workflow-versions { + display: flex; + flex: 2; + } + } + + .overview-header { + display: flex; + margin: 35px 60px 35px 60px; + color: $blue; + justify-content: space-between; + .title { + display: flex; + @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; + } + } + .restore-btn { + margin-left: 20px; + } + .archive-btn { + margin-left: 20px; + fill: $gray; + &:hover { + fill: $blue; + color: $light-blue; + cursor: pointer; + } + } + } + + @mixin version-page-box-shadow() { + box-shadow: 1px 1px 0 0 rgba(24, 24, 24, 0.06); + } + + @mixin version-page-sub-title(){ + color: $text-black; + text-transform: uppercase; + border-bottom: 1px solid $light-gray; + padding: 12px 0 10px 45px; + } + + .versions-page-view { + padding: 0 56px 0 45px; + display: flex; + flex: 2; + flex-direction: column; + + .create-new-version { + @extend .text-uppercase; + display: flex; + flex-direction: row-reverse; + color: $blue; + margin-left: auto; + cursor: pointer; + } + .newVersionDisabled > *, .svg-icon-wrapper{ + pointer-events: none; + color: $gray; + } + .version-page-header { + display: flex; + justify-content: space-between; + .versions-page-title { + @include heading-1; + text-transform: uppercase; + margin-bottom: 29px; + color: $blue; + } + .depricate-btn-wrapper { + display: flex; + justify-content: flex-end; + margin-bottom: 10px; + } + } + + .versions-page-list-and-tree { + display: flex; + margin-top: 10px; + + .version-tree-wrapper { + display: flex; + flex-direction: column; + transition: all 1s ease; + @include version-page-box-shadow(); + + .version-tree-title-container { + @include body-1-emphasis(); + @media (min-width: 1076px) { + @include sticky(1px); + } + background-color: $light-silver; + display: flex; + align-items: center; + height: 40px; + @include version-page-sub-title(); + padding-right: 10px; + + .version-tree-full-screen { + margin-left: auto; + } + } + + .tree-view { + flex: 1; + border-left: 1px solid $silver; + &:last-child { + border-bottom: 1px solid $silver; + } + .node:not(.selectedNode):hover { + .outer-circle, .inner-circle { + transform: scale(1.1); + } + } + } + } + } + + .version-list { + @extend .flex; + flex-direction: column; + + .version-list-items { + @extend .flex-column; + + .item-version, .item-status { + font-size: 12px; + font-weight: 600; + } + .version-item-row { + &:last-child { + border-bottom: 1px solid $silver; + } + } + } + + .version-item-row { + $row-hover-color: lighten($blue, 54%); + $row-active-color: lighten($blue, 51%); + cursor: $cursor-pointer; + + display: flex; + align-items: center; + padding: 15px 30px; + @include version-page-box-shadow(); + height: 70px; + max-height: 70px; + + &:hover { + background-color: $row-hover-color; + } + + &.selected { + box-shadow: 0 1px 4px 0 rgba(24, 24, 24, 0.06), inset 5px 0 0 0 $blue; + background-color: $row-active-color; + + &:hover { + box-shadow: 0 1px 4px 0 rgba(24, 24, 24, 0.06), inset 5px 0 0 0 lighten($blue, 35%); + } + } + + &.header-row { + height: 40px; + background-color: $light-silver; + @media (min-width: 1076px) { + @include sticky(1px); + } + @include body-1-emphasis(); + @include version-page-sub-title(); + padding: 15px 27px; + + &:hover { + pointer-events: none; + &:active { + @include version-page-box-shadow(); + } + } + .header-field.actions { + margin-right: 57px; + } + } + + .version-item-field { + @extend .flex; + margin-right: 10px; + + &.item-version, &.item-status { + flex: 0 1 10%; + color: $text-black; + } + + &.item-description, &.item-last-edited { + @include body-1; + } + + &.item-description, &.header-description { + flex: 1 1 0; + } + + &.item-description > .description-text { + margin-right: 10px; + @include ellipsis($max-width: 280px); + width: initial; + } + + &.item-actions { + display: flex; + flex: 1 1 3%; + justify-content: space-between; + } + + &.item-select, &.item-create { + @include body-1; + flex: 0 1 auto; + margin-right: 0; + + .svg-icon-wrapper { + fill: $blue; + color: $blue; + + &[disabled] { + cursor: default; + } + + .svg-icon { + width: 16px; + height: 16px; + } + + &:hover:not([disabled]) { + fill: $dark-blue; + color: $dark-blue; + } + } + } + + } + + /* To keep ellipsis hider's background the same color as row background */ + &:not(.selected):hover .item-description > .description-text:after { + background: $row-hover-color; + } + + &:hover:active .item-description > .description-text:after { + background: $row-active-color; + } + + } + + } + + &.clickable { + cursor: pointer; + } + } + +} + +.inputinput-selector { + padding-right: 10px; + border-color: $light-gray; + border-radius: 2px; + width: 100%; + height: 30px; + @include body-1; + + &:disabled { + @extend .disabled; + background-color: $silver; + } +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_workflow.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_workflow.scss new file mode 100644 index 00000000..f959d17f --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/features/_workflow.scss @@ -0,0 +1,4 @@ +.workflow-view { + display: grid; + grid-template-columns: 245px 1fr; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/resources/scss/style.scss b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/style.scss new file mode 100644 index 00000000..09e8c8bc --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/resources/scss/style.scss @@ -0,0 +1,7 @@ +@import '~bpmn-js/dist/assets/diagram-js.css'; +@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn.css'; +@import 'common'; +@import '~onap-ui-common/lib/style.css'; +@import '~perfect-scrollbar/css/perfect-scrollbar.css'; +@import 'components'; +@import 'features'; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/App.js b/sdc-workflow-designer-ui/src/main/frontend/src/App.js new file mode 100644 index 00000000..5b7c154d --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/App.js @@ -0,0 +1,106 @@ +/* +* 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 { hot } from 'react-hot-loader'; +import React, { Component } from 'react'; +import { Route, withRouter } from 'react-router-dom'; +import qs from 'qs'; +import { connect } from 'react-redux'; +import { PluginPubSub } from 'shared/pubsub/plugin-pubsub'; +import 'resources/scss/style.scss'; +import 'bpmn-js-properties-panel/styles/properties.less'; +import { routes } from 'wfapp/routes'; +import { USER_ID } from 'wfapp/appConstants'; +import { getVersionsAction } from 'features/workflow/overview/overviewConstansts'; +import { setOperationModeAction } from 'features/version/versionConstants'; +import { setPluginContext } from './pluginContext/pluginContextActions'; +import { notificationType } from 'wfapp/pluginContext/pluginContextConstants'; +const RouteWithSubRoutes = route => ( + } + /> +); + +function mapActionsToProps(dispatch) { + return { + getOverview: workflowId => { + dispatch(getVersionsAction(workflowId)); + dispatch(setOperationModeAction()); + }, + setPluginContext: payload => dispatch(setPluginContext(payload)) + }; +} + +class App extends Component { + constructor(props) { + super(props); + + this.searchParams = qs.parse(location.search, { + ignoreQueryPrefix: true + }); + + if (this.searchParams && this.searchParams.userId) { + localStorage.setItem(USER_ID, this.searchParams.userId); + } + } + + componentDidMount() { + if (this.searchParams) { + const { + eventsClientId, + parentUrl, + workflowId, + versionId + } = this.searchParams; + + if (eventsClientId && parentUrl) { + this.props.setPluginContext({ + eventsClientId, + parentUrl + }); + const client = new PluginPubSub(eventsClientId, parentUrl); + client.notify(notificationType.READY); + } + if (workflowId && versionId) { + this.props.getOverview(workflowId); + this.props.history.push( + `/workflow/${workflowId}/version/${versionId}/composition` + ); + } + } + } + + render() { + return ( +
+ {routes.map((route, i) => ( + + ))} +
+ ); + } +} + +export default hot(module)( + withRouter( + connect( + null, + mapActionsToProps + )(App) + ) +); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/appConstants.js b/sdc-workflow-designer-ui/src/main/frontend/src/appConstants.js new file mode 100644 index 00000000..710c4d8c --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/appConstants.js @@ -0,0 +1,37 @@ +/* +* 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 { createAction } from 'redux-actions'; +export const LANG = 'en'; +export const USER_ID = 'USER_ID'; +export const VERSION_LEVEL_LIST = [ + { + id: '2', + name: 'Major', + value: '2' + }, + { + id: '1', + name: 'Minor', + value: '1' + } +]; + +export const NETWORK_GENERIC_ERROR = 'NETWORK_GENERIC_ERROR'; +export const genericNetworkErrorAction = createAction( + NETWORK_GENERIC_ERROR, + error => error +); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/appSelectors.js b/sdc-workflow-designer-ui/src/main/frontend/src/appSelectors.js new file mode 100644 index 00000000..657429e4 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/appSelectors.js @@ -0,0 +1,16 @@ +/* +* 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. +*/ +export const i18nSelector = state => state && state.i18n.locale; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/config/Configuration.js b/sdc-workflow-designer-ui/src/main/frontend/src/config/Configuration.js new file mode 100644 index 00000000..36ad33d7 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/config/Configuration.js @@ -0,0 +1,63 @@ +/* + * 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 configData from './config.json'; + +class Configuration { + get(key) { + return configData[key]; + } + + set(key, value) { + var prev = configData[key]; + configData[key] = value; + return prev; + } + + setCatalogApiRoot(CatalogApiRoot) { + let restCatalogPrefix = CatalogApiRoot, + restPrefix = CatalogApiRoot.replace( + /\/feProxy\b[^:]*$/, + '/feProxy/onboarding-api' + ); + + this.set('restPrefix', restPrefix); + this.set('restCatalogPrefix', restCatalogPrefix); + } + + setCatalogApiHeaders(CatalogApiHeaders) { + this.set('CatalogApiHeaders', CatalogApiHeaders); + + let { userId: { value: UserID } = {} } = CatalogApiHeaders; + this.set('UserID', UserID); + } +} + +const configuration = new Configuration(); + +(function setDefaultRestPrefixes(configuration) { + configuration.set('restPrefix', configuration.get('defaultRestPrefix')); + configuration.set( + 'restCatalogPrefix', + configuration.get('defaultRestCatalogPrefix') + ); + configuration.set( + 'activitiesRestPrefix', + configuration.get('activitiesRestPrefix') + ); + configuration.set('appContextPath', configuration.get('appContextPath')); +})(configuration); + +export default configuration; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/config/config.json b/sdc-workflow-designer-ui/src/main/frontend/src/config/config.json new file mode 100644 index 00000000..96a7ca5b --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/config/config.json @@ -0,0 +1,6 @@ +{ + "version": "0.1", + "appContextPath" : "/", + "defaultRestPrefix": "/workflows/wf", + "activitiesRestPrefix": "/workflows/v1.0" +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesActions.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesActions.js new file mode 100644 index 00000000..833f6e5f --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesActions.js @@ -0,0 +1,25 @@ +/* +* Copyright © 2018 European Support Limited +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* + * http://www.apache.org/licenses/LICENSE-2.0 +* + * Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import { SET_ACTIVITIES_LIST, GET_ACTIVITIES } from './activitiesConstants'; + +export const setActivitiesList = payload => ({ + type: SET_ACTIVITIES_LIST, + payload +}); + +export const getActivitiesList = () => ({ + type: GET_ACTIVITIES +}); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesApi.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesApi.js new file mode 100644 index 00000000..10141e09 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesApi.js @@ -0,0 +1,35 @@ +/* +* 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 RestfulAPIUtil from 'services/restAPIUtil'; +import Configuration from 'config/Configuration.js'; +import { activityStatus } from './activitiesConstants'; + +function baseUrl() { + const restPrefix = Configuration.get('activitiesRestPrefix'); + return `${restPrefix}/activity-spec`; +} + +export default { + fetchActivities: () => { + return RestfulAPIUtil.fetch( + `${baseUrl()}?status=${activityStatus.CERTIFIED}` + ); + }, + + fetchActivity: id => { + return RestfulAPIUtil.fetch(`${baseUrl()}/${id}/versions/latest`); + } +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesConstants.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesConstants.js new file mode 100644 index 00000000..f99789c2 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesConstants.js @@ -0,0 +1,24 @@ +/* +* 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. +*/ +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/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesReducer.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesReducer.js new file mode 100644 index 00000000..5c361401 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesReducer.js @@ -0,0 +1,26 @@ +/* +* 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 } from './activitiesConstants'; + +export default (state = [], action) => { + switch (action.type) { + case SET_ACTIVITIES_LIST: { + return action.payload; + } + default: + return state; + } +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSaga.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSaga.js new file mode 100644 index 00000000..2350b9c3 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSaga.js @@ -0,0 +1,41 @@ +/* +* Copyright © 2018 European Support Limited +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import { call, put, takeEvery, all } from 'redux-saga/effects'; +import { genericNetworkErrorAction } from 'src/appConstants'; +import { GET_ACTIVITIES } from './activitiesConstants'; +import activitiesApi from './activitiesApi'; +import { setActivitiesList } from './activitiesActions'; + +function* fetchActivities() { + try { + const activitiesList = yield call(activitiesApi.fetchActivities); + const updatedActivitiesList = yield all( + activitiesList.items.map(item => + call(activitiesApi.fetchActivity, item.id) + ) + ); + + yield put(setActivitiesList(updatedActivitiesList)); + } catch (error) { + yield put(genericNetworkErrorAction(error)); + } +} + +function* activitiesSaga() { + yield takeEvery(GET_ACTIVITIES, fetchActivities); +} + +export default activitiesSaga; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSelectors.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSelectors.js new file mode 100644 index 00000000..fc0c55ab --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/activities/activitiesSelectors.js @@ -0,0 +1,22 @@ +/* +* 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. +*/ + +export const activitiesSelector = state => + state && + state.activities.map(item => ({ + ...item, + value: item.name + })); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/Catalog.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/Catalog.js new file mode 100644 index 00000000..b675b220 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/Catalog.js @@ -0,0 +1,53 @@ +/* +* 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 { connect } from 'react-redux'; + +import CatalogView from 'features/catalog/CatalogView'; +import { + fetchWorkflow, + searchChangedAction +} from 'features/catalog/catalogActions'; + +import { showCustomModalAction } from 'shared/modal/modalWrapperActions'; +import { NEW_WORKFLOW_MODAL } from 'shared/modal/modalWrapperComponents'; +import { clearWorkflowAction } from 'features/workflow/workflowConstants'; + +const mapStateToProps = state => ({ + catalog: state.catalog +}); + +const mapDispatchToProps = dispatch => ({ + handleFetchWorkflow: ({ sort, offset, searchNameFilter, status }) => + dispatch(fetchWorkflow({ sort, offset, searchNameFilter, status })), + clearWorkflow: () => dispatch(clearWorkflowAction), + showNewWorkflowModal: () => + dispatch( + showCustomModalAction({ + customComponentName: NEW_WORKFLOW_MODAL, + title: 'New Workflow' + }) + ), + searchInputChanged: searchValue => + dispatch(searchChangedAction(searchValue)) +}); + +const Catalog = connect( + mapStateToProps, + mapDispatchToProps +)(CatalogView); + +export default Catalog; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/CatalogView.jsx b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/CatalogView.jsx new file mode 100644 index 00000000..edaa64f3 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/CatalogView.jsx @@ -0,0 +1,182 @@ +/* +* 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 React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import InfiniteScroll from 'shared/scroll/InfiniteScroll'; +import Workflows from 'features/catalog/views/Workflows'; +import AddWorkflow from 'features/catalog/views/AddWorkflow'; +import { WORKFLOW_STATUS } from 'features/workflow/workflowConstants'; + +import Header from 'features/catalog/views/Header'; +import Main from 'features/catalog/views/Main'; +import { NAME, ASC, DESC } from 'features/catalog/catalogConstants'; + +class CatalogView extends Component { + constructor(props) { + super(props); + } + + componentDidMount() { + const { clearWorkflow } = this.props; + clearWorkflow(); + this.fetchWorkflows(); + } + + fetchWorkflows = () => { + const { + catalog: { sort, status, searchNameFilter }, + handleFetchWorkflow + } = this.props; + handleFetchWorkflow({ + sort, + searchNameFilter, + status + }); + }; + + handleAlphabeticalOrderByClick = e => { + e.preventDefault(); + + const { + handleFetchWorkflow, + catalog: { sort, status, searchNameFilter } + } = this.props; + + const payload = { + ...sort + }; + + payload[NAME] = payload[NAME] === ASC ? DESC : ASC; + handleFetchWorkflow({ + sort: payload, + searchNameFilter, + status + }); + }; + handleStatusChange = value => { + const { + handleFetchWorkflow, + catalog: { sort, searchNameFilter } + } = this.props; + + handleFetchWorkflow({ + sort, + searchNameFilter, + status: value + }); + }; + + handleScroll = () => { + const { + catalog: { + paging: { offset }, + sort, + status, + searchNameFilter + }, + handleFetchWorkflow + } = this.props; + handleFetchWorkflow({ + sort, + offset, + searchNameFilter, + status + }); + }; + + goToOverviewPage = id => { + const { history } = this.props; + const { location } = history; + history.push(`${location.pathname}workflow/${id}/overview`); + }; + + searchChange = searchValue => { + this.setState({ searchValue: searchValue }); + this.dispatchChange(searchValue); + }; + + dispatchChange = searchValue => { + const { searchInputChanged, catalog } = this.props; + searchInputChanged({ + ...catalog, + searchNameFilter: searchValue + }); + sessionStorage.setItem('searchNameFilter', searchValue); + }; + + render() { + const { catalog, showNewWorkflowModal } = this.props; + const { + sort, + paging: { hasMore, total }, + items, + status, + searchNameFilter + } = catalog; + const alphabeticalOrder = sort[NAME]; + + return ( +
+
+ +
+
+ {status === WORKFLOW_STATUS.ACTIVE && ( + + )} + +
+
+
+
+ ); + } +} + +CatalogView.propTypes = { + history: PropTypes.object, + catalog: PropTypes.object, + handleResetWorkflow: PropTypes.func, + handleFetchWorkflow: PropTypes.func, + showNewWorkflowModal: PropTypes.func, + clearWorkflow: PropTypes.func, + searchInputChanged: PropTypes.func, + searchNameFilter: PropTypes.string +}; + +CatalogView.defaultProps = { + showNewWorkflowModal: () => {}, + clearWorkflow: () => {} +}; + +export default CatalogView; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogActions-test.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogActions-test.js new file mode 100644 index 00000000..bd2b0006 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogActions-test.js @@ -0,0 +1,65 @@ +/* +* 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. +*/ + +'use strict'; + +import { + FETCH_WORKFLOW, + UPDATE_WORKFLOW, + LIMIT, + NAME, + ASC +} from 'features/catalog/catalogConstants'; +import { WORKFLOW_STATUS } from 'features/workflow/workflowConstants'; +import { fetchWorkflow, updateWorkflow } from 'features/catalog/catalogActions'; + +describe('Catalog Actions', () => { + it('should have `fetchWorkflow` action', () => { + const sort = { [NAME]: ASC }; + const offset = 0; + const status = WORKFLOW_STATUS.ACTIVE; + expect(fetchWorkflow({ sort, offset, status })).toEqual({ + type: FETCH_WORKFLOW, + payload: { + sort, + limit: LIMIT, + status, + offset + } + }); + }); + + it('should have `updateWorkflow` action', () => { + const payload = { + paging: { + offset: 1, + limit: 1, + count: 1, + hasMore: false, + total: 2 + }, + items: [], + sort: { + name: 'asc' + } + }; + + expect(updateWorkflow(payload)).toEqual({ + type: UPDATE_WORKFLOW, + payload + }); + }); +}); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogReducer-test.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogReducer-test.js new file mode 100644 index 00000000..264e8112 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogReducer-test.js @@ -0,0 +1,112 @@ +/* +* 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. +*/ + +'use strict'; + +import { NAME, ASC, DESC } from 'features/catalog/catalogConstants'; +import catalogReducer, { initialState } from 'features/catalog/catalogReducer'; +import { updateWorkflow } from 'features/catalog/catalogActions'; +import { WORKFLOW_STATUS } from 'features/workflow/workflowConstants'; + +describe('Catalog Reducer', () => { + const state = { + paging: { + offset: 1, + limit: 1, + count: 1, + hasMore: false, + total: 2 + }, + status: WORKFLOW_STATUS.ACTIVE, + sort: { + [NAME]: ASC + }, + searchNameFilter: '', + items: [ + { + id: 'c5b7ca1a0f7944bfa948b85b32c5f314', + name: 'Workflow_2', + description: null, + versionStates: ['DRAFT'], + versions: null + }, + { + id: '221336ef3f1645c686bc81899368ac27', + name: 'Workflow_1', + description: null, + versionStates: ['DRAFT'], + versions: null + } + ] + }; + + const sort = { + [NAME]: DESC + }; + + const offset = 0; + + const dataPayload = { + paging: { + offset, + limit: 10, + count: 2, + hasMore: false, + total: 2 + }, + items: [ + { + id: 'c5b7ca1a0f7944bfa948b85b32c5f314', + name: 'Workflow_2', + description: null, + versionStates: ['DRAFT'], + versions: null + }, + { + id: '221336ef3f1645c686bc81899368ac27', + name: 'Workflow_1', + description: null, + versionStates: ['DRAFT'], + versions: null + } + ] + }; + + it('returns the initial state', () => { + expect(catalogReducer(undefined, {})).toEqual(initialState); + }); + + it('should replace results when page is first', () => { + expect( + catalogReducer(state, updateWorkflow({ sort, ...dataPayload })) + ).toEqual({ + ...initialState, + sort, + ...dataPayload + }); + }); + + it('should add results when page is not first', () => { + expect( + catalogReducer( + state, + updateWorkflow({ sort, ...{ ...dataPayload, offset: 2 } }) + ).items + ).toEqual( + expect.arrayContaining([...dataPayload.items, ...state.items]) + ); + }); +}); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogSagas-test.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogSagas-test.js new file mode 100644 index 00000000..d3e9bda2 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/__tests__/catalogSagas-test.js @@ -0,0 +1,109 @@ +/* +* 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. +*/ + +'use strict'; + +import { runSaga } from 'redux-saga'; +import { takeLatest } from 'redux-saga/effects'; + +import { + NAME, + DESC, + LIMIT, + SEARCH_CHANGED +} from 'features/catalog/catalogConstants'; +import { WORKFLOW_STATUS } from 'features/workflow/workflowConstants'; +import catalogApi from '../catalogApi'; +import { fetchWorkflow, updateWorkflow } from 'features/catalog/catalogActions'; +import catalogSaga, { + fetchWorkflowSaga, + debounceSearchChanged +} from 'features/catalog/catalogSagas'; + +jest.mock('../catalogApi'); + +describe('Catalog Sagas', () => { + it('should watch for `fetchWorkflow` action', () => { + const gen = catalogSaga(); + + expect(gen.next().value).toEqual( + takeLatest(fetchWorkflow, fetchWorkflowSaga) + ); + expect(gen.next().value).toEqual( + takeLatest(SEARCH_CHANGED, debounceSearchChanged) + ); + expect(gen.next().done).toBe(true); + }); + + it('should get workflows and put `updateWorkflow` action', async () => { + const sort = { + [NAME]: DESC + }; + const status = WORKFLOW_STATUS.ACTIVE; + const offset = 0; + const searchNameFilter = undefined; + const data = { + paging: { + offset, + limit: 10, + count: 2, + hasMore: false, + total: 2 + }, + status: WORKFLOW_STATUS.ACTIVE, + searchNameFilter: 'w', + items: [ + { + id: 'c5b7ca1a0f7944bfa948b85b32c5f314', + name: 'Workflow_2', + description: null, + versionStates: ['DRAFT'], + versions: null + }, + { + id: '221336ef3f1645c686bc81899368ac27', + name: 'Workflow_1', + description: null, + versionStates: ['DRAFT'], + versions: null + } + ] + }; + const dispatched = []; + + catalogApi.getWorkflows.mockReturnValue(data); + + await runSaga( + { + dispatch: action => dispatched.push(action) + }, + fetchWorkflowSaga, + fetchWorkflow({ sort, offset, status }) + ).done; + + expect(dispatched).toEqual( + expect.arrayContaining([updateWorkflow({ sort, ...data })]) + ); + + expect(catalogApi.getWorkflows).toBeCalledWith({ + sort, + status, + limit: LIMIT, + offset: offset + LIMIT, + searchNameFilter + }); + }); +}); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogActions.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogActions.js new file mode 100644 index 00000000..81c22848 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogActions.js @@ -0,0 +1,48 @@ +/* +* 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 { createActions, createAction } from 'redux-actions'; + +import { + NAMESPACE, + LIMIT, + SEARCH_CHANGED, + FETCH_WORKFLOW +} from 'features/catalog/catalogConstants'; + +export const { + [NAMESPACE]: { updateWorkflow } +} = createActions({ + [NAMESPACE]: { + UPDATE_WORKFLOW: undefined + } +}); + +export const fetchWorkflow = createAction( + FETCH_WORKFLOW, + ({ sort, offset, searchNameFilter, status }) => ({ + sort, + limit: LIMIT, + offset, + searchNameFilter, + status + }) +); + +export const searchChangedAction = createAction( + SEARCH_CHANGED, + payload => payload +); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogApi.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogApi.js new file mode 100644 index 00000000..b15f3d8e --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogApi.js @@ -0,0 +1,45 @@ +/* +* 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 qs from 'qs'; + +import RestfulAPIUtil from 'services/restAPIUtil'; +import Configuration from 'config/Configuration.js'; + +function baseUrl() { + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/workflows`; +} + +const Api = { + getWorkflows: ({ sort, limit, offset, searchNameFilter, status }) => { + const queryParams = { + sort: Object.keys(sort).map(key => `${key}:${sort[key]}`), + limit, + offset, + archiving: status + }; + if (searchNameFilter) queryParams.searchNameFilter = searchNameFilter; + const queryString = qs.stringify(queryParams, { + indices: false, + addQueryPrefix: true + }); + + return RestfulAPIUtil.fetch(`${baseUrl()}${queryString}`); + } +}; + +export default Api; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogConstants.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogConstants.js new file mode 100644 index 00000000..44bdc6bb --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogConstants.js @@ -0,0 +1,31 @@ +/* +* 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. +*/ + +export const NAMESPACE = 'catalog'; + +export const NAME = 'name'; +export const ASC = 'asc'; +export const DESC = 'desc'; + +//Limit = max tiles in a standard screen +export const LIMIT = 31; + +export const SEARCH_BUFFER = 1000; +export const SEARCH_CHANGED = `catalog/SEARCH_CHANGED`; + +export const FETCH_WORKFLOW = `${NAMESPACE}/FETCH_WORKFLOW`; +export const UPDATE_WORKFLOW = `${NAMESPACE}/UPDATE_WORKFLOW`; +export const RESET_WORKFLOW = `${NAMESPACE}/RESET_WORKFLOW`; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogReducer.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogReducer.js new file mode 100644 index 00000000..db7bc43b --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogReducer.js @@ -0,0 +1,60 @@ +/* +* 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 { + NAME, + ASC, + UPDATE_WORKFLOW, + SEARCH_CHANGED +} from 'features/catalog/catalogConstants'; +import { WORKFLOW_STATUS } from 'features/workflow/workflowConstants'; +export const initialState = { + paging: { + hasMore: true, + total: 0 + }, + sort: { + [NAME]: ASC + }, + status: WORKFLOW_STATUS.ACTIVE, + //In order to save state inside iframe session + searchNameFilter: sessionStorage.getItem('searchNameFilter') || '' +}; + +const catalogReducer = (state = initialState, action) => { + const { type, payload } = action; + + switch (type) { + case UPDATE_WORKFLOW: + return { + ...state, + ...payload, + items: + payload.paging.offset === 0 + ? [...payload.items] + : [...state.items, ...payload.items] + }; + case SEARCH_CHANGED: + return { + ...state, + searchNameFilter: action.payload.searchNameFilter + }; + default: + return state; + } +}; + +export default catalogReducer; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogSagas.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogSagas.js new file mode 100644 index 00000000..dd77bc97 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/catalogSagas.js @@ -0,0 +1,56 @@ +/* +* 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, takeLatest } from 'redux-saga/effects'; +import { delay } from 'redux-saga'; + +import catalogApi from 'features/catalog/catalogApi'; +import { fetchWorkflow, updateWorkflow } from 'features/catalog/catalogActions'; +import { + SEARCH_CHANGED, + LIMIT, + SEARCH_BUFFER +} from 'features/catalog/catalogConstants'; + +const noOp = () => {}; + +export function* fetchWorkflowSaga({ payload }) { + const { sort, limit, offset, searchNameFilter, status } = payload; + try { + const data = yield call(catalogApi.getWorkflows, { + sort, + limit: LIMIT, + offset: offset === undefined ? 0 : offset + limit, + searchNameFilter, + status + }); + yield put(updateWorkflow({ sort, status, ...data })); + } catch (e) { + noOp(); + } +} + +export function* debounceSearchChanged({ payload }) { + yield call(delay, SEARCH_BUFFER); + yield call(fetchWorkflowSaga, { payload }); +} + +function* catalogSaga() { + yield takeLatest(fetchWorkflow, fetchWorkflowSaga); + yield takeLatest(SEARCH_CHANGED, debounceSearchChanged); +} + +export default catalogSaga; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/AddWorkflow.jsx b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/AddWorkflow.jsx new file mode 100644 index 00000000..1700d92e --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/AddWorkflow.jsx @@ -0,0 +1,45 @@ +/* +* 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 React from 'react'; +import PropTypes from 'prop-types'; +import { Translate } from 'react-redux-i18n'; +import { SVGIcon } from 'onap-ui-react'; + +class AddWorkflow extends React.Component { + render() { + const { onClick } = this.props; + return ( +
+
+ +
+
+ +
+
+ ); + } +} + +AddWorkflow.propTypes = { + onClick: PropTypes.func +}; + +export default AddWorkflow; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Header.jsx b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Header.jsx new file mode 100644 index 00000000..b70c0a50 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Header.jsx @@ -0,0 +1,46 @@ +/* +* 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 React from 'react'; +import PropTypes from 'prop-types'; +import SearchInput from 'shared/searchInput/SearchInput'; +import StatusSelect from './StatusSelector'; + +const Header = ({ searchChange, searchValue, statusChange, status }) => ( +
+ +
+ +
+
+); + +Header.propTypes = { + searchChange: PropTypes.func, + searchValue: PropTypes.string, + statusChange: PropTypes.func, + status: PropTypes.string +}; + +Header.defaultProps = { + searchChange: () => {}, + searchValue: '' +}; +export default Header; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Main.jsx b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Main.jsx new file mode 100644 index 00000000..b4288f3b --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Main.jsx @@ -0,0 +1,79 @@ +/* +* 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 React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { Translate } from 'react-redux-i18n'; + +import { ASC } from 'features/catalog/catalogConstants'; +import { SVGIcon } from 'onap-ui-react'; + +class Main extends Component { + render() { + const { + total, + alphabeticalOrder, + onAlphabeticalOrderByClick, + children + } = this.props; + + return ( +
+
+
+ +
+
+
+ : +
+
+
+ +
+
+ +
+
+
+
+ {children} +
+ ); + } +} + +Main.propTypes = { + total: PropTypes.number, + alphabeticalOrder: PropTypes.string, + onAlphabeticalOrderByClick: PropTypes.func, + handleSort: PropTypes.func, + children: PropTypes.node +}; + +Main.defaultProps = { + total: 0 +}; + +export default Main; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/StatusSelector.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/StatusSelector.js new file mode 100644 index 00000000..5b77bd5d --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/StatusSelector.js @@ -0,0 +1,24 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { WORKFLOW_STATUS } from 'features/workflow/workflowConstants'; + +const StatusSelect = ({ status, onChange }) => ( + +); + +StatusSelect.propTypes = { + status: PropTypes.string, + onChange: PropTypes.func +}; + +export default StatusSelect; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Workflows.jsx b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Workflows.jsx new file mode 100644 index 00000000..d69ec47e --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/catalog/views/Workflows.jsx @@ -0,0 +1,47 @@ +/* +* 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 React from 'react'; +import PropTypes from 'prop-types'; + +import { Tile, TileInfo, TileInfoLine } from 'onap-ui-react'; + +const Workflows = ({ items, onWorkflowClick }) => + items.map((workflow, index) => ( + onWorkflowClick(workflow.id)}> + + {workflow.name} + + + )); + +Workflows.propTypes = { + items: PropTypes.array, + onWorkflowClick: PropTypes.func +}; + +Workflows.defaultProps = { + items: [] +}; + +export default Workflows; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/Version.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/Version.js new file mode 100644 index 00000000..5df68759 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/Version.js @@ -0,0 +1,19 @@ +import { connect } from 'react-redux'; +import VersionView from 'features/version/VersionView'; +import { workflowVersionFetchRequestedAction } from 'features/version/versionConstants'; + +const mapStateToProps = ({ currentVersion: { operationMode } }) => { + return { + operationMode + }; +}; + +const mapDispatchToProps = dispatch => ({ + loadSelectedVersion: payload => + dispatch(workflowVersionFetchRequestedAction(payload)) +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(VersionView); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/VersionView.jsx b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/VersionView.jsx new file mode 100644 index 00000000..48c671e2 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/VersionView.jsx @@ -0,0 +1,127 @@ +/* +* 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 React from 'react'; +import PropTypes from 'prop-types'; +import { Route, matchPath } from 'react-router-dom'; +import { I18n } from 'react-redux-i18n'; + +import NavigationSideBar from 'shared/navigationSideBar/index'; +import VersionController from 'features/version/versionController/VersionController'; + +class VersionView extends React.Component { + componentDidMount() { + const { loadSelectedVersion, match } = this.props; + const workflowId = match.params.workflowId; + const versionId = match.params.versionId; + loadSelectedVersion({ workflowId, versionId }); + } + + onSelect = item => { + const { history, match } = this.props; + + if (!item.disabled) { + history.push( + item.path === '/' ? match.url : `${match.url}${item.path}` + ); + } + }; + + getGroups = () => { + const { routes } = this.props; + + const items = routes.map(route => { + return route.i18nName + ? { + ...route, + name: I18n.t(route.i18nName) + } + : route; + }); + + return [ + { + id: 'WORKFLOW', + items + } + ]; + }; + + getActiveItemIdProps = () => { + const { location, routes, match } = this.props; + + const activeItem = routes.find(route => + matchPath(location.pathname, { + path: `${match.path}${route.path}`, + exact: true, + strict: false + }) + ); + + return activeItem && activeItem.id; + }; + + render() { + const { match, routes, history, operationMode } = this.props; + + const groups = this.getGroups(); + const activeItemId = this.getActiveItemIdProps(); + + return ( +
+ + +
+ {!operationMode && ( +
+ +
+ )} + {routes.map((route, i) => ( + + ))} +
+
+ ); + } +} + +VersionView.propTypes = { + history: PropTypes.object, + location: PropTypes.object, + match: PropTypes.object, + routes: PropTypes.array, + loadSelectedVersion: PropTypes.func, + operationMode: PropTypes.bool +}; + +export default VersionView; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/Composition.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/Composition.js new file mode 100644 index 00000000..97697c70 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/Composition.js @@ -0,0 +1,62 @@ +/* +* 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 { connect } from 'react-redux'; +import { I18n } from 'react-redux-i18n'; +import { updateComposition, updateValidation } from './compositionActions'; +import CompositionView from './CompositionView'; +import { showErrorModalAction } from '../../../shared/modal/modalWrapperActions'; +import { getComposition, getErrors } from './compositionSelectors'; +import { getWorkflowName } from '../../workflow/workflowSelectors'; +import { activitiesSelector } from 'features/activities/activitiesSelectors'; +import { getInputOutputForComposition } from 'features/version/inputOutput/inputOutputSelectors'; +import { getVersionInfo } from 'features/version/general/generalSelectors'; +import { getIsCertified } from 'features/version/general/generalSelectors'; +import { isWorkflowArchive } from 'features/workflow/workflowSelectors'; + +function mapStateToProps(state) { + return { + composition: getComposition(state), + name: getWorkflowName(state), + versionName: getVersionInfo(state).name, + activities: activitiesSelector(state), + inputOutput: getInputOutputForComposition(state), + errors: getErrors(state), + isReadOnly: getIsCertified(state) || isWorkflowArchive(state) + }; +} + +function mapDispatchToProps(dispatch) { + return { + compositionUpdate: composition => + dispatch(updateComposition(composition)), + showErrorModal: msg => + dispatch( + showErrorModalAction({ + title: I18n.t('workflow.composition.bpmnError'), + body: msg, + withButtons: true, + closeButtonText: I18n.t('buttons.okBtn') + }) + ), + validationUpdate: (element, isValid) => + dispatch(updateValidation({ element, isValid })) + }; +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(CompositionView); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionUpdate.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionUpdate.js new file mode 100644 index 00000000..e5756eb5 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionUpdate.js @@ -0,0 +1,131 @@ +/* +* 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 React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { I18n } from 'react-redux-i18n'; + +import CustomModeler from 'features/version/composition/custom-modeler'; +import camundaModuleDescriptor from 'features/version/composition/custom-properties-provider/descriptors/camunda'; +import { setElementInputsOutputs } from 'features/version/composition/bpmnUtils.js'; + +import { connect } from 'react-redux'; +import { updateComposition } from 'features/version/composition/compositionActions'; +import { showErrorModalAction } from 'shared/modal/modalWrapperActions'; +import { getComposition } from 'features/version/composition/compositionSelectors'; +import { getWorkflowName } from 'features/workflow/workflowSelectors'; +import { activitiesSelector } from 'features/activities/activitiesSelectors'; +import { getInputOutputForComposition } from 'features/version/inputOutput/inputOutputSelectors'; + +class CompositionUpdate extends Component { + static propTypes = { + compositionUpdate: PropTypes.func, + showErrorModal: PropTypes.func, + composition: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), + inputOutput: PropTypes.object, + activities: PropTypes.object, + certifyBack: PropTypes.func + }; + + constructor(props) { + super(props); + this.generatedId = 'bpmn-container' + Date.now(); + this.fileInput = React.createRef(); + this.bpmnContainer = React.createRef(); + } + + componentDidMount() { + const { composition, activities, inputOutput } = this.props; + + this.modeler = new CustomModeler({ + moddleExtensions: { + camunda: camundaModuleDescriptor + }, + workflow: { + activities: activities, + workflowInputOutput: inputOutput + } + }); + + this.setDiagramToBPMN(composition); + } + + setDiagramToBPMN = diagram => { + let modeler = this.modeler; + this.modeler.importXML(diagram, err => { + if (err) { + return this.props.showErrorModal( + I18n.t('workflow.composition.importErrorMsg') + ); + } + const canvas = modeler.get('canvas'); + const { businessObject } = canvas._rootElement; + + setElementInputsOutputs( + businessObject, + this.props.inputOutput, + this.modeler.get('moddle') + ); + + this.exportDiagramToStore(); + }); + }; + + exportDiagramToStore = () => { + this.modeler.saveXML({ format: true }, (err, xml) => { + if (err) { + return this.props.showErrorModal( + I18n.t('workflow.composition.saveErrorMsg') + ); + } + this.props.compositionUpdate(xml); + this.props.certifyBack(); + }); + }; + + render() { + return
; + } +} + +function mapStateToProps(state) { + return { + composition: getComposition(state), + name: getWorkflowName(state), + activities: activitiesSelector(state), + inputOutput: getInputOutputForComposition(state) + }; +} + +function mapDispatchToProps(dispatch) { + return { + compositionUpdate: composition => + dispatch(updateComposition(composition)), + showErrorModal: msg => + dispatch( + showErrorModalAction({ + title: I18n.t('workflow.composition.bpmnError'), + body: msg, + withButtons: true, + closeButtonText: I18n.t('buttons.okBtn') + }) + ) + }; +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(CompositionUpdate); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js new file mode 100644 index 00000000..e444d98c --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/CompositionView.js @@ -0,0 +1,284 @@ +/* +* 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 React, { Component } from 'react'; +import fileSaver from 'file-saver'; +import isEqual from 'lodash.isequal'; +import PropTypes from 'prop-types'; +import propertiesPanelModule from 'bpmn-js-properties-panel'; +import { I18n } from 'react-redux-i18n'; + +import CustomModeler from './custom-modeler'; +import propertiesProviderModule from './custom-properties-provider/provider/camunda'; +import camundaModuleDescriptor from './custom-properties-provider/descriptors/camunda'; +import newDiagramXML from './newDiagram.bpmn'; +import CompositionButtons from './components/CompositionButtonsPanel'; +import { setElementInputsOutputs } from './bpmnUtils.js'; +import { + PROCESS_DEFAULT_ID, + COMPOSITION_ERROR_COLOR, + COMPOSITION_VALID_COLOR, + CAMUNDA_PANEL_INPUTS_NAMES +} from './compositionConstants'; +import readOnly from './readOnly'; + +function setStatusToElement(type, status, parent) { + let elements = parent.getElementsByTagName(type); + for (let item of elements) { + if (item.name !== 'selectedExtensionElement') { + item.readOnly = status; + item.disabled = status; + } + } +} + +function disablePanelInputs(status) { + let panel = document.getElementById('js-properties-panel'); + + if (panel) { + setStatusToElement('input', status, panel); + setStatusToElement('button', status, panel); + setStatusToElement('select', status, panel); + + //distinguish editable and clickable fields using attr and style + CAMUNDA_PANEL_INPUTS_NAMES.map(name => { + const div = document.getElementById(name); + if (div) { + div.setAttribute('editable-readonly', !status); + } + }); + } +} +class CompositionView extends Component { + static propTypes = { + compositionUpdate: PropTypes.func, + showErrorModal: PropTypes.func, + composition: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), + name: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), + versionName: PropTypes.string, + inputOutput: PropTypes.object, + activities: PropTypes.array, + validationUpdate: PropTypes.func, + errors: PropTypes.array, + isReadOnly: PropTypes.bool + }; + + constructor(props) { + super(props); + this.generatedId = 'bpmn-container' + Date.now(); + this.fileInput = React.createRef(); + this.bpmnContainer = React.createRef(); + this.versionChanged = false; + } + componentDidUpdate(prevProps) { + const { errors, isReadOnly, versionName, composition } = this.props; + if (!isEqual(prevProps.errors, errors)) { + errors.map(item => { + this.modeling.setColor([item.element], { + fill: item.isValid + ? COMPOSITION_VALID_COLOR + : COMPOSITION_ERROR_COLOR + }); + }); + } + if (prevProps.isReadOnly !== isReadOnly) { + this.modeler.get('readOnly').readOnly(isReadOnly); + disablePanelInputs(isReadOnly); + } + + if (prevProps.versionName !== versionName) { + this.versionChanged = true; + } + if ( + !isEqual(prevProps.composition, composition) && + this.versionChanged + ) { + this.setDiagramToBPMN(composition); + this.versionChanged = false; + } + } + componentDidMount() { + const { + composition, + activities, + inputOutput, + validationUpdate, + isReadOnly + } = this.props; + + const readOnlyModule = { + __init__: ['readOnly'], + readOnly: ['type', readOnly] + }; + this.modeler = new CustomModeler({ + propertiesPanel: { + parent: '#js-properties-panel' + }, + additionalModules: [ + propertiesPanelModule, + propertiesProviderModule, + readOnlyModule + ], + moddleExtensions: { + camunda: camundaModuleDescriptor + }, + workflow: { + activities: activities, + getActivityInputsOutputs: this.getActivityInputsOutputs, + workflowInputOutput: inputOutput, + validationUpdate: validationUpdate + } + }); + + this.modeler.attachTo('#' + this.generatedId); + this.setDiagramToBPMN(composition); + this.modeler.on('element.out', () => this.exportDiagramToStore()); + this.modeler.on('element.click', this.handleCompositionStatus); + this.modeler.on( + 'propertiesPanel.changed', + this.handleCompositionStatus + ); + this.modeling = this.modeler.get('modeling'); + this.modeler.get('readOnly').readOnly(isReadOnly); + } + handleCompositionStatus = () => { + disablePanelInputs(this.props.isReadOnly); + }; + getActivityInputsOutputs = selectedValue => { + const selectedActivity = this.props.activities.find( + el => el.name === selectedValue + ); + + if (selectedActivity) { + const inputsOutputs = { + inputs: selectedActivity.inputs, + outputs: selectedActivity.outputs + }; + return inputsOutputs; + } else return { inputs: [], outputs: [] }; + }; + + setDiagramToBPMN = diagram => { + let modeler = this.modeler; + this.modeler.importXML(diagram, err => { + if (err) { + return this.props.showErrorModal( + I18n.t('workflow.composition.importErrorMsg') + ); + } + const canvas = modeler.get('canvas'); + canvas.zoom('fit-viewport'); + const { businessObject } = canvas._rootElement; + + this.setDefaultIdAndName(businessObject); + setElementInputsOutputs( + businessObject, + this.props.inputOutput, + this.modeler.get('moddle') + ); + disablePanelInputs(this.props.isReadOnly); + }); + }; + setDefaultIdAndName = businessObject => { + const { name = '' } = this.props; + if (!businessObject.name) { + businessObject.name = name; + } + + if (businessObject.id === PROCESS_DEFAULT_ID || !businessObject.id) { + businessObject.id = name.toLowerCase().replace(/\s/g, '_'); + } + }; + exportDiagramToStore = () => { + this.modeler.saveXML({ format: true }, (err, xml) => { + if (err) { + return this.props.showErrorModal( + I18n.t('workflow.composition.saveErrorMsg') + ); + } + return this.props.compositionUpdate(xml); + }); + }; + + exportDiagram = () => { + const { name, showErrorModal, versionName } = this.props; + this.modeler.saveXML({ format: true }, (err, xml) => { + if (err) { + return showErrorModal( + I18n.t('workflow.composition.exportErrorMsg') + ); + } + const blob = new Blob([xml], { type: 'text/html;charset=utf-8' }); + fileSaver.saveAs( + blob, + `${name.replace(/\s/g, '').toLowerCase()}-${versionName}.bpmn` + ); + }); + }; + + loadNewDiagram = () => { + this.setDiagramToBPMN(newDiagramXML); + }; + + uploadDiagram = () => { + this.fileInput.current.click(); + }; + + handleFileInputChange = filesList => { + const file = filesList[0]; + const reader = new FileReader(); + reader.onloadend = event => { + var xml = event.target.result; + this.setDiagramToBPMN(xml); + this.fileInput.value = ''; + }; + reader.readAsText(file); + }; + + render() { + return ( +
+ this.handleFileInputChange(e.target.files)} + id="file-input" + accept=".bpmn, .xml" + type="file" + name="file-input" + style={{ display: 'none' }} + /> +
+
+
+ +
+
+ ); + } +} + +export default CompositionView; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/bpmnUtils.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/bpmnUtils.js new file mode 100644 index 00000000..ada2bdc4 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/bpmnUtils.js @@ -0,0 +1,93 @@ +/* +* 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, parent) { + return inputData.map(item => { + const existingInput = existingArray.find(el => el.name === item.name); + const updatedElement = moddle.create( + type, + existingInput ? { ...item, value: existingInput.value } : item + ); + updatedElement.$parent = parent; + return updatedElement; + }); +} + +export function setElementInputsOutputs( + businessObject, + inputOutput, + moddle, + cleanInputsOutpus +) { + const { inputs = [], outputs = [] } = inputOutput; + + if (!businessObject.extensionElements) { + businessObject.extensionElements = moddle.create( + bpmnElementsTypes.EXTENSION_ElEMENTS + ); + businessObject.extensionElements.$parent = businessObject.id; + } + + const existingInputOutput = getExtension( + businessObject, + bpmnElementsTypes.INPUT_OUTPUT + ); + + const processInputs = updatedData( + moddle, + inputs, + cleanInputsOutpus + ? [] + : (existingInputOutput && existingInputOutput.inputParameters) || + [], + bpmnElementsTypes.INPUT_PARAMETER, + businessObject.id + ); + + const processOutputs = updatedData( + moddle, + outputs, + cleanInputsOutpus + ? [] + : (existingInputOutput && existingInputOutput.outputParameters) || + [], + bpmnElementsTypes.OUTPUT_PARAMETER, + businessObject.id + ); + + const processInputOutput = moddle.create(bpmnElementsTypes.INPUT_OUTPUT); + processInputOutput.$parent = businessObject.id; + processInputOutput.inputParameters = [...processInputs]; + processInputOutput.outputParameters = [...processOutputs]; + + const extensionElements = businessObject.extensionElements.get('values'); + businessObject.extensionElements.set( + 'values', + extensionElements + .filter(item => item.$type !== bpmnElementsTypes.INPUT_OUTPUT) + .concat(processInputOutput) + ); +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/components/CompositionButton.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/components/CompositionButton.js new file mode 100644 index 00000000..62500d25 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/components/CompositionButton.js @@ -0,0 +1,36 @@ +/* +* 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 React from 'react'; +import PropTypes from 'prop-types'; +import { SVGIcon } from 'onap-ui-react'; + +const CompositionButton = ({ onClick, name, title, disabled }) => ( +
{} : onClick} + className={`diagram-btn ${disabled ? 'disabled' : ''}`}> + +
+); + +CompositionButton.propTypes = { + onClick: PropTypes.func, + className: PropTypes.string, + name: PropTypes.string, + title: PropTypes.string, + disabled: PropTypes.bool +}; + +export default CompositionButton; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/components/CompositionButtonsPanel.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/components/CompositionButtonsPanel.js new file mode 100644 index 00000000..0292fd4e --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/components/CompositionButtonsPanel.js @@ -0,0 +1,56 @@ +/* +* 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 React from 'react'; +import PropTypes from 'prop-types'; +import CompositionButton from './CompositionButton'; + +const Divider = () =>
; + +const CompositionButtons = ({ onClean, onUpload, onDownload, isReadOnly }) => ( +
+ + + + + + +
+); + +CompositionButtons.propTypes = { + onClean: PropTypes.func, + onUpload: PropTypes.func, + onDownload: PropTypes.func, + isReadOnly: PropTypes.bool +}; +export default CompositionButtons; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionActions.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionActions.js new file mode 100644 index 00000000..fe74ba0d --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionActions.js @@ -0,0 +1,34 @@ +/* +* 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_COMPOSITION, + UPDATE_ERRORS, + DELETE_COMPOSITION +} from './compositionConstants'; + +export const updateComposition = payload => ({ + type: SET_COMPOSITION, + payload +}); + +export const deleteCompositionArtifact = () => ({ + type: DELETE_COMPOSITION +}); + +export const updateValidation = payload => ({ + type: UPDATE_ERRORS, + payload +}); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionConstants.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionConstants.js new file mode 100644 index 00000000..1db40210 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionConstants.js @@ -0,0 +1,38 @@ +/* +* 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. +*/ +export const SET_COMPOSITION = 'composition/SET_COMPOSITION'; +export const DELETE_COMPOSITION = 'composition/DELETE_COMPOSITION'; +export const UPDATE_ERRORS = 'composition/UPDATE_ERRORS'; + +export const bpmnElementsTypes = { + EXTENSION_ElEMENTS: 'bpmn:ExtensionElements', + INPUT_OUTPUT: 'camunda:InputOutput', + INPUT_PARAMETER: 'camunda:InputParameter', + OUTPUT_PARAMETER: 'camunda:OutputParameter' +}; + +export const PROCESS_DEFAULT_ID = 'Process_1'; + +export const COMPOSITION_ERROR_COLOR = '#f0c2c2'; +export const COMPOSITION_VALID_COLOR = 'white'; + +//list of field ids (contenteditable) that has separate treatment +export const CAMUNDA_PANEL_INPUTS_NAMES = [ + 'camunda-parameterType-text', + 'camunda-documentation', + 'camunda-name', + 'camunda-listener-field-value' +]; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionReducer.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionReducer.js new file mode 100644 index 00000000..9deb9cbd --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionReducer.js @@ -0,0 +1,44 @@ +/* +* 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_COMPOSITION, DELETE_COMPOSITION } from './compositionConstants'; +import { UPDATE_ERRORS } from './compositionConstants'; +import newDiagramXML from './newDiagram.bpmn'; + +export default (state = { diagram: newDiagramXML, errors: [] }, action) => { + switch (action.type) { + case SET_COMPOSITION: + return { + ...state, + diagram: action.payload + }; + case DELETE_COMPOSITION: + return { + ...state, + diagram: newDiagramXML + }; + case UPDATE_ERRORS: { + const filteredErrors = state.errors.filter( + item => item.element.id !== action.payload.element.id + ); + return { + ...state, + errors: [...filteredErrors, action.payload] + }; + } + default: + return state; + } +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionSelectors.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionSelectors.js new file mode 100644 index 00000000..e6b51f1a --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/compositionSelectors.js @@ -0,0 +1,32 @@ +/* +* 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. +*/ +export const getComposition = state => + state && state.currentVersion && state.currentVersion.composition.diagram; + +export const getCompositionHasErrors = state => + state && + state.currentVersion && + state.currentVersion.composition && + state.currentVersion.composition.errors && + Boolean( + state.currentVersion.composition.errors.find(item => !item.isValid) + ); + +export const getErrors = state => + state && + state.currentVersion && + state.currentVersion.composition && + state.currentVersion.composition.errors; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomContextPadProvider.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomContextPadProvider.js new file mode 100644 index 00000000..0f2ba528 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomContextPadProvider.js @@ -0,0 +1,43 @@ +import inherits from 'inherits'; + +import ContextPadProvider from 'bpmn-js/lib/features/context-pad/ContextPadProvider'; + +import { isAny } from 'bpmn-js/lib/features/modeling/util/ModelingUtil'; + +import { assign, bind } from 'min-dash'; + +export default function CustomContextPadProvider(injector, connect, translate) { + injector.invoke(ContextPadProvider, this); + + var cached = bind(this.getContextPadEntries, this); + + this.getContextPadEntries = function(element) { + var actions = cached(element); + + var businessObject = element.businessObject; + + function startConnect(event, element, autoActivate) { + connect.start(event, element, autoActivate); + } + + if (isAny(businessObject, ['custom:triangle', 'custom:circle'])) { + assign(actions, { + connect: { + group: 'connect', + className: 'bpmn-icon-connection-multi', + title: translate('Connect using custom connection'), + action: { + click: startConnect, + dragstart: startConnect + } + } + }); + } + + return actions; + }; +} + +inherits(CustomContextPadProvider, ContextPadProvider); + +CustomContextPadProvider.$inject = ['injector', 'connect', 'translate']; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomElementFactory.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomElementFactory.js new file mode 100644 index 00000000..01d4d278 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomElementFactory.js @@ -0,0 +1,101 @@ +import { assign } from 'min-dash'; + +import inherits from 'inherits'; + +import BpmnElementFactory from 'bpmn-js/lib/features/modeling/ElementFactory'; +import { DEFAULT_LABEL_SIZE } from 'bpmn-js/lib/util/LabelUtil'; + +/** + * A custom factory that knows how to create BPMN _and_ custom elements. + */ +export default function CustomElementFactory(bpmnFactory, moddle) { + BpmnElementFactory.call(this, bpmnFactory, moddle); + + var self = this; + + /** + * Create a diagram-js element with the given type (any of shape, connection, label). + * + * @param {String} elementType + * @param {Object} attrs + * + * @return {djs.model.Base} + */ + this.create = function(elementType, attrs) { + var type = attrs.type; + + if (elementType === 'label') { + return self.baseCreate( + elementType, + assign({ type: 'label' }, DEFAULT_LABEL_SIZE, attrs) + ); + } + + // add type to businessObject if custom + if (/^custom:/.test(type)) { + if (!attrs.businessObject) { + attrs.businessObject = { + type: type + }; + + if (attrs.id) { + assign(attrs.businessObject, { + id: attrs.id + }); + } + } + + // add width and height if shape + if (!/:connection$/.test(type)) { + assign(attrs, self._getCustomElementSize(type)); + } + + if (!('$instanceOf' in attrs.businessObject)) { + // ensure we can use ModelUtil#is for type checks + Object.defineProperty(attrs.businessObject, '$instanceOf', { + value: function(type) { + return this.type === type; + } + }); + } + + return self.baseCreate(elementType, attrs); + } + + return self.createBpmnElement(elementType, attrs); + }; +} + +inherits(CustomElementFactory, BpmnElementFactory); + +CustomElementFactory.$inject = ['bpmnFactory', 'moddle']; + +/** + * Returns the default size of custom shapes. + * + * The following example shows an interface on how + * to setup the custom shapes's dimensions. + * + * @example + * + * var shapes = { + * triangle: { width: 40, height: 40 }, + * rectangle: { width: 100, height: 20 } + * }; + * + * return shapes[type]; + * + * + * @param {String} type + * + * @return {Dimensions} a {width, height} object representing the size of the element + */ +CustomElementFactory.prototype._getCustomElementSize = function(type) { + var shapes = { + __default: { width: 100, height: 80 }, + 'custom:triangle': { width: 40, height: 40 }, + 'custom:circle': { width: 140, height: 140 } + }; + + return shapes[type] || shapes.__default; +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomPalette.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomPalette.js new file mode 100644 index 00000000..a8adb2fd --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomPalette.js @@ -0,0 +1,151 @@ +import { assign } from 'min-dash'; + +/** + * A palette that allows you to create BPMN _and_ custom elements. + */ +export default function PaletteProvider( + palette, + create, + elementFactory, + spaceTool, + lassoTool, + handTool, + globalConnect, + translate +) { + this._create = create; + this._elementFactory = elementFactory; + this._spaceTool = spaceTool; + this._lassoTool = lassoTool; + this._handTool = handTool; + this._globalConnect = globalConnect; + this._translate = translate; + + palette.registerProvider(this); +} + +PaletteProvider.$inject = [ + 'palette', + 'create', + 'elementFactory', + 'spaceTool', + 'lassoTool', + 'handTool', + 'globalConnect', + 'translate' +]; + +PaletteProvider.prototype.getPaletteEntries = function() { + var actions = {}, + create = this._create, + elementFactory = this._elementFactory, + spaceTool = this._spaceTool, + lassoTool = this._lassoTool, + handTool = this._handTool, + globalConnect = this._globalConnect, + translate = this._translate; + + function createAction(type, group, className, title, options) { + function createListener(event) { + var shape = elementFactory.createShape( + assign({ type: type }, options) + ); + + if (options) { + shape.businessObject.di.isExpanded = options.isExpanded; + } + + create.start(event, shape); + } + + var shortType = type.replace(/^bpmn:/, ''); + + return { + group: group, + className: className, + title: title || 'Create ' + shortType, + action: { + dragstart: createListener, + click: createListener + } + }; + } + + assign(actions, { + 'hand-tool': { + group: 'tools', + className: 'bpmn-icon-hand-tool', + title: translate('Activate the hand tool'), + action: { + click: function(event) { + handTool.activateHand(event); + } + } + }, + 'lasso-tool': { + group: 'tools', + className: 'bpmn-icon-lasso-tool', + title: translate('Activate the lasso tool'), + action: { + click: function(event) { + lassoTool.activateSelection(event); + } + } + }, + 'space-tool': { + group: 'tools', + className: 'bpmn-icon-space-tool', + title: translate('Activate the create/remove space tool'), + action: { + click: function(event) { + spaceTool.activateSelection(event); + } + } + }, + 'global-connect-tool': { + group: 'tools', + className: 'bpmn-icon-connection-multi', + title: translate('Activate the global connect tool'), + action: { + click: function(event) { + globalConnect.toggle(event); + } + } + }, + 'tool-separator': { + group: 'tools', + separator: true + }, + 'create.start-event': createAction( + 'bpmn:StartEvent', + 'event', + 'bpmn-icon-start-event-none' + ), + 'create.intermediate-event': createAction( + 'bpmn:IntermediateThrowEvent', + 'event', + 'bpmn-icon-intermediate-event-none', + translate('Create Intermediate/Boundary Event') + ), + 'create.end-event': createAction( + 'bpmn:EndEvent', + 'event', + 'bpmn-icon-end-event-none' + ), + 'create.exclusive-gateway': createAction( + 'bpmn:ExclusiveGateway', + 'gateway', + 'bpmn-icon-gateway-none', + translate('Create Gateway') + ), + 'create.task': createAction('bpmn:Task', 'activity', 'bpmn-icon-task'), + 'create.subprocess-expanded': createAction( + 'bpmn:SubProcess', + 'activity', + 'bpmn-icon-subprocess-expanded', + translate('Create expanded SubProcess'), + { isExpanded: true } + ) + }); + return actions; +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomRenderer.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomRenderer.js new file mode 100644 index 00000000..f397fed9 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomRenderer.js @@ -0,0 +1,176 @@ +import inherits from 'inherits'; + +import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer'; + +import { componentsToPath, createLine } from 'diagram-js/lib/util/RenderUtil'; + +import { + append as svgAppend, + attr as svgAttr, + create as svgCreate +} from 'tiny-svg'; + +/** + * A renderer that knows how to render custom elements. + */ +export default function CustomRenderer(eventBus, styles) { + BaseRenderer.call(this, eventBus, 2000); + + var computeStyle = styles.computeStyle; + + this.drawTriangle = function(p, side) { + var halfSide = side / 2, + points, + attrs; + + points = [halfSide, 0, side, side, 0, side]; + + attrs = computeStyle(attrs, { + stroke: '#3CAA82', + strokeWidth: 2, + fill: '#3CAA82' + }); + + var polygon = svgCreate('polygon'); + + svgAttr(polygon, { + points: points + }); + + svgAttr(polygon, attrs); + + svgAppend(p, polygon); + + return polygon; + }; + + this.getTrianglePath = function(element) { + var x = element.x, + y = element.y, + width = element.width, + height = element.height; + + var trianglePath = [ + ['M', x + width / 2, y], + ['l', width / 2, height], + ['l', -width, 0], + ['z'] + ]; + + return componentsToPath(trianglePath); + }; + + this.drawCircle = function(p, width, height) { + var cx = width / 2, + cy = height / 2; + + var attrs = computeStyle(attrs, { + stroke: '#4488aa', + strokeWidth: 4, + fill: 'white' + }); + + var circle = svgCreate('circle'); + + svgAttr(circle, { + cx: cx, + cy: cy, + r: Math.round((width + height) / 4) + }); + + svgAttr(circle, attrs); + + svgAppend(p, circle); + + return circle; + }; + + this.getCirclePath = function(shape) { + var cx = shape.x + shape.width / 2, + cy = shape.y + shape.height / 2, + radius = shape.width / 2; + + var circlePath = [ + ['M', cx, cy], + ['m', 0, -radius], + ['a', radius, radius, 0, 1, 1, 0, 2 * radius], + ['a', radius, radius, 0, 1, 1, 0, -2 * radius], + ['z'] + ]; + + return componentsToPath(circlePath); + }; + + this.drawCustomConnection = function(p, element) { + var attrs = computeStyle(attrs, { + stroke: '#ff471a', + strokeWidth: 2 + }); + + return svgAppend(p, createLine(element.waypoints, attrs)); + }; + + this.getCustomConnectionPath = function(connection) { + var waypoints = connection.waypoints.map(function(p) { + return p.original || p; + }); + + var connectionPath = [['M', waypoints[0].x, waypoints[0].y]]; + + waypoints.forEach(function(waypoint, index) { + if (index !== 0) { + connectionPath.push(['L', waypoint.x, waypoint.y]); + } + }); + + return componentsToPath(connectionPath); + }; +} + +inherits(CustomRenderer, BaseRenderer); + +CustomRenderer.$inject = ['eventBus', 'styles']; + +CustomRenderer.prototype.canRender = function(element) { + return /^custom:/.test(element.type); +}; + +CustomRenderer.prototype.drawShape = function(p, element) { + var type = element.type; + + if (type === 'custom:triangle') { + return this.drawTriangle(p, element.width); + } + + if (type === 'custom:circle') { + return this.drawCircle(p, element.width, element.height); + } +}; + +CustomRenderer.prototype.getShapePath = function(shape) { + var type = shape.type; + + if (type === 'custom:triangle') { + return this.getTrianglePath(shape); + } + + if (type === 'custom:circle') { + return this.getCirclePath(shape); + } +}; + +CustomRenderer.prototype.drawConnection = function(p, element) { + var type = element.type; + + if (type === 'custom:connection') { + return this.drawCustomConnection(p, element); + } +}; + +CustomRenderer.prototype.getConnectionPath = function(connection) { + var type = connection.type; + + if (type === 'custom:connection') { + return this.getCustomConnectionPath(connection); + } +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomRules.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomRules.js new file mode 100644 index 00000000..1dce143d --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomRules.js @@ -0,0 +1,136 @@ +import { reduce } from 'min-dash'; + +import inherits from 'inherits'; + +import { is } from 'bpmn-js/lib/util/ModelUtil'; + +import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider'; + +var HIGH_PRIORITY = 1500; + +function isCustom(element) { + return element && /^custom:/.test(element.type); +} + +/** + * Specific rules for custom elements + */ +export default function CustomRules(eventBus) { + RuleProvider.call(this, eventBus); +} + +inherits(CustomRules, RuleProvider); + +CustomRules.$inject = ['eventBus']; + +CustomRules.prototype.init = function() { + /** + * Can shape be created on target container? + */ + function canCreate(shape, target) { + // only judge about custom elements + if (!isCustom(shape)) { + return; + } + + // allow creation on processes + return ( + is(target, 'bpmn:Process') || + is(target, 'bpmn:Participant') || + is(target, 'bpmn:Collaboration') + ); + } + + /** + * Can source and target be connected? + */ + function canConnect(source, target) { + // only judge about custom elements + if (!isCustom(source) && !isCustom(target)) { + return; + } + + // allow connection between custom shape and task + if (isCustom(source)) { + if (is(target, 'bpmn:Task')) { + return { type: 'custom:connection' }; + } else { + return false; + } + } else if (isCustom(target)) { + if (is(source, 'bpmn:Task')) { + return { type: 'custom:connection' }; + } else { + return false; + } + } + } + + this.addRule('elements.move', HIGH_PRIORITY, function(context) { + var target = context.target, + shapes = context.shapes; + + var type; + + // do not allow mixed movements of custom / BPMN shapes + // if any shape cannot be moved, the group cannot be moved, too + var allowed = reduce( + shapes, + function(result, s) { + if (type === undefined) { + type = isCustom(s); + } + + if (type !== isCustom(s) || result === false) { + return false; + } + + return canCreate(s, target); + }, + undefined + ); + + // reject, if we have at least one + // custom element that cannot be moved + return allowed; + }); + + this.addRule('shape.create', HIGH_PRIORITY, function(context) { + var target = context.target, + shape = context.shape; + + return canCreate(shape, target); + }); + + this.addRule('shape.resize', HIGH_PRIORITY, function(context) { + var shape = context.shape; + + if (isCustom(shape)) { + // cannot resize custom elements + return false; + } + }); + + this.addRule('connection.create', HIGH_PRIORITY, function(context) { + var source = context.source, + target = context.target; + + return canConnect(source, target); + }); + + this.addRule('connection.reconnectStart', HIGH_PRIORITY, function(context) { + var connection = context.connection, + source = context.hover || context.source, + target = connection.target; + + return canConnect(source, target, connection); + }); + + this.addRule('connection.reconnectEnd', HIGH_PRIORITY, function(context) { + var connection = context.connection, + source = connection.source, + target = context.hover || context.target; + + return canConnect(source, target, connection); + }); +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomUpdater.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomUpdater.js new file mode 100644 index 00000000..532c24f3 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/CustomUpdater.js @@ -0,0 +1,136 @@ +import inherits from 'inherits'; + +import { pick, assign } from 'min-dash'; + +import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor'; + +import { + add as collectionAdd, + remove as collectionRemove +} from 'diagram-js/lib/util/Collections'; + +/** + * A handler responsible for updating the custom element's businessObject + * once changes on the diagram happen. + */ +export default function CustomUpdater(eventBus, bpmnjs) { + CommandInterceptor.call(this, eventBus); + + function updateCustomElement(e) { + var context = e.context, + shape = context.shape, + businessObject = shape.businessObject; + + if (!isCustom(shape)) { + return; + } + + var parent = shape.parent; + + var customElements = bpmnjs._customElements; + + // make sure element is added / removed from bpmnjs.customElements + if (!parent) { + collectionRemove(customElements, businessObject); + } else { + collectionAdd(customElements, businessObject); + } + + // save custom element position + assign(businessObject, pick(shape, ['x', 'y'])); + } + + function updateCustomConnection(e) { + var context = e.context, + connection = context.connection, + source = connection.source, + target = connection.target, + businessObject = connection.businessObject; + + var parent = connection.parent; + + var customElements = bpmnjs._customElements; + + // make sure element is added / removed from bpmnjs.customElements + if (!parent) { + collectionRemove(customElements, businessObject); + } else { + collectionAdd(customElements, businessObject); + } + + // update waypoints + assign(businessObject, { + waypoints: copyWaypoints(connection) + }); + + if (source && target) { + assign(businessObject, { + source: source.id, + target: target.id + }); + } + } + + this.executed( + ['shape.create', 'shape.move', 'shape.delete'], + ifCustomElement(updateCustomElement) + ); + + this.reverted( + ['shape.create', 'shape.move', 'shape.delete'], + ifCustomElement(updateCustomElement) + ); + + this.executed( + [ + 'connection.create', + 'connection.reconnectStart', + 'connection.reconnectEnd', + 'connection.updateWaypoints', + 'connection.delete', + 'connection.layout', + 'connection.move' + ], + ifCustomElement(updateCustomConnection) + ); + + this.reverted( + [ + 'connection.create', + 'connection.reconnectStart', + 'connection.reconnectEnd', + 'connection.updateWaypoints', + 'connection.delete', + 'connection.layout', + 'connection.move' + ], + ifCustomElement(updateCustomConnection) + ); +} + +inherits(CustomUpdater, CommandInterceptor); + +CustomUpdater.$inject = ['eventBus', 'bpmnjs']; + +/////// helpers /////////////////////////////////// + +function copyWaypoints(connection) { + return connection.waypoints.map(function(p) { + return { x: p.x, y: p.y }; + }); +} + +function isCustom(element) { + return element && /custom:/.test(element.type); +} + +function ifCustomElement(fn) { + return function(event) { + var context = event.context, + element = context.shape || context.connection; + + if (isCustom(element)) { + fn(event); + } + }; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/index.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/index.js new file mode 100644 index 00000000..f1085390 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/custom/index.js @@ -0,0 +1,22 @@ +import CustomElementFactory from './CustomElementFactory'; +import CustomRenderer from './CustomRenderer'; +import CustomPalette from './CustomPalette'; +import CustomRules from './CustomRules'; +import CustomUpdater from './CustomUpdater'; +import CustomContextPadProvider from './CustomContextPadProvider'; + +export default { + __init__: [ + 'customRenderer', + 'paletteProvider', + 'customRules', + 'customUpdater', + 'contextPadProvider' + ], + elementFactory: ['type', CustomElementFactory], + customRenderer: ['type', CustomRenderer], + paletteProvider: ['type', CustomPalette], + customRules: ['type', CustomRules], + customUpdater: ['type', CustomUpdater], + contextPadProvider: ['type', CustomContextPadProvider] +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/index.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/index.js new file mode 100644 index 00000000..86fbff6a --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-modeler/index.js @@ -0,0 +1,99 @@ +import Modeler from 'bpmn-js/lib/Modeler'; + +import { assign, isArray } from 'min-dash'; + +import inherits from 'inherits'; + +import CustomModule from './custom'; + +export default function CustomModeler(options) { + Modeler.call(this, options); + + this._customElements = []; +} + +inherits(CustomModeler, Modeler); + +CustomModeler.prototype._modules = [].concat(CustomModeler.prototype._modules, [ + CustomModule +]); + +/** + * Add a single custom element to the underlying diagram + * + * @param {Object} customElement + */ +CustomModeler.prototype._addCustomShape = function(customElement) { + this._customElements.push(customElement); + + var canvas = this.get('canvas'), + elementFactory = this.get('elementFactory'); + + var customAttrs = assign({ businessObject: customElement }, customElement); + + var customShape = elementFactory.create('shape', customAttrs); + + return canvas.addShape(customShape); +}; + +CustomModeler.prototype._addCustomConnection = function(customElement) { + this._customElements.push(customElement); + + var canvas = this.get('canvas'), + elementFactory = this.get('elementFactory'), + elementRegistry = this.get('elementRegistry'); + + var customAttrs = assign({ businessObject: customElement }, customElement); + + var connection = elementFactory.create( + 'connection', + assign(customAttrs, { + source: elementRegistry.get(customElement.source), + target: elementRegistry.get(customElement.target) + }), + elementRegistry.get(customElement.source).parent + ); + + return canvas.addConnection(connection); +}; + +/** + * Add a number of custom elements and connections to the underlying diagram. + * + * @param {Array} customElements + */ +CustomModeler.prototype.addCustomElements = function(customElements) { + if (!isArray(customElements)) { + throw new Error('argument must be an array'); + } + + var shapes = [], + connections = []; + + customElements.forEach(function(customElement) { + if (isCustomConnection(customElement)) { + connections.push(customElement); + } else { + shapes.push(customElement); + } + }); + + // add shapes before connections so that connections + // can already rely on the shapes being part of the diagram + shapes.forEach(this._addCustomShape, this); + + connections.forEach(this._addCustomConnection, this); +}; + +/** + * Get custom elements with their current status. + * + * @return {Array} custom elements on the diagram + */ +CustomModeler.prototype.getCustomElements = function() { + return this._customElements; +}; + +function isCustomConnection(element) { + return element.type === 'custom:connection'; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/descriptors/camunda.json b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/descriptors/camunda.json new file mode 100644 index 00000000..6613c4bf --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/descriptors/camunda.json @@ -0,0 +1,1025 @@ +{ + "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": "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": "workflowSource", + "isAttr": true, + "type": "String" + }, + { + "name": "workflowTarget", + "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/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/WorkflowPropertiesProvider.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/WorkflowPropertiesProvider.js new file mode 100644 index 00000000..d6b3b274 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/WorkflowPropertiesProvider.js @@ -0,0 +1,300 @@ +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 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); + 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, + config + ) + }; + 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/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/index.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/index.js new file mode 100644 index 00000000..bc60c581 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/index.js @@ -0,0 +1,10 @@ +import ElementTemplates from 'bpmn-js-properties-panel/lib/provider/camunda/element-templates'; +import Translate from 'diagram-js/lib/i18n/translate'; + +import WorkflowPropertiesProvider from './WorkflowPropertiesProvider'; + +export default { + __depends__: [ElementTemplates, Translate], + __init__: ['propertiesProvider'], + propertiesProvider: ['type', WorkflowPropertiesProvider] +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputParameterProps.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputParameterProps.js new file mode 100644 index 00000000..d221c6e3 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputParameterProps.js @@ -0,0 +1,21 @@ +import inputOutputParameter from './implementation/InputOutputParameter'; +import assign from 'lodash.assign'; + +export default function( + group, + element, + bpmnFactory, + options, + translate, + config +) { + group.entries = group.entries.concat( + inputOutputParameter( + element, + bpmnFactory, + assign({}, options), + translate, + config + ) + ); +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputProps.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputProps.js new file mode 100644 index 00000000..bdcbab46 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/InputOutputProps.js @@ -0,0 +1,13 @@ +'use strict'; + +import inputOutput from './implementation/InputOutput'; + +export default function(group, element, bpmnFactory, translate) { + const inputOutputEntry = inputOutput(element, bpmnFactory, {}, translate); + + group.entries = group.entries.concat(inputOutputEntry.entries); + + return { + getSelectedParameter: inputOutputEntry.getSelectedParameter + }; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/WorkflowServiceTaskDelegateProps.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/WorkflowServiceTaskDelegateProps.js new file mode 100644 index 00000000..bc871357 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/WorkflowServiceTaskDelegateProps.js @@ -0,0 +1,123 @@ +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, + serviceTaskEntries +} from './implementation/implementationConstants'; +import Delegate from './implementation/Delegate'; +import ResultVariable from './implementation/ResultVariable'; + +const getImplementationType = element => { + let implementationType = ImplementationTypeHelper.getImplementationType( + element + ); + + if (!implementationType || implementationType === 'expression') { + const bo = getBusinessObject(element); + if (bo) { + if ( + typeof bo.get(implementationTypeConst.ACTIVITY) !== 'undefined' + ) { + return 'workflowActivity'; + } + } + } + + return implementationType; +}; + +const hideResultVariable = element => { + return getImplementationType(element) !== 'expression'; +}; + +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 !== serviceTaskEntries.IMPLEMENTATION && + entry.id !== serviceTaskEntries.DELEGATE && + entry.id !== serviceTaskEntries.RESULT_VARIABLE + ); + + group.entries = group.entries.concat( + workflowActivity( + element, + config, + bpmnFactory, + { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType + }, + translate + ) + ); + + group.entries = group.entries.concat( + Delegate( + element, + bpmnFactory, + { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType + }, + translate + ) + ); + + group.entries = group.entries.concat( + ResultVariable( + element, + bpmnFactory, + { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType, + hideResultVariable: hideResultVariable + }, + translate + ) + ); + group.entries = group.entries.concat( + workflowImplementationType( + element, + bpmnFactory, + { + getBusinessObject: getBusinessObject, + getImplementationType: getImplementationType, + hasDmnSupport: isDmnCapable(element), + hasExternalSupport: isExternalCapable( + getBusinessObject(element) + ), + hasServiceTaskLikeSupport: true + }, + translate + ) + ); + } +} + +inherits(WorkflowServiceTaskDelegateProps, ServiceTaskDelegateProps); + +export default WorkflowServiceTaskDelegateProps; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/createInputOutputTabGroups.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/createInputOutputTabGroups.js new file mode 100644 index 00000000..3dede1a9 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/createInputOutputTabGroups.js @@ -0,0 +1,58 @@ +import inputOutputParameter from './InputOutputParameterProps'; +import inputOutput from './InputOutputProps'; +const 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, + config +) { + 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, + config + ); + + return [inputOutputGroup, inputOutputParameterGroup]; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/Delegate.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/Delegate.js new file mode 100644 index 00000000..f6a0b247 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/Delegate.js @@ -0,0 +1,78 @@ +'use strict'; + +import entryFactory from 'bpmn-js-properties-panel/lib/factory/EntryFactory'; +import cmdHelper from 'bpmn-js-properties-panel/lib/helper/CmdHelper'; + +const DELEGATE_TYPES = ['class', 'expression', 'delegateExpression']; + +const PROPERTIES = { + class: 'camunda:class', + expression: 'camunda:expression', + delegateExpression: 'camunda:delegateExpression' +}; + +function isDelegate(type) { + return DELEGATE_TYPES.indexOf(type) !== -1; +} + +function getAttribute(type) { + return PROPERTIES[type]; +} + +export default function(element, bpmnFactory, options, translate) { + var getImplementationType = options.getImplementationType, + getBusinessObject = options.getBusinessObject; + + function getDelegationLabel(type) { + switch (type) { + case 'class': + return translate('Java Class'); + case 'expression': + return translate('Expression'); + case 'delegateExpression': + return translate('Delegate Expression'); + default: + return ''; + } + } + + var delegateEntry = entryFactory.textField({ + id: 'delegate', + label: translate('Value'), + dataValueLabel: 'delegationLabel', + modelProperty: 'delegate', + + get: function(element) { + var bo = getBusinessObject(element); + var type = getImplementationType(element); + var attr = getAttribute(type); + var label = getDelegationLabel(type); + return { + delegate: bo.get(attr), + delegationLabel: label + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + var type = getImplementationType(element); + var attr = getAttribute(type); + var prop = {}; + prop[attr] = values.delegate || ''; + return cmdHelper.updateBusinessObject(element, bo, prop); + }, + + validate: function(element, values) { + return isDelegate(getImplementationType(element)) && + !values.delegate + ? { delegate: 'Must provide a value' } + : {}; + }, + + hidden: function(element) { + return !isDelegate(getImplementationType(element)); + } + }); + + return [delegateEntry]; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutput.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutput.js new file mode 100644 index 00000000..2bbef4f2 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutput.js @@ -0,0 +1,289 @@ +import inputOutputHelper from './InputOutputHelper'; +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'), + cmdHelper = require('bpmn-js-properties-panel/lib/helper/CmdHelper'); + +var extensionElementsEntry = require('bpmn-js-properties-panel/lib/provider/camunda/parts/implementation//ExtensionElements'); + +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); +} + +export function createElement(type, parent, factory, properties) { + const el = elementHelper.createElement(type, properties, parent, factory); + return el; +} + +export 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 + ); +} + +export default 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 + }); + + 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: inputOutputHelper.isCreateDeleteSupported( + element + ) + ? newElement('camunda:InputParameter', 'inputParameters') + : undefined, + removeExtensionElement: inputOutputHelper.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: inputOutputHelper.isCreateDeleteSupported( + element + ) + ? newElement('camunda:OutputParameter', 'outputParameters') + : undefined, + removeExtensionElement: inputOutputHelper.isCreateDeleteSupported( + element + ) + ? removeElement( + getOutputParameter, + 'outputParameters', + 'inputParameters' + ) + : inputOutputHelper.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/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputHelper.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputHelper.js new file mode 100644 index 00000000..595ab799 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputHelper.js @@ -0,0 +1,173 @@ +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'); +import { implementationType } from './implementationConstants'; + +var 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) + ); +}; + +InputOutputHelper.isCreateDeleteSupported = function(element) { + const bo = getBusinessObject(element); + return ( + (element.type !== 'bpmn:ServiceTask' || + !bo[implementationType.ACTIVITY]) && + element.type !== 'bpmn:Process' + ); +}; + +InputOutputHelper.isWorkflowTargetSupported = function(element, selected) { + const bo = getBusinessObject(element); + return ( + is(bo, 'bpmn:ServiceTask') && is(selected, 'camunda:OutputParameter') + ); +}; + +InputOutputHelper.isWorkflowSourceSupported = function(element, selected) { + const bo = getBusinessObject(element); + return is(bo, 'bpmn:ServiceTask') && is(selected, 'camunda:InputParameter'); +}; + +export default InputOutputHelper; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputParameter.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputParameter.js new file mode 100644 index 00000000..10e258e3 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputParameter.js @@ -0,0 +1,424 @@ +import inputOutputHelper from './InputOutputHelper'; + +var is = require('bpmn-js/lib/util/ModelUtil').is; + +var elementHelper = require('bpmn-js-properties-panel/lib/helper/ElementHelper'), + 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 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); +} + +export default 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 !inputOutputHelper.isCreateDeleteSupported(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 !inputOutputHelper.isCreateDeleteSupported(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: '
' + script.template + '
', + 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/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputUpdater.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputUpdater.js new file mode 100644 index 00000000..056a2dba --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/InputOutputUpdater.js @@ -0,0 +1,74 @@ +/* +* 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 cmdHelper from 'bpmn-js-properties-panel/lib/helper/CmdHelper'; +import { createInputOutput, createElement } from './InputOutput'; +import InputOutputHelper from './InputOutputHelper'; +import { INPUT, OUTPUT } from './implementationConstants'; + +export default ({ element, bo, bpmnFactory, activityInputsOutputs }) => { + const commands = []; + const existedInputOutput = InputOutputHelper.getInputOutput(element); + + let newInputOutput = createInputOutput(element, bpmnFactory, { + inputParameters: [], + outputParameters: [] + }); + + const inputs = activityInputsOutputs.inputs.map(({ name, value }) => + createElement(INPUT, newInputOutput, bpmnFactory, { + name, + type: 'Text', + value + }) + ); + + const outputs = activityInputsOutputs.outputs.map(({ name, value }) => + createElement(OUTPUT, newInputOutput, bpmnFactory, { + name, + type: 'Text', + value + }) + ); + + newInputOutput.inputParameters = inputs; + newInputOutput.outputParameters = outputs; + + const objectToRemove = existedInputOutput ? [existedInputOutput] : []; + const extensionElements = + bo.extensionElements || + createElement('bpmn:ExtensionElements', bo, bpmnFactory, []); + + if (!bo.extensionElements) { + commands.push( + cmdHelper.updateBusinessObject(element, bo, { + extensionElements + }) + ); + } + + commands.push( + cmdHelper.addAndRemoveElementsFromList( + element, + extensionElements, + 'values', + 'extensionElements', + [newInputOutput], + objectToRemove + ) + ); + return commands; +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/ResultVariable.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/ResultVariable.js new file mode 100644 index 00000000..a0b425fe --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/ResultVariable.js @@ -0,0 +1,52 @@ +'use strict'; + +import { is } from 'bpmn-js/lib/util/ModelUtil'; + +import assign from 'lodash.assign'; + +var entryFactory = require('bpmn-js-properties-panel/lib/factory/EntryFactory'), + cmdHelper = require('bpmn-js-properties-panel/lib/helper/CmdHelper'); + +export default function(element, bpmnFactory, options, translate) { + var getBusinessObject = options.getBusinessObject, + hideResultVariable = options.hideResultVariable, + id = options.id || 'resultVariable'; + + var resultVariableEntry = entryFactory.textField({ + id: id, + label: translate('Result Variable'), + modelProperty: 'resultVariable', + + get: function(element) { + var bo = getBusinessObject(element); + return { resultVariable: bo.get('camunda:resultVariable') }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + + var resultVariable = values.resultVariable || undefined; + + var props = { + 'camunda:resultVariable': resultVariable + }; + + if (is(bo, 'camunda:DmnCapable') && !resultVariable) { + props = assign( + { 'camunda:mapDecisionResult': 'resultList' }, + props + ); + } + + return cmdHelper.updateBusinessObject(element, bo, props); + }, + + hidden: function() { + if (typeof hideResultVariable === 'function') { + return hideResultVariable.apply(resultVariableEntry, arguments); + } + } + }); + + return [resultVariableEntry]; +} diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowActivity.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowActivity.js new file mode 100644 index 00000000..6616f6a4 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowActivity.js @@ -0,0 +1,89 @@ +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, + SERVICE_TASK_NAME +} from './implementationConstants'; + +import InputOutputUpdater from './InputOutputUpdater'; + +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); + const value = bo.get(implementationType.ACTIVITY); + const activityValue = + value && value.indexOf(IMPLEMENTATION_TYPE_VALUE) > -1 + ? value.substr(IMPLEMENTATION_TYPE_VALUE.length) + : ''; + + return { + workflowActivity: activityValue + }; + }, + + set: function(element, values) { + var bo = getBusinessObject(element); + + const commands = []; + const dataForUpdate = {}; + + const activityInputsOutputs = config.getActivityInputsOutputs( + values.workflowActivity + ); + + dataForUpdate[ + implementationType.ACTIVITY + ] = `${IMPLEMENTATION_TYPE_VALUE}${values.workflowActivity}`; + + dataForUpdate[implementationType.EXPRESSION] = + implementationType.EXPRESSION_VALUE; + + dataForUpdate[SERVICE_TASK_NAME] = values.workflowActivity; + + commands.push( + cmdHelper.updateBusinessObject(element, bo, dataForUpdate) + ); + return [ + ...commands, + ...InputOutputUpdater({ + element, + bo, + bpmnFactory, + activityInputsOutputs, + commands + }) + ]; + }, + + validate: function(element, values) { + const hasErrors = + isWorkflowActivity(element) && !values.workflowActivity; + config.validationUpdate(element, !hasErrors); + + return hasErrors + ? { workflowActivity: 'Must provide a value' } + : {}; + }, + + hidden: function(element) { + return !isWorkflowActivity(element); + } + }); + + return [workflowActivityEntry]; +}; + +export default workflowActivity; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowImplementationType.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowImplementationType.js new file mode 100644 index 00000000..729cc22b --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/WorkflowImplementationType.js @@ -0,0 +1,226 @@ +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; + +export default 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.RESULT_VARIABLE] = undefined; + props[implementationType.EXPRESSION] = undefined; + } 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/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/implementationConstants.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/implementationConstants.js new file mode 100644 index 00000000..efc70800 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/custom-properties-provider/provider/camunda/parts/implementation/implementationConstants.js @@ -0,0 +1,34 @@ +/* +* 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. +*/ + +export const implementationType = { + ACTIVITY: 'implementation', + EXPRESSION: 'camunda:expression', + EXPRESSION_VALUE: '${ExecuteActivity.execute(execution)}', + RESULT_VARIABLE: 'camunda:resultVariable' +}; + +export const IMPLEMENTATION_TYPE_VALUE = 'activity:'; +export const SERVICE_TASK_NAME = 'name'; + +export const serviceTaskEntries = { + IMPLEMENTATION: 'implementation', + DELEGATE: 'delegate', + RESULT_VARIABLE: 'resultVariable' +}; + +export const INPUT = 'camunda:InputParameter'; +export const OUTPUT = 'camunda:OutputParameter'; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/newDiagram.bpmn b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/newDiagram.bpmn new file mode 100644 index 00000000..6abaf8df --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/newDiagram.bpmn @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/readOnly.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/readOnly.js new file mode 100644 index 00000000..f1da7dcf --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/composition/readOnly.js @@ -0,0 +1,134 @@ +import forEach from 'lodash.foreach'; + +const HIGH_PRIORITY = 10001; + +function ReadOnly( + eventBus, + contextPad, + dragging, + directEditing, + editorActions, + modeling, + palette, + paletteProvider +) { + this._readOnly = false; + this._eventBus = eventBus; + + let self = this; + eventBus.on('readOnly.changed', HIGH_PRIORITY, function(e) { + self._readOnly = e.readOnly; + + if (e.readOnly) { + directEditing.cancel(); + contextPad.close(); + dragging.cancel(); + } + + palette._update(); + }); + + function intercept(obj, fnName, cb) { + var fn = obj[fnName]; + obj[fnName] = function() { + return cb.call(this, fn, arguments); + }; + } + + function ignoreWhenReadOnly(obj, fnName) { + intercept(obj, fnName, function(fn, args) { + if (self._readOnly) { + return; + } + + return fn.apply(this, args); + }); + } + + function throwIfReadOnly(obj, fnName) { + intercept(obj, fnName, function(fn, args) { + if (self._readOnly) { + throw new Error('model is read-only'); + } + + return fn.apply(this, args); + }); + } + + ignoreWhenReadOnly(contextPad, 'open'); + + ignoreWhenReadOnly(dragging, 'init'); + + ignoreWhenReadOnly(directEditing, 'activate'); + + ignoreWhenReadOnly(editorActions._actions, 'undo'); + ignoreWhenReadOnly(editorActions._actions, 'redo'); + ignoreWhenReadOnly(editorActions._actions, 'copy'); + ignoreWhenReadOnly(editorActions._actions, 'paste'); + ignoreWhenReadOnly(editorActions._actions, 'removeSelection'); + // BpmnEditorActions + ignoreWhenReadOnly(editorActions._actions, 'spaceTool'); + ignoreWhenReadOnly(editorActions._actions, 'lassoTool'); + ignoreWhenReadOnly(editorActions._actions, 'globalConnectTool'); + ignoreWhenReadOnly(editorActions._actions, 'distributeElements'); + ignoreWhenReadOnly(editorActions._actions, 'alignElements'); + ignoreWhenReadOnly(editorActions._actions, 'directEditing'); + + throwIfReadOnly(modeling, 'moveShape'); + throwIfReadOnly(modeling, 'updateAttachment'); + throwIfReadOnly(modeling, 'moveElements'); + throwIfReadOnly(modeling, 'moveConnection'); + throwIfReadOnly(modeling, 'layoutConnection'); + throwIfReadOnly(modeling, 'createConnection'); + throwIfReadOnly(modeling, 'createShape'); + throwIfReadOnly(modeling, 'createLabel'); + throwIfReadOnly(modeling, 'appendShape'); + throwIfReadOnly(modeling, 'removeElements'); + throwIfReadOnly(modeling, 'distributeElements'); + throwIfReadOnly(modeling, 'removeShape'); + throwIfReadOnly(modeling, 'removeConnection'); + throwIfReadOnly(modeling, 'replaceShape'); + throwIfReadOnly(modeling, 'pasteElements'); + throwIfReadOnly(modeling, 'alignElements'); + throwIfReadOnly(modeling, 'resizeShape'); + throwIfReadOnly(modeling, 'createSpace'); + throwIfReadOnly(modeling, 'updateWaypoints'); + throwIfReadOnly(modeling, 'reconnectStart'); + throwIfReadOnly(modeling, 'reconnectEnd'); + + intercept(paletteProvider, 'getPaletteEntries', function(fn, args) { + var entries = fn.apply(this, args); + if (self._readOnly) { + forEach(entries, function(value, key) { + delete entries[key]; + }); + } + return entries; + }); +} + +ReadOnly.$inject = [ + 'eventBus', + 'contextPad', + 'dragging', + 'directEditing', + 'editorActions', + 'modeling', + 'palette', + 'paletteProvider' +]; + +module.exports = ReadOnly; + +ReadOnly.prototype.readOnly = function(readOnly) { + var newValue = !!readOnly, + oldValue = !!this._readOnly; + + if (readOnly === undefined || newValue === oldValue) { + return oldValue; + } + + this._readOnly = newValue; + this._eventBus.fire('readOnly.changed', { readOnly: newValue }); + return newValue; +}; diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersion.js b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersion.js new file mode 100644 index 00000000..2635fa36 --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersion.js @@ -0,0 +1,53 @@ +/* +* 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 { connect } from 'react-redux'; +import { withRouter } from 'react-router-dom'; + +import { hideModalAction } from 'shared/modal/modalWrapperActions'; +import CreateVersionView from 'features/version/create/CreateVersionView'; +import { + newVersionAction, + submitVersionAction +} from 'features/version/create/createVersionConstants'; +import { + getWorkflowId, + getLatestBaseId +} from 'features/workflow/overview/overviewSelectors'; + +function mapStateToProps(state) { + return { + workflowId: getWorkflowId(state), + baseVersionId: getLatestBaseId(state) + }; +} + +function mapDispatchToProps(dispatch) { + return { + submitNewVersion: payload => { + dispatch(submitVersionAction(payload)); + dispatch(hideModalAction()); + }, + closeCreateVersionModal: () => dispatch(hideModalAction()), + versionDetailsChanged: payload => dispatch(newVersionAction(payload)) + }; +} + +export default withRouter( + connect( + mapStateToProps, + mapDispatchToProps + )(CreateVersionView) +); diff --git a/sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersionView.jsx b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersionView.jsx new file mode 100644 index 00000000..101b442d --- /dev/null +++ b/sdc-workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersionView.jsx @@ -0,0 +1,95 @@ +/* +* 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 React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { I18n } from 'react-redux-i18n'; +import { Button } from 'onap-ui-react'; +import Description from 'shared/components/Description'; +import Select from 'shared/components/Select/index'; +import { VERSION_LEVEL_LIST } from 'wfapp/appConstants'; + +class CreateVersionView extends Component { + static propTypes = { + versionCategories: PropTypes.array, + closeCreateVersionModal: PropTypes.func, + versionDetailsChanged: PropTypes.func, + submitNewVersion: PropTypes.func, + workflowId: PropTypes.string, + baseVersionId: PropTypes.string, + history: PropTypes.object + }; + + constructor(props) { + super(props); + this.state = { + newVersion: '' + }; + } + handleSubmitForm = () => { + const { + submitNewVersion, + workflowId, + baseVersionId, + history + } = this.props; + submitNewVersion({ + description: this.state.newVersion.description, + workflowId: workflowId, + baseId: baseVersionId || null, + history: history + }); + }; + + versionDetailsChanged = val => { + this.setState({ newVersion: val }); + }; + + render() { + const { closeCreateVersionModal } = this.props; + return ( +
+
+
+ + + + +
+
+
+
+ description +
+