From 6812928b86c84b9366e79581b38207dc153f65ef Mon Sep 17 00:00:00 2001 From: Thiago Lugli Date: Thu, 21 Nov 2024 07:53:15 -0300 Subject: [PATCH 1/5] Refactor Management Console to support multiple runtimes --- .../kogito-management-console/Containerfile | 1 + .../kogito-management-console/entrypoint.sh | 3 +- .../README.md | 4 +- .../build/defaultEnvJson.js | 15 +- .../keycloak/realm.json} | 2210 ++++++----- .../dev-webapp/secured-runtime/pom.xml | 134 + .../java/org/kie/kogito/hr/CandidateData.java | 93 + .../main/java/org/kie/kogito/hr/Offer.java | 46 + .../resources/META-INF/processSVG/hiring.svg | 1427 +++++++ .../src/main/resources/NewHiringOffer.dmn | 190 + .../src/main/resources/application.properties | 55 + .../src/main/resources/hiring.bpmn | 1057 +++++ .../dev-webapp/unsecured-runtime/pom.xml | 134 + .../java/org/kie/kogito/hr/CandidateData.java | 93 + .../main/java/org/kie/kogito/hr/Offer.java | 46 + .../resources/META-INF/processSVG/hiring.svg | 1427 +++++++ .../src/main/resources/NewHiringOffer.dmn | 190 + .../src/main/resources/application.properties | 45 + .../src/main/resources/hiring.bpmn | 1057 +++++ .../dev/server/MockData/controllers.js | 228 -- .../dev/server/MockData/graphql.js | 3421 ----------------- .../dev/server/MockData/mutationRest.js | 102 - .../dev/server/MockData/rest.js | 100 - .../dev/server/MockData/types.js | 662 ---- .../dev/server/server.js | 414 -- .../dev/server/static/flightBooking.svg | 290 -- .../dev/server/static/hotelBooking.svg | 290 -- .../dev/server/static/travels.svg | 1744 --------- .../env/index.js | 52 +- .../package.json | 24 +- .../serve.json | 3 - .../src/aboutModal/AboutButton.tsx | 106 + .../src/authSessions/AuthSessionApi.ts | 182 + .../src/authSessions/AuthSessionMigrations.ts | 101 + .../src/authSessions/AuthSessionsContext.tsx | 262 ++ .../src/authSessions/AuthSessionsService.ts | 304 ++ .../components/AuthSessionSelect.tsx | 174 + .../components/AuthSessionsList.tsx | 197 + .../NewAuthSessionLoginSuccessPage.tsx | 73 + .../components/NewAuthSessionModal.tsx | 187 + .../src/authSessions/components/index.ts | 23 + .../src/authSessions/index.ts | 24 + .../ManagementConsole/ManagementConsole.tsx | 86 - .../ManagementConsoleNav.tsx | 54 - .../ManagementConsoleRoutes.tsx | 46 - .../JobsContainer/JobsContainer.tsx | 32 - .../ProcessDetailsContainer.tsx | 66 - .../ProcessListContainer.tsx | 63 - .../TasksContainer/TasksContainer.tsx | 58 - .../components/pages/JobsPage/JobsPage.tsx | 45 - .../ProcessDetailsPage/ProcessDetailsPage.tsx | 159 - .../pages/ProcessListPage/ProcessListPage.tsx | 65 - .../pages/TaskDetailsPage/TaskDetailsPage.tsx | 280 -- .../components/pages/TasksPage/TasksPage.tsx | 58 - .../src/components/pages/index.ts | 23 - .../src/env/EnvJson.ts | 10 +- .../src/env/hooks/EnvContext.tsx | 32 + .../src/env/hooks/EnvContextProvider.tsx | 67 + .../src/favicon.ico | Bin 1371 -> 0 bytes .../form-displayer-envelope.ts} | 4 +- .../src/index.tsx | 89 +- .../src/jobs/Jobs.tsx | 90 + .../src/jobs/JobsPage.tsx | 75 + .../{dev/server/app.js => src/jobs/index.ts} | 7 +- .../managementConsole/ManagementConsole.tsx | 45 + .../ManagementConsoleHome.tsx | 121 + .../ManagementConsolePageLayout.tsx | 122 + .../ManagementConsoleRoutes.tsx | 123 + .../ManagementConsoleToolbar.tsx | 38 + .../src/navigation/Hooks.tsx | 54 + .../navigation/NavigationContextProvider.tsx | 141 + .../src/navigation/Routes.ts | 210 + .../queryParams/QueryParamsContext.ts | 32 + .../src/process/details/ProcessDetails.tsx | 141 + .../process/details/ProcessDetailsPage.tsx | 104 + .../config/index.js => src/process/index.ts} | 11 +- .../src/process/list/ProcessList.tsx | 119 + .../src/process/list/ProcessListPage.tsx | 83 + .../src/runtime/RuntimeContext.tsx | 499 +++ .../src/runtime/RuntimeNav.tsx | 60 + .../src/runtime/RuntimePageLayoutContext.tsx | 78 + .../src/static/managementConsoleLogo.svg | 262 -- .../src/styles.css | 90 + .../src/tasks/TaskDetails.tsx | 302 ++ .../src/tasks/TaskDetailsPage.tsx | 96 + .../TaskForm.tsx} | 56 +- .../src/tasks/Tasks.tsx | 123 + .../src/tasks/TasksPage.tsx | 85 + .../components}/FormNotification.tsx | 12 +- .../tasks/components/ImpersonationForm.tsx | 171 + .../styles.css => tasks/components/index.ts} | 13 +- .../{components/console => tasks}/index.ts | 7 +- .../{src => }/static/env.json | 0 .../static/favicon.svg | 44 + .../images/app_logo_rgb_fullcolor_default.svg | 130 + .../images/app_logo_rgb_fullcolor_reverse.svg | 130 + .../{src => static}/index.html | 15 +- .../resources/form-displayer.html | 2 +- .../tsconfig.json | 6 +- .../webpack.config.js | 75 +- .../pages/ProcessFormPage/ProcessFormPage.tsx | 2 +- .../pages/TaskDetailsPage/TaskDetailsPage.tsx | 5 +- .../pages/TaskInboxPage/TaskInboxPage.tsx | 11 +- .../src/components/styles.css | 2 +- .../package.json | 1 + .../api/JobsManagementEnvelopeApi.ts | 8 +- .../embedded/EmbeddedJobsManagement.tsx | 28 +- .../envelope/JobsManagementEnvelope.tsx | 2 +- .../envelope/JobsManagementEnvelopeApiImpl.ts | 6 +- .../envelope/JobsManagementEnvelopeContext.ts | 3 +- .../envelope/JobsManagementEnvelopeView.tsx | 32 +- .../JobsManagement/JobsManagement.tsx | 383 +- .../JobsManagementTable.tsx | 331 +- .../JobsManagementToolbar.tsx | 154 +- .../JobsRescheduleModal.tsx | 162 +- .../embedded/EmbeddedProcessList.tsx | 15 +- .../envelope/ProcessListEnvelopeView.tsx | 32 +- .../components/ProcessList/ProcessList.tsx | 236 +- .../ProcessListActionsKebab.tsx | 10 +- .../ProcessListChildTable.tsx | 258 +- .../ProcessListTable/ProcessListTable.tsx | 230 +- .../ProcessListToolbar/ProcessListToolbar.tsx | 17 +- .../taskForm/embedded/EmbeddedTaskForm.tsx | 2 +- .../envelope/TaskFormEnvelopeView.tsx | 72 +- .../src/taskInbox/api/TaskInboxChannelApi.ts | 2 +- .../taskInbox/embedded/EmbeddedTaskInbox.tsx | 17 +- .../envelope/TaskInboxEnvelopeView.tsx | 6 +- .../components/TaskInbox/TaskInbox.tsx | 267 +- .../TaskInboxToolbar/TaskInboxToolbar.tsx | 229 +- .../src/types.ts | 5 + .../JobsManagementContextProvider.tsx | 12 +- .../JobsManagementGatewayApi.ts | 29 +- .../ProcessListContextProvider.tsx | 2 +- .../src/ProcessList/ProcessListGatewayApi.ts | 33 +- .../src/TaskForms/TaskFormGatewayApi.ts | 36 +- .../TaskInbox/TaskInboxContextProvider.tsx | 14 +- .../src/TaskInbox/TaskInboxGatewayApi.ts | 34 +- pnpm-lock.yaml | 499 ++- repo/graph.dot | 4 +- repo/graph.json | 20 +- 140 files changed, 14425 insertions(+), 10985 deletions(-) rename packages/runtime-tools-management-console-webapp/{dev/config/kogito-realm.json => dev-webapp/keycloak/realm.json} (54%) create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/pom.xml create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/java/org/kie/kogito/hr/CandidateData.java create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/java/org/kie/kogito/hr/Offer.java create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/META-INF/processSVG/hiring.svg create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/NewHiringOffer.dmn create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/application.properties create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/hiring.bpmn create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/pom.xml create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/java/org/kie/kogito/hr/CandidateData.java create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/java/org/kie/kogito/hr/Offer.java create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/META-INF/processSVG/hiring.svg create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/NewHiringOffer.dmn create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/application.properties create mode 100644 packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/hiring.bpmn delete mode 100644 packages/runtime-tools-management-console-webapp/dev/server/MockData/controllers.js delete mode 100644 packages/runtime-tools-management-console-webapp/dev/server/MockData/graphql.js delete mode 100644 packages/runtime-tools-management-console-webapp/dev/server/MockData/mutationRest.js delete mode 100644 packages/runtime-tools-management-console-webapp/dev/server/MockData/rest.js delete mode 100644 packages/runtime-tools-management-console-webapp/dev/server/MockData/types.js delete mode 100644 packages/runtime-tools-management-console-webapp/dev/server/server.js delete mode 100644 packages/runtime-tools-management-console-webapp/dev/server/static/flightBooking.svg delete mode 100644 packages/runtime-tools-management-console-webapp/dev/server/static/hotelBooking.svg delete mode 100644 packages/runtime-tools-management-console-webapp/dev/server/static/travels.svg delete mode 100644 packages/runtime-tools-management-console-webapp/serve.json create mode 100644 packages/runtime-tools-management-console-webapp/src/aboutModal/AboutButton.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionApi.ts create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionMigrations.ts create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionsContext.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionsService.ts create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/components/AuthSessionSelect.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/components/AuthSessionsList.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/components/NewAuthSessionLoginSuccessPage.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/components/NewAuthSessionModal.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/components/index.ts create mode 100644 packages/runtime-tools-management-console-webapp/src/authSessions/index.ts delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsole/ManagementConsole.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsoleNav/ManagementConsoleNav.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsoleRoutes/ManagementConsoleRoutes.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/containers/JobsContainer/JobsContainer.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/containers/ProcessDetailsContainer/ProcessDetailsContainer.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/containers/ProcessListContainer/ProcessListContainer.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/containers/TasksContainer/TasksContainer.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/pages/JobsPage/JobsPage.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/pages/ProcessDetailsPage/ProcessDetailsPage.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/pages/ProcessListPage/ProcessListPage.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/pages/TasksPage/TasksPage.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/components/pages/index.ts create mode 100644 packages/runtime-tools-management-console-webapp/src/env/hooks/EnvContext.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/env/hooks/EnvContextProvider.tsx delete mode 100755 packages/runtime-tools-management-console-webapp/src/favicon.ico rename packages/runtime-tools-management-console-webapp/src/{resources/form-displayer.ts => forms/form-displayer-envelope.ts} (89%) create mode 100644 packages/runtime-tools-management-console-webapp/src/jobs/Jobs.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/jobs/JobsPage.tsx rename packages/runtime-tools-management-console-webapp/{dev/server/app.js => src/jobs/index.ts} (91%) create mode 100644 packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsole.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleHome.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsolePageLayout.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleRoutes.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleToolbar.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/navigation/Hooks.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/navigation/NavigationContextProvider.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/navigation/Routes.ts create mode 100644 packages/runtime-tools-management-console-webapp/src/navigation/queryParams/QueryParamsContext.ts create mode 100644 packages/runtime-tools-management-console-webapp/src/process/details/ProcessDetails.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/process/details/ProcessDetailsPage.tsx rename packages/runtime-tools-management-console-webapp/{dev/server/config/index.js => src/process/index.ts} (80%) create mode 100644 packages/runtime-tools-management-console-webapp/src/process/list/ProcessList.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/process/list/ProcessListPage.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/runtime/RuntimeContext.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/runtime/RuntimeNav.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/runtime/RuntimePageLayoutContext.tsx delete mode 100644 packages/runtime-tools-management-console-webapp/src/static/managementConsoleLogo.svg create mode 100644 packages/runtime-tools-management-console-webapp/src/styles.css create mode 100644 packages/runtime-tools-management-console-webapp/src/tasks/TaskDetails.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/tasks/TaskDetailsPage.tsx rename packages/runtime-tools-management-console-webapp/src/{components/containers/TaskFormContainer/TaskFormContainer.tsx => tasks/TaskForm.tsx} (60%) create mode 100644 packages/runtime-tools-management-console-webapp/src/tasks/Tasks.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/tasks/TasksPage.tsx rename packages/runtime-tools-management-console-webapp/src/{components/pages/TaskDetailsPage/components/FormNotification => tasks/components}/FormNotification.tsx (82%) create mode 100644 packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationForm.tsx rename packages/runtime-tools-management-console-webapp/src/{components/styles.css => tasks/components/index.ts} (79%) rename packages/runtime-tools-management-console-webapp/src/{components/console => tasks}/index.ts (73%) rename packages/runtime-tools-management-console-webapp/{src => }/static/env.json (100%) create mode 100644 packages/runtime-tools-management-console-webapp/static/favicon.svg create mode 100644 packages/runtime-tools-management-console-webapp/static/images/app_logo_rgb_fullcolor_default.svg create mode 100644 packages/runtime-tools-management-console-webapp/static/images/app_logo_rgb_fullcolor_reverse.svg rename packages/runtime-tools-management-console-webapp/{src => static}/index.html (79%) rename packages/runtime-tools-management-console-webapp/{ => static}/resources/form-displayer.html (96%) diff --git a/packages/kogito-management-console/Containerfile b/packages/kogito-management-console/Containerfile index e58ae32a702..372652abfa5 100644 --- a/packages/kogito-management-console/Containerfile +++ b/packages/kogito-management-console/Containerfile @@ -26,6 +26,7 @@ COPY entrypoint.sh dist-dev/image-env-to-json-standalone dist-dev/EnvJson.schema RUN microdnf --disableplugin=subscription-manager -y install httpd \ && microdnf --disableplugin=subscription-manager clean all \ && echo "Mutex posixsem" >> /etc/httpd/conf/httpd.conf \ + && echo "AllowEncodedSlashes NoDecode" >> /etc/httpd/conf/httpd.conf \ && sed -i -e "/#ServerName www.example.com:80/aHeader set Content-Security-Policy \"frame-ancestors 'self';\"" /etc/httpd/conf/httpd.conf \ && sed -i -e 's/Options Indexes FollowSymLinks/Options -Indexes +FollowSymLinks/' /etc/httpd/conf/httpd.conf \ && sed -i "s/Listen 80/Listen ${KOGITO_MANAGEMENT_CONSOLE_PORT}/g" /etc/httpd/conf/httpd.conf \ diff --git a/packages/kogito-management-console/entrypoint.sh b/packages/kogito-management-console/entrypoint.sh index 1b92377150b..ceeec6d2c46 100644 --- a/packages/kogito-management-console/entrypoint.sh +++ b/packages/kogito-management-console/entrypoint.sh @@ -18,8 +18,7 @@ # under the License. # -# Copying the Task Console assets here is essential for when the container is running with the readOnlyRootFilesystem flag. -# But, just like any other directory modified during runtime, the /var/www/html must be a mounted volume in the container in this case. +# Copying the Management Console assets here is essential for when the container is running with the readOnlyRootFilesystem flag. cp -R /management-console/app/* /var/www/html /management-console/image-env-to-json-standalone --directory /var/www/html --json-schema /management-console/EnvJson.schema.json diff --git a/packages/runtime-tools-management-console-webapp/README.md b/packages/runtime-tools-management-console-webapp/README.md index 4083d328dfe..cacf82ab9db 100644 --- a/packages/runtime-tools-management-console-webapp/README.md +++ b/packages/runtime-tools-management-console-webapp/README.md @@ -15,7 +15,9 @@ under the License. --> -# runtime-tools-management-console-webapp +# Apache KIEā„¢ Management Console + +A web application to manage multiple Runtimes. ## Working with Management Console features diff --git a/packages/runtime-tools-management-console-webapp/build/defaultEnvJson.js b/packages/runtime-tools-management-console-webapp/build/defaultEnvJson.js index ad06a77878c..bec7591a21d 100644 --- a/packages/runtime-tools-management-console-webapp/build/defaultEnvJson.js +++ b/packages/runtime-tools-management-console-webapp/build/defaultEnvJson.js @@ -19,20 +19,9 @@ const { env } = require("../env"); -const version = require("../package.json").version; - module.exports = { defaultEnvJson: { - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_KOGITO_ENV_MODE: env.runtimeToolsManagementConsoleWebapp.kogitoEnvMode, - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_KOGITO_APP_NAME: "Management Console", - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_KOGITO_APP_VERSION: version, - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_DATA_INDEX_ENDPOINT: env.runtimeToolsManagementConsoleWebapp.kogitoDataIndexUrl, - KOGITO_CONSOLES_KEYCLOAK_DISABLE_HEALTH_CHECK: false, - KOGITO_CONSOLES_KEYCLOAK_UPDATE_TOKEN_VALIDITY: 30, - KOGITO_CONSOLES_KEYCLOAK_HEALTH_CHECK_URL: - "http://localhost:8280/auth/realms/kogito/.well-known/openid-configuration", - KOGITO_CONSOLES_KEYCLOAK_REALM: "kogito", - KOGITO_CONSOLES_KEYCLOAK_URL: "http://localhost:8280/auth", - KOGITO_CONSOLES_KEYCLOAK_CLIENT_ID: "kogito-console-react", + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME: env.runtimeToolsManagementConsoleWebapp.appName, + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_OIDC_CLIENT_CLIENT_ID: env.runtimeToolsManagementConsoleWebapp.oidcClient.clientId, }, }; diff --git a/packages/runtime-tools-management-console-webapp/dev/config/kogito-realm.json b/packages/runtime-tools-management-console-webapp/dev-webapp/keycloak/realm.json similarity index 54% rename from packages/runtime-tools-management-console-webapp/dev/config/kogito-realm.json rename to packages/runtime-tools-management-console-webapp/dev-webapp/keycloak/realm.json index 3fa33cae2b9..031180e2b0e 100644 --- a/packages/runtime-tools-management-console-webapp/dev/config/kogito-realm.json +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/keycloak/realm.json @@ -1,6 +1,8 @@ { - "realm": "kogito", + "id": "2a888d9a-ee15-44b7-9d95-8b9c22bb03d3", + "realm": "management-console-dev-webapp-realm", "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", "revokeRefreshToken": false, "refreshTokenMaxReuse": 0, "accessTokenLifespan": 300, @@ -12,11 +14,17 @@ "offlineSessionIdleTimeout": 2592000, "offlineSessionMaxLifespanEnabled": false, "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, "accessCodeLifespan": 60, - "accessCodeLifespanUserAction": 300, - "accessCodeLifespanLogin": 1800, + "accessCodeLifespanUserAction": 900, + "accessCodeLifespanLogin": 5400, "actionTokenGeneratedByAdminLifespan": 43200, - "actionTokenGeneratedByUserLifespan": 300, + "actionTokenGeneratedByUserLifespan": 900, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, "enabled": true, "sslRequired": "external", "registrationAllowed": false, @@ -29,6 +37,8 @@ "editUsernameAllowed": false, "bruteForceProtected": false, "permanentLockout": false, + "maxTemporaryLockouts": 0, + "bruteForceStrategy": "MULTIPLE", "maxFailureWaitSeconds": 900, "minimumQuickLoginWaitSeconds": 60, "waitIncrementSeconds": 60, @@ -38,288 +48,382 @@ "roles": { "realm": [ { - "name": "confidential", + "id": "98c3dc43-ce4d-4ac2-ab11-adb8c3089738", + "name": "observer", "composite": false, "clientRole": false, - "containerId": "11d78bf6-6d10-4484-baba-a1388379d68b", + "containerId": "2a888d9a-ee15-44b7-9d95-8b9c22bb03d3", "attributes": {} }, { - "name": "uma_authorization", - "description": "${role_uma_authorization}", + "id": "f8f7fe7a-f278-45bd-8327-23a1ee98a74c", + "name": "admin", "composite": false, "clientRole": false, - "containerId": "11d78bf6-6d10-4484-baba-a1388379d68b", + "containerId": "2a888d9a-ee15-44b7-9d95-8b9c22bb03d3", "attributes": {} }, { - "name": "admin", + "id": "239c3e57-1f83-49a5-9bbf-55189ac83818", + "name": "user", "composite": false, "clientRole": false, - "containerId": "11d78bf6-6d10-4484-baba-a1388379d68b", + "containerId": "2a888d9a-ee15-44b7-9d95-8b9c22bb03d3", "attributes": {} }, { - "name": "user", + "id": "651791c0-bfef-46f7-b441-4e972072b7ca", + "name": "offline_access", + "description": "${role_offline-access}", "composite": false, "clientRole": false, - "containerId": "11d78bf6-6d10-4484-baba-a1388379d68b", + "containerId": "2a888d9a-ee15-44b7-9d95-8b9c22bb03d3", "attributes": {} }, { - "name": "offline_access", - "description": "${role_offline-access}", + "id": "006d437f-e502-4b79-8d4f-74177faa3206", + "name": "default-roles-dev-management-console", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": ["offline_access", "uma_authorization"], + "client": { + "account": ["manage-account", "view-profile"] + } + }, + "clientRole": false, + "containerId": "2a888d9a-ee15-44b7-9d95-8b9c22bb03d3", + "attributes": {} + }, + { + "id": "cefa1127-7c7f-4245-b6d4-08e6c345475e", + "name": "uma_authorization", + "description": "${role_uma_authorization}", "composite": false, "clientRole": false, - "containerId": "11d78bf6-6d10-4484-baba-a1388379d68b", + "containerId": "2a888d9a-ee15-44b7-9d95-8b9c22bb03d3", "attributes": {} } ], "client": { "realm-management": [ { - "name": "manage-identity-providers", - "description": "${role_manage-identity-providers}", + "id": "a7c4880f-90f1-4af1-8fac-f3b70f2ca211", + "name": "create-client", + "description": "${role_create-client}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "impersonation", - "description": "${role_impersonation}", + "id": "899759af-6b9b-40d6-8b3f-599a287a84b7", + "name": "view-events", + "description": "${role_view-events}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "view-identity-providers", - "description": "${role_view-identity-providers}", + "id": "37721551-a752-4711-9881-e578697f56ec", + "name": "query-clients", + "description": "${role_query-clients}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "view-realm", - "description": "${role_view-realm}", + "id": "e6626827-e59c-4ab4-9f91-4ee27d95512b", + "name": "manage-authorization", + "description": "${role_manage-authorization}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "query-users", - "description": "${role_query-users}", + "id": "4202bf01-cd5a-4e2b-8b1d-d06b8633f159", + "name": "query-groups", + "description": "${role_query-groups}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "manage-clients", - "description": "${role_manage-clients}", + "id": "9bc83f6b-23a1-4b93-b6f9-f86a9ee65113", + "name": "manage-users", + "description": "${role_manage-users}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "manage-events", - "description": "${role_manage-events}", + "id": "4184e5ae-687a-489c-8f86-a7a5d68db664", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", + "attributes": {} + }, + { + "id": "3074cb9e-0ae1-4054-87a0-be77a1a48edc", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-groups", "query-users"] + } + }, + "clientRole": true, + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", + "attributes": {} + }, + { + "id": "146bd8d1-6aff-47b1-a071-3b24f9017982", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { + "id": "9ed11394-48c0-4eab-93cf-99c2dd0cd058", "name": "realm-admin", "description": "${role_realm-admin}", "composite": true, "composites": { "client": { "realm-management": [ - "impersonation", - "manage-identity-providers", - "view-identity-providers", - "view-realm", - "query-users", - "manage-clients", - "manage-events", - "manage-realm", - "view-authorization", - "manage-authorization", - "view-users", "create-client", + "view-events", "query-clients", + "manage-authorization", "query-groups", "manage-users", + "impersonation", + "view-users", + "manage-identity-providers", + "view-realm", "view-clients", - "view-events", - "query-realms" + "query-users", + "manage-realm", + "view-identity-providers", + "manage-events", + "manage-clients", + "query-realms", + "view-authorization" ] } }, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "manage-realm", - "description": "${role_manage-realm}", - "composite": false, + "id": "ce3d9b45-62cb-4a30-a5ae-67ee3708ab82", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-clients"] + } + }, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "view-authorization", - "description": "${role_view-authorization}", + "id": "156e31b6-2dbc-4b5a-af45-ebeda2dd1278", + "name": "view-realm", + "description": "${role_view-realm}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "manage-authorization", - "description": "${role_manage-authorization}", + "id": "8eb8e069-5cca-45c0-96fd-cd98682f878c", + "name": "query-users", + "description": "${role_query-users}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "create-client", - "description": "${role_create-client}", + "id": "0f8f6072-7792-4398-b1cb-7260a03aed96", + "name": "manage-realm", + "description": "${role_manage-realm}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "view-users", - "description": "${role_view-users}", - "composite": true, - "composites": { - "client": { - "realm-management": ["query-groups", "query-users"] - } - }, + "id": "9c8c6136-e9e0-4902-8a5e-07237f759141", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "query-clients", - "description": "${role_query-clients}", + "id": "ba6889c5-1801-4f9a-99cf-3be9a497e084", + "name": "manage-clients", + "description": "${role_manage-clients}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "query-groups", - "description": "${role_query-groups}", + "id": "4a5fc9b4-c619-4d78-bbce-9e8c5a550fdb", + "name": "manage-events", + "description": "${role_manage-events}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "manage-users", - "description": "${role_manage-users}", + "id": "ff402b4c-ecd0-4652-afce-4564983410e6", + "name": "query-realms", + "description": "${role_query-realms}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "attributes": {} }, { - "name": "view-clients", - "description": "${role_view-clients}", + "id": "84d836e0-e8ba-4fcd-990c-27f5fc72a3c3", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", + "attributes": {} + } + ], + "security-admin-console": [], + "admin-cli": [], + "management-console-dev-webapp": [], + "account-console": [], + "broker": [ + { + "id": "befe0e69-f4a8-4ef3-8de0-400a0ca3c1e0", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "b02d6b22-1d20-4494-ae96-1f9d60834c53", + "attributes": {} + } + ], + "account": [ + { + "id": "b06a0902-4212-48f4-ad3b-aa16196ac92e", + "name": "manage-account", + "description": "${role_manage-account}", "composite": true, "composites": { "client": { - "realm-management": ["query-clients"] + "account": ["manage-account-links"] } }, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "89bab51b-7d0d-47e4-9c20-7627f47a6d4c", "attributes": {} }, { - "name": "view-events", - "description": "${role_view-events}", + "id": "fd022464-8f97-40df-9213-1664394a73d5", + "name": "view-consent", + "description": "${role_view-consent}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "89bab51b-7d0d-47e4-9c20-7627f47a6d4c", "attributes": {} }, { - "name": "query-realms", - "description": "${role_query-realms}", + "id": "046e3068-2af7-4cb0-b195-9303d07fdb69", + "name": "view-applications", + "description": "${role_view-applications}", "composite": false, "clientRole": true, - "containerId": "376bd940-e50a-4495-80fc-9c6c07312748", + "containerId": "89bab51b-7d0d-47e4-9c20-7627f47a6d4c", "attributes": {} - } - ], - "security-admin-console": [], - "admin-cli": [], - "kogito-service": [ + }, { - "name": "uma_protection", + "id": "91eeaad7-7d08-456f-a244-e1eaf71385eb", + "name": "delete-account", + "description": "${role_delete-account}", "composite": false, "clientRole": true, - "containerId": "0ac5df91-e044-4051-bd03-106a3a5fb9cc", + "containerId": "89bab51b-7d0d-47e4-9c20-7627f47a6d4c", "attributes": {} - } - ], - "broker": [ + }, { - "name": "read-token", - "description": "${role_read-token}", + "id": "e70c3a46-ea17-4c42-acbd-98ad0ecc7840", + "name": "manage-account-links", + "description": "${role_manage-account-links}", "composite": false, "clientRole": true, - "containerId": "53d4fe53-a039-471e-886a-28eddc950e95", + "containerId": "89bab51b-7d0d-47e4-9c20-7627f47a6d4c", "attributes": {} - } - ], - "account": [ + }, + { + "id": "8ffa551c-ea91-4523-a901-98192be12630", + "name": "view-groups", + "description": "${role_view-groups}", + "composite": false, + "clientRole": true, + "containerId": "89bab51b-7d0d-47e4-9c20-7627f47a6d4c", + "attributes": {} + }, { + "id": "b634381d-21db-4f30-afcf-d984f8297c2a", "name": "view-profile", "description": "${role_view-profile}", "composite": false, "clientRole": true, - "containerId": "e55e1234-38fa-432d-8d90-39f5e024688d", + "containerId": "89bab51b-7d0d-47e4-9c20-7627f47a6d4c", "attributes": {} }, { - "name": "manage-account", - "description": "${role_manage-account}", + "id": "7f584f89-d243-425c-8f57-7fff53583318", + "name": "manage-consent", + "description": "${role_manage-consent}", "composite": true, "composites": { "client": { - "account": ["manage-account-links"] + "account": ["view-consent"] } }, "clientRole": true, - "containerId": "e55e1234-38fa-432d-8d90-39f5e024688d", - "attributes": {} - }, - { - "name": "manage-account-links", - "description": "${role_manage-account-links}", - "composite": false, - "clientRole": true, - "containerId": "e55e1234-38fa-432d-8d90-39f5e024688d", + "containerId": "89bab51b-7d0d-47e4-9c20-7627f47a6d4c", "attributes": {} } - ] + ], + "management-console-dev-webapp-runtime": [] } }, "groups": [], - "defaultRoles": ["uma_authorization", "offline_access"], + "defaultRole": { + "id": "006d437f-e502-4b79-8d4f-74177faa3206", + "name": "default-roles-dev-management-console", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "2a888d9a-ee15-44b7-9d95-8b9c22bb03d3" + }, "requiredCredentials": ["password"], "otpPolicyType": "totp", "otpPolicyAlgorithm": "HmacSHA1", @@ -327,24 +431,57 @@ "otpPolicyDigits": 6, "otpPolicyLookAheadWindow": 1, "otpPolicyPeriod": 30, - "otpSupportedApplications": ["FreeOTP", "Google Authenticator"], + "otpPolicyCodeReusable": false, + "otpSupportedApplications": ["totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName"], + "localizationTexts": {}, + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": ["ES256", "RS256"], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyExtraOrigins": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": ["ES256", "RS256"], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "webAuthnPolicyPasswordlessExtraOrigins": [], "scopeMappings": [ { "clientScope": "offline_access", "roles": ["offline_access"] } ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": ["manage-account", "view-groups"] + } + ] + }, "clients": [ { + "id": "89bab51b-7d0d-47e4-9c20-7627f47a6d4c", "clientId": "account", "name": "${client_account}", - "baseUrl": "/auth/realms/kogito/account", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/dev-management-console/account/", "surrogateAuthRequired": false, "enabled": true, + "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", - "secret": "0136c3ef-0dfd-4b13-a6d0-2c8b6358edec", - "defaultRoles": ["view-profile", "manage-account"], - "redirectUris": ["/auth/realms/kogito/account/*"], + "redirectUris": ["/realms/dev-management-console/account/*"], "webOrigins": [], "notBefore": 0, "bearerOnly": false, @@ -353,23 +490,70 @@ "implicitFlowEnabled": false, "directAccessGrantsEnabled": false, "serviceAccountsEnabled": false, - "publicClient": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] + }, + { + "id": "3d7e4565-526e-4245-bc13-6fe35437b305", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/dev-management-console/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/realms/dev-management-console/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, "frontchannelLogout": false, "protocol": "openid-connect", - "attributes": {}, + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "protocolMappers": [ + { + "id": "c268ea39-bca1-40e4-ab0f-4db8391f7ef8", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, { + "id": "db815902-5a95-4f30-a04b-a03b2fb593bc", "clientId": "admin-cli", "name": "${client_admin-cli}", "surrogateAuthRequired": false, "enabled": true, + "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", - "secret": "a951803a-79c7-46a6-8197-e32835286971", "redirectUris": [], "webOrigins": [], "notBefore": 0, @@ -382,24 +566,29 @@ "publicClient": true, "frontchannelLogout": false, "protocol": "openid-connect", - "attributes": {}, + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true", + "post.logout.redirect.uris": "+" + }, "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, + "fullScopeAllowed": true, "nodeReRegistrationTimeout": 0, - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, { + "id": "b02d6b22-1d20-4494-ae96-1f9d60834c53", "clientId": "broker", "name": "${client_broker}", "surrogateAuthRequired": false, "enabled": true, + "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", - "secret": "e1f7edd7-e15c-43b4-8736-ff8204d16836", "redirectUris": [], "webOrigins": [], "notBefore": 0, - "bearerOnly": false, + "bearerOnly": true, "consentRequired": false, "standardFlowEnabled": true, "implicitFlowEnabled": false, @@ -408,23 +597,30 @@ "publicClient": false, "frontchannelLogout": false, "protocol": "openid-connect", - "attributes": {}, + "attributes": { + "realm_client": "true", + "post.logout.redirect.uris": "+" + }, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, { - "clientId": "kogito-frontend", - "rootUrl": "http://localhost:8082", - "adminUrl": "http://localhost:8082", + "id": "81da65bd-9e3f-4a90-8a36-52a687c49acb", + "clientId": "management-console-dev-webapp-runtime", + "name": "Management Console Dev webapp Runtime", + "description": "", + "rootUrl": "http://localhost:8080", + "adminUrl": "", + "baseUrl": "http://localhost:8080", "surrogateAuthRequired": false, "enabled": true, + "alwaysDisplayInConsole": true, "clientAuthenticatorType": "client-secret", - "secret": "secret", - "redirectUris": ["http://localhost:8082/*"], - "webOrigins": ["http://localhost:8082"], + "redirectUris": ["http://localhost:8080/*"], + "webOrigins": ["http://localhost:8080"], "notBefore": 0, "bearerOnly": false, "consentRequired": false, @@ -432,45 +628,38 @@ "implicitFlowEnabled": false, "directAccessGrantsEnabled": true, "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, + "publicClient": true, + "frontchannelLogout": true, "protocol": "openid-connect", "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", - "saml_force_name_id_format": "false", - "saml.client.signature": "false", - "tls.client.certificate.bound.access.tokens": "false", - "saml.authnstatement": "false", + "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "post.logout.redirect.uris": "http://localhost:8080/*", + "oauth2.device.authorization.grant.enabled": "false", "display.on.consent.screen": "false", - "saml.onetimeuse.condition": "false" + "backchannel.logout.revoke.offline.tokens": "false" }, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": true, "nodeReRegistrationTimeout": -1, - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"], - "access": { - "view": true, - "configure": true, - "manage": true - } + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, { - "clientId": "kogito-app", - "rootUrl": "http://localhost:8080", - "adminUrl": "http://localhost:8080", + "id": "d338df06-b8ce-4385-9b1e-e6c35353888b", + "clientId": "management-console-dev-webapp", + "name": "Management Console Webapp", + "description": "", + "rootUrl": "http://localhost:9025", + "adminUrl": "", + "baseUrl": "http://localhost:9025", "surrogateAuthRequired": false, "enabled": true, + "alwaysDisplayInConsole": true, "clientAuthenticatorType": "client-secret", - "secret": "secret", - "redirectUris": ["http://localhost:8080/*"], - "webOrigins": ["*"], + "redirectUris": ["http://localhost:9025/*"], + "webOrigins": ["http://localhost:9025"], "notBefore": 0, "bearerOnly": false, "consentRequired": false, @@ -478,320 +667,32 @@ "implicitFlowEnabled": false, "directAccessGrantsEnabled": true, "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, + "publicClient": true, + "frontchannelLogout": true, "protocol": "openid-connect", "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", - "saml_force_name_id_format": "false", - "saml.client.signature": "false", - "tls.client.certificate.bound.access.tokens": "false", - "saml.authnstatement": "false", + "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "post.logout.redirect.uris": "http://localhost:9025/*", + "oauth2.device.authorization.grant.enabled": "false", "display.on.consent.screen": "false", - "saml.onetimeuse.condition": "false" + "backchannel.logout.revoke.offline.tokens": "false" }, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": true, "nodeReRegistrationTimeout": -1, - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"], - "access": { - "view": true, - "configure": true, - "manage": true - } - }, - { - "clientId": "kogito-service", - "rootUrl": "", - "surrogateAuthRequired": false, - "enabled": true, - "clientAuthenticatorType": "client-secret", - "secret": "secret", - "redirectUris": ["*"], - "webOrigins": ["*"], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": true, - "authorizationServicesEnabled": true, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": {}, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "protocolMappers": [ - { - "name": "Client ID", - "protocol": "openid-connect", - "protocolMapper": "oidc-usersessionmodel-note-mapper", - "consentRequired": false, - "config": { - "user.session.note": "clientId", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "clientId", - "jsonType.label": "String" - } - }, - { - "name": "Client IP Address", - "protocol": "openid-connect", - "protocolMapper": "oidc-usersessionmodel-note-mapper", - "consentRequired": false, - "config": { - "user.session.note": "clientAddress", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "clientAddress", - "jsonType.label": "String" - } - }, - { - "name": "Client Host", - "protocol": "openid-connect", - "protocolMapper": "oidc-usersessionmodel-note-mapper", - "consentRequired": false, - "config": { - "user.session.note": "clientHost", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "clientHost", - "jsonType.label": "String" - } - } - ], - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"], - "authorizationSettings": { - "allowRemoteResourceManagement": true, - "policyEnforcementMode": "ENFORCING", - "resources": [ - { - "name": "User Resource", - "ownerManagedAccess": false, - "attributes": {}, - "_id": "df1b74a9-3f10-499d-a581-368de48e512b", - "uris": ["/api/users/*"] - }, - { - "name": "Administration Resource", - "ownerManagedAccess": false, - "attributes": {}, - "_id": "7124e2f1-e6dc-44b4-87ab-24b010090b97", - "uris": ["/api/admin/*"] - } - ], - "policies": [ - { - "name": "Any User Policy", - "description": "Any user granted with the user role can access something", - "type": "role", - "logic": "POSITIVE", - "decisionStrategy": "UNANIMOUS", - "config": { - "roles": "[{\"id\":\"user\",\"required\":false}]" - } - }, - { - "name": "Only Administrators", - "description": "Only administrators can access", - "type": "role", - "logic": "POSITIVE", - "decisionStrategy": "UNANIMOUS", - "config": { - "roles": "[{\"id\":\"admin\",\"required\":false}]" - } - }, - { - "name": "User Resource Permission", - "type": "resource", - "logic": "POSITIVE", - "decisionStrategy": "UNANIMOUS", - "config": { - "resources": "[\"User Resource\"]", - "applyPolicies": "[\"Any User Policy\"]" - } - }, - { - "name": "Administration Resource Permission", - "type": "resource", - "logic": "POSITIVE", - "decisionStrategy": "UNANIMOUS", - "config": { - "resources": "[\"Administration Resource\"]", - "applyPolicies": "[\"Only Administrators\"]" - } - } - ], - "scopes": [], - "decisionStrategy": "UNANIMOUS" - } - }, - { - "clientId": "kogito-console-react", - "rootUrl": "http://localhost:9026", - "adminUrl": "http://localhost:9026/", - "baseUrl": "http://localhost:9026/", - "surrogateAuthRequired": false, - "enabled": true, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": ["http://localhost:9026/*"], - "webOrigins": ["*"], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", - "saml_force_name_id_format": "false", - "saml.client.signature": "false", - "tls.client.certificate.bound.access.tokens": "false", - "saml.authnstatement": "false", - "display.on.consent.screen": "false", - "saml.onetimeuse.condition": "false" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] - }, - { - "clientId": "kogito-console-quarkus", - "rootUrl": "http://localhost:8380", - "adminUrl": "http://localhost:8380/", - "baseUrl": "http://localhost:8380/", - "surrogateAuthRequired": false, - "enabled": true, - "clientAuthenticatorType": "client-secret", - "secret": "**********", - "redirectUris": ["http://localhost:8380/*"], - "webOrigins": ["*"], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": false, - "serviceAccountsEnabled": false, - "publicClient": true, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", - "saml_force_name_id_format": "false", - "saml.client.signature": "false", - "tls.client.certificate.bound.access.tokens": "false", - "saml.authnstatement": "false", - "display.on.consent.screen": "false", - "saml.onetimeuse.condition": "false" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "protocolMappers": [ - { - "name": "groups", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "multivalued": "true", - "user.attribute": "foo", - "id.token.claim": "true", - "access.token.claim": "true", - "claim.name": "groups", - "jsonType.label": "String" - } - } - ], - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] - }, - { - "clientId": "kogito-jobs-service", - "rootUrl": "http://localhost:8080", - "adminUrl": "http://localhost:8080", - "surrogateAuthRequired": false, - "enabled": true, - "clientAuthenticatorType": "client-secret", - "secret": "secret", - "redirectUris": ["http://localhost:8080/*"], - "webOrigins": ["http://localhost:8080"], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", - "saml_force_name_id_format": "false", - "saml.client.signature": "false", - "tls.client.certificate.bound.access.tokens": "false", - "saml.authnstatement": "false", - "display.on.consent.screen": "false", - "saml.onetimeuse.condition": "false" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"], - "access": { - "view": true, - "configure": true, - "manage": true - } + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, { + "id": "837e0b7e-6f80-4c3c-83e7-1274787fa2e9", "clientId": "realm-management", "name": "${client_realm-management}", "surrogateAuthRequired": false, "enabled": true, + "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", - "secret": "c41b709a-a012-4c69-89d7-4f926dba0619", "redirectUris": [], "webOrigins": [], "notBefore": 0, @@ -804,23 +705,28 @@ "publicClient": false, "frontchannelLogout": false, "protocol": "openid-connect", - "attributes": {}, + "attributes": { + "realm_client": "true", + "post.logout.redirect.uris": "+" + }, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": false, "nodeReRegistrationTimeout": 0, - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, { + "id": "ac98e892-04de-4fff-8c73-e460848d01b8", "clientId": "security-admin-console", "name": "${client_security-admin-console}", - "baseUrl": "/auth/admin/kogito/console/index.html", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/dev-management-console/console/", "surrogateAuthRequired": false, "enabled": true, + "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", - "secret": "e571b211-2550-475d-b87f-116ff54091ee", - "redirectUris": ["/auth/admin/kogito/console/*"], - "webOrigins": [], + "redirectUris": ["/admin/dev-management-console/console/*"], + "webOrigins": ["+"], "notBefore": 0, "bearerOnly": false, "consentRequired": false, @@ -831,17 +737,24 @@ "publicClient": true, "frontchannelLogout": false, "protocol": "openid-connect", - "attributes": {}, + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": false, + "fullScopeAllowed": true, "nodeReRegistrationTimeout": 0, "protocolMappers": [ { + "id": "c0e21caa-5eae-4a37-9b11-457a68c4cd7c", "name": "locale", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", "user.attribute": "locale", "id.token.claim": "true", @@ -851,22 +764,43 @@ } } ], - "defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"], - "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"] + "defaultClientScopes": ["web-origins", "acr", "roles", "profile", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] } ], "clientScopes": [ { + "id": "c9eaac81-fd04-4fa7-a434-5f088ff38899", + "name": "saml_organization", + "description": "Organization Membership", + "protocol": "saml", + "attributes": { + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "790ee107-e6fd-4cec-bc18-3f162e7d7157", + "name": "organization", + "protocol": "saml", + "protocolMapper": "saml-organization-membership-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "49b0cf75-efcc-4afb-94f4-d6f419d2d703", "name": "address", "description": "OpenID Connect built-in scope: address", "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${addressScopeConsentText}" + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { + "id": "94b173c6-57e1-4b80-a4a5-21cc5adf2bd2", "name": "address", "protocol": "openid-connect", "protocolMapper": "oidc-address-mapper", @@ -874,6 +808,7 @@ "config": { "user.attribute.formatted": "formatted", "user.attribute.country": "country", + "introspection.token.claim": "true", "user.attribute.postal_code": "postal_code", "userinfo.token.claim": "true", "user.attribute.street": "street", @@ -886,21 +821,65 @@ ] }, { + "id": "5bed0250-89ef-4c60-9743-bbbcfb34ddfc", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "60487308-1bc8-4466-b9de-f91fb325cb6a", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "00eff690-aa70-4208-97c0-dbee0633b382", "name": "email", "description": "OpenID Connect built-in scope: email", "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${emailScopeConsentText}" + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { - "name": "email", + "id": "c83644d5-9ad0-4b37-ba41-2e0d7bd101e0", + "name": "email verified", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-property-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "e7a59895-e505-43fc-a386-1f2f75c94424", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", "user.attribute": "email", "id.token.claim": "true", @@ -908,63 +887,148 @@ "claim.name": "email", "jsonType.label": "String" } - }, + } + ] + }, + { + "id": "e473e3fd-77fc-4ba3-b417-45815ab6e424", + "name": "organization", + "description": "Additional claims about the organization a subject belongs to", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${organizationScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ { - "name": "email verified", + "id": "487fe61f-b88c-42c7-a511-b66a981206e7", + "name": "organization", "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", + "protocolMapper": "oidc-organization-membership-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", + "multivalued": "true", "userinfo.token.claim": "true", - "user.attribute": "emailVerified", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "email_verified", - "jsonType.label": "boolean" + "claim.name": "organization", + "jsonType.label": "String" } } ] }, { - "name": "microprofile-jwt", - "description": "Microprofile - JWT built-in scope", + "id": "9b2cf5eb-ce78-489c-b9a5-2ed88be13ccf", + "name": "basic", + "description": "OpenID Connect scope for add all basic claims to the token", "protocol": "openid-connect", "attributes": { - "include.in.token.scope": "true", + "include.in.token.scope": "false", "display.on.consent.screen": "false" }, "protocolMappers": [ { - "name": "upn", + "id": "76d33319-65ad-4ddd-b634-519fb4eb3afe", + "name": "auth_time", "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", + "protocolMapper": "oidc-usersessionmodel-note-mapper", "consentRequired": false, "config": { + "user.session.note": "AUTH_TIME", + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "username", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "upn", - "jsonType.label": "String" + "claim.name": "auth_time", + "jsonType.label": "long" } }, { - "name": "groups", + "id": "a960e80b-c647-4126-8f24-f15848b4a3b7", + "name": "sub", "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", + "protocolMapper": "oidc-sub-mapper", "consentRequired": false, "config": { - "multivalued": "true", - "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "6a12ce81-1178-4523-b418-8511cf0735fe", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "138161de-9420-42c3-8643-7d8572ad7b79", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "fe2f95fa-ecbe-4bad-b5a0-9dcfc454000c", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${phoneScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "6068e4aa-0ee6-4484-b2d1-f19328b2ef57", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "groups", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "1d9861d3-affc-43ae-8f75-fe1d1954b7a0", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", "jsonType.label": "String" } } ] }, { + "id": "36206eca-eb73-46e6-9654-ec866bd5089b", "name": "offline_access", "description": "OpenID Connect built-in scope: offline_access", "protocol": "openid-connect", @@ -974,240 +1038,352 @@ } }, { - "name": "phone", - "description": "OpenID Connect built-in scope: phone", + "id": "94011eab-2af7-4be0-8578-7f1d1ff1a568", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "ad389df7-6f06-403c-94df-5f742c45ac61", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "5f9db7d0-7ed8-41c9-9b2d-3be5fe0b138f", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "afe75a0e-376b-4e07-9ceb-63ee89a25155", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "db204d4b-8592-4e10-9f0a-6a7ed203d733", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "309c5dc1-20e6-447c-87d8-72ee08f46ebd", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "a0507390-c147-4960-a956-8a27d53a4992", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${phoneScopeConsentText}" + "display.on.consent.screen": "false" }, "protocolMappers": [ { - "name": "phone number verified", + "id": "00b2daad-1aca-4c2c-a6b8-1daef55c7e98", + "name": "groups", "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", + "protocolMapper": "oidc-usermodel-realm-role-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", + "multivalued": "true", "userinfo.token.claim": "true", - "user.attribute": "phoneNumberVerified", + "user.attribute": "foo", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "phone_number_verified", - "jsonType.label": "boolean" + "claim.name": "groups", + "jsonType.label": "String" } }, { - "name": "phone number", + "id": "04a79477-57e0-4cb8-911d-229e14627f0c", + "name": "upn", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "phoneNumber", + "user.attribute": "username", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "phone_number", + "claim.name": "upn", "jsonType.label": "String" } } ] }, { + "id": "55921623-7736-4140-ae53-fcc7c497491f", "name": "profile", "description": "OpenID Connect built-in scope: profile", "protocol": "openid-connect", "attributes": { "include.in.token.scope": "true", - "display.on.consent.screen": "true", - "consent.screen.text": "${profileScopeConsentText}" + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" }, "protocolMappers": [ { - "name": "nickname", + "id": "2d6fab16-129f-4103-bce2-0ad078eb629e", + "name": "locale", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "nickname", + "user.attribute": "locale", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "nickname", + "claim.name": "locale", "jsonType.label": "String" } }, { - "name": "zoneinfo", + "id": "048c5178-f818-4506-bfd1-d22b43c5009e", + "name": "given name", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "zoneinfo", + "user.attribute": "firstName", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "zoneinfo", + "claim.name": "given_name", "jsonType.label": "String" } }, { - "name": "updated at", + "id": "c6d2835b-abd5-4cf9-ba59-e672770cdd81", + "name": "middle name", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "updatedAt", + "user.attribute": "middleName", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "updated_at", + "claim.name": "middle_name", "jsonType.label": "String" } }, { - "name": "birthdate", + "id": "91347c26-83be-49ee-b89d-98c49a43f78d", + "name": "zoneinfo", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "birthdate", + "user.attribute": "zoneinfo", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "birthdate", + "claim.name": "zoneinfo", "jsonType.label": "String" } }, { - "name": "given name", + "id": "3d809903-8d18-4591-adda-62604fba8dcc", + "name": "full name", "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", + "protocolMapper": "oidc-full-name-mapper", "consentRequired": false, "config": { - "userinfo.token.claim": "true", - "user.attribute": "firstName", "id.token.claim": "true", + "introspection.token.claim": "true", "access.token.claim": "true", - "claim.name": "given_name", - "jsonType.label": "String" + "userinfo.token.claim": "true" } }, { - "name": "full name", + "id": "bb607cb9-8791-4dbf-9e0d-33746dccfe49", + "name": "picture", "protocol": "openid-connect", - "protocolMapper": "oidc-full-name-mapper", + "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "picture", "id.token.claim": "true", "access.token.claim": "true", - "userinfo.token.claim": "true" + "claim.name": "picture", + "jsonType.label": "String" } }, { - "name": "middle name", + "id": "b644a6ca-429d-455d-bd38-2ab1cc86454b", + "name": "family name", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "middleName", + "user.attribute": "lastName", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "middle_name", + "claim.name": "family_name", "jsonType.label": "String" } }, { - "name": "username", + "id": "967c73cf-5307-47d6-be57-8cd8a3e260c0", + "name": "updated at", "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", + "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "username", + "user.attribute": "updatedAt", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "preferred_username", - "jsonType.label": "String" + "claim.name": "updated_at", + "jsonType.label": "long" } }, { - "name": "family name", + "id": "aa326992-5421-4568-9caf-52a99b500c1c", + "name": "nickname", "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-property-mapper", + "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "lastName", + "user.attribute": "nickname", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "family_name", + "claim.name": "nickname", "jsonType.label": "String" } }, { - "name": "gender", + "id": "73f18549-ddcd-45e6-8aaf-365e5dd2fdb6", + "name": "profile", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "gender", + "user.attribute": "profile", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "gender", + "claim.name": "profile", "jsonType.label": "String" } }, { - "name": "picture", + "id": "1221fff1-bbb0-4787-b12f-e0701d75bf20", + "name": "gender", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "picture", + "user.attribute": "gender", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "picture", + "claim.name": "gender", "jsonType.label": "String" } }, { - "name": "locale", + "id": "b660b429-3fe2-4f32-b455-2d3306f39ead", + "name": "birthdate", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "locale", + "user.attribute": "birthdate", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "locale", + "claim.name": "birthdate", "jsonType.label": "String" } }, { - "name": "profile", + "id": "2cfcb51d-353e-43a2-a3e0-2558f685b386", + "name": "username", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", - "user.attribute": "profile", + "user.attribute": "username", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "profile", + "claim.name": "preferred_username", "jsonType.label": "String" } }, { + "id": "e044a6c5-fbd9-48b6-b57e-131c1173e889", "name": "website", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "consentRequired": false, "config": { + "introspection.token.claim": "true", "userinfo.token.claim": "true", "user.attribute": "website", "id.token.claim": "true", @@ -1217,103 +1393,27 @@ } } ] - }, - { - "name": "role_list", - "description": "SAML role list", - "protocol": "saml", - "attributes": { - "consent.screen.text": "${samlRoleListScopeConsentText}", - "display.on.consent.screen": "true" - }, - "protocolMappers": [ - { - "name": "role list", - "protocol": "saml", - "protocolMapper": "saml-role-list-mapper", - "consentRequired": false, - "config": { - "single": "false", - "attribute.nameformat": "Basic", - "attribute.name": "Role" - } - } - ] - }, - { - "name": "roles", - "description": "OpenID Connect scope for add user roles to the access token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "true", - "consent.screen.text": "${rolesScopeConsentText}" - }, - "protocolMappers": [ - { - "name": "realm roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-realm-role-mapper", - "consentRequired": false, - "config": { - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "realm_access.roles", - "jsonType.label": "String", - "multivalued": "true" - } - }, - { - "name": "audience resolve", - "protocol": "openid-connect", - "protocolMapper": "oidc-audience-resolve-mapper", - "consentRequired": false, - "config": {} - }, - { - "name": "client roles", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-client-role-mapper", - "consentRequired": false, - "config": { - "user.attribute": "foo", - "access.token.claim": "true", - "claim.name": "resource_access.${client_id}.roles", - "jsonType.label": "String", - "multivalued": "true" - } - } - ] - }, - { - "name": "web-origins", - "description": "OpenID Connect scope for add allowed web origins to the access token", - "protocol": "openid-connect", - "attributes": { - "include.in.token.scope": "false", - "display.on.consent.screen": "false", - "consent.screen.text": "" - }, - "protocolMappers": [ - { - "name": "allowed web origins", - "protocol": "openid-connect", - "protocolMapper": "oidc-allowed-origins-mapper", - "consentRequired": false, - "config": {} - } - ] } ], - "defaultDefaultClientScopes": ["role_list", "profile", "email", "roles", "web-origins"], - "defaultOptionalClientScopes": ["offline_access", "address", "phone", "microprofile-jwt"], + "defaultDefaultClientScopes": [ + "role_list", + "saml_organization", + "profile", + "email", + "roles", + "web-origins", + "acr", + "basic" + ], + "defaultOptionalClientScopes": ["offline_access", "address", "phone", "microprofile-jwt", "organization"], "browserSecurityHeaders": { "contentSecurityPolicyReportOnly": "", "xContentTypeOptions": "nosniff", + "referrerPolicy": "no-referrer", "xRobotsTag": "none", "xFrameOptions": "SAMEORIGIN", - "xXSSProtection": "1; mode=block", "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", "strictTransportSecurity": "max-age=31536000; includeSubDomains" }, "smtpServer": {}, @@ -1322,36 +1422,12 @@ "enabledEventTypes": [], "adminEventsEnabled": false, "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], "components": { "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ { - "name": "Allowed Protocol Mapper Types", - "providerId": "allowed-protocol-mappers", - "subType": "anonymous", - "subComponents": {}, - "config": { - "allowed-protocol-mapper-types": [ - "oidc-full-name-mapper", - "saml-user-attribute-mapper", - "saml-user-property-mapper", - "oidc-address-mapper", - "saml-role-list-mapper", - "oidc-sha256-pairwise-sub-mapper", - "oidc-usermodel-attribute-mapper", - "oidc-usermodel-property-mapper" - ] - } - }, - { - "name": "Allowed Client Scopes", - "providerId": "allowed-client-templates", - "subType": "authenticated", - "subComponents": {}, - "config": { - "allow-default-scopes": ["true"] - } - }, - { + "id": "85aced3c-b87f-4847-8235-7c58aa32233d", "name": "Allowed Client Scopes", "providerId": "allowed-client-templates", "subType": "anonymous", @@ -1361,6 +1437,7 @@ } }, { + "id": "d2e6312f-ea3a-4be9-a98a-196e93a8e8fa", "name": "Trusted Hosts", "providerId": "trusted-hosts", "subType": "anonymous", @@ -1371,13 +1448,7 @@ } }, { - "name": "Full Scope Disabled", - "providerId": "scope", - "subType": "anonymous", - "subComponents": {}, - "config": {} - }, - { + "id": "6cc905d8-7114-45f0-be24-b40b7abd31c3", "name": "Max Clients Limit", "providerId": "max-clients", "subType": "anonymous", @@ -1387,6 +1458,7 @@ } }, { + "id": "6ae6bf4e-1d5b-4baf-aa6b-c7651933a777", "name": "Consent Required", "providerId": "consent-required", "subType": "anonymous", @@ -1394,58 +1466,99 @@ "config": {} }, { + "id": "1eee1eca-b834-4aff-867a-cc5737b21076", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "7a63be91-8f04-476d-8357-b94b73290d35", "name": "Allowed Protocol Mapper Types", "providerId": "allowed-protocol-mappers", "subType": "authenticated", "subComponents": {}, "config": { "allowed-protocol-mapper-types": [ + "oidc-full-name-mapper", "saml-user-attribute-mapper", + "saml-user-property-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "oidc-usermodel-attribute-mapper", + "saml-role-list-mapper", + "oidc-sha256-pairwise-sub-mapper" + ] + } + }, + { + "id": "e0570fa1-ec5c-4742-9aa7-6c5e0c86c7af", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "65085019-d4e4-47a6-9665-fa7687270afd", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-property-mapper", "oidc-full-name-mapper", + "saml-user-attribute-mapper", "saml-role-list-mapper", - "saml-user-property-mapper", - "oidc-usermodel-attribute-mapper", "oidc-address-mapper", - "oidc-usermodel-property-mapper", - "oidc-sha256-pairwise-sub-mapper" + "oidc-usermodel-attribute-mapper" ] } } ], "org.keycloak.keys.KeyProvider": [ { + "id": "ec44fea6-5c73-43d1-ad15-6e3efdea64ab", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": ["100"] + } + }, + { + "id": "04113a08-7361-4ab8-babc-92e399be0e69", "name": "rsa-generated", "providerId": "rsa-generated", "subComponents": {}, "config": { - "privateKey": [ - "MIIEowIBAAKCAQEAn5T13suF8mlS+pJXp0U1bto41nW55wpcs+Rps8ZVCRyJKWqzwSCYnI7lm0rB2wBpAAO4OPoj1zlmVoFmBPsDU9Xf7rjsJb5LIzIQDCZY44aSDZt6RR+gakPiQvlzHyW/RozYpngDJF7TsTD7rdRF1xQ4RprfBF8fwK/xsU7pxbeom5xDHZhz3fiw8s+7UdbmnazDHfAjU58aUrLGgVRfUsuoHjtsptYlOIXEifaeMetXZE+HhqLYRHQPDap5fbBJl773Trosn7N9nmzN4x1xxGj9So21WC5UboQs9sAIVgizc4omjZ5Y4RN9HLH7G4YwJctNntzmnJhDui9zAO+zSQIDAQABAoIBADi+F7rTtVoft0Cfnok8o6Y58/HVxHdxiMryUd95iy0FN4RBi48FTx6D9QKFz25Ws/8sU2n3D51srIXf1u24b1N0/f39RQKaqk7mcyxOylaEuBQcj5pah4ihgKd92UBfBKdKV5LBo6RgD3e2yhbiHr8+UlBQqzH7vOef6Bm6zIbfmi3N88swAJhP0YizRZFklsbmLsK6nkwyro00CHJvPVKSBbM+ad+/zIBsLw56MvNngB5TuFguUgoljd6M1T2z4utmZGlTUqrfE1onAVLJZoGnRohyIr7dJEg6YxWR70PxsgmkDKyeRvet9P1trO0n+OSprusfrC3cHJStabap1V0CgYEA1A/CtsqTnjdYYsB19eumZgdpzUgNc/YEAzZ/OWb8yTLoB2ncci+63A1rXHUXAqJFY7vtjn5mxv7SuASNbUrzq+6KfZvC1x9XEtnczqT/ypunNfxmIZuj8Nuu6vtURguZ8kPPwdkI8toTizRFeRE5ZDBvoQryiEVYugfHaHT5vzsCgYEAwKWODwquI0Lv9BuwdNVrBXQpkKh3ZfYOA7i9xvhxlM7xUu8OMCwwCPn3r7vrW5APjTqX4h330mJ44SLEs+7gbCUs4BbJBLA6g0ChlHa9PTkxp6tk2nDF/B34fxiZSRkE85L+d+at0Dc3hnlzLCJCzJawGpoPniPU9e4w0p4dN0sCgYAsGnMGjS8SUrRhJWHjGXVr9tK8TOXvXhULjgP7rj2Yoqu7Dvs4DFEyft/7RKbad2EzEtyfLA64CDtO5jN7rYDsGxpWcVSeZPg5BXJ0z8AbJTArfCjJiJMZ/rZsTIUEZFlKF2xYBolj6JLz+pUQTtK+0YwF1D8ItFN1rTR9twZSDQKBgQC6sPXNX+VH6LuPTjIf1x8CxwLs3EXxOpV0R9kp9GRl+HJnk6GlT30xhcThufQo5KAdllXQXIhoiuNoEoCbevhj9Vbax1oBQCNERSMRNEzKAx46xd9TzYwgeo7x5E3QR/3DaoVOfu+cY5ZcrF/PulgP2kxJS1mtQD5GIpGP2oinpwKBgGqiqTFPqRcelx76vBvTU+Jp1zM62T4AotbMrSQR/oUvqHe5Ytj/SbZx+wbbHAiyGgV700Mosyviik83YEAbR3kdOPjgYvAJJW2Y3jEMdQ7MwriXz8XLh5BGmYfVjkSOJXed9ua9WlYLKOJeXXv191BbDvrx5NXuJyVVU4vJx3YZ" - ], - "certificate": [ - "MIICnTCCAYUCBgFp4EYIrjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdwcm90ZWFuMB4XDTE5MDQwMjIyNTYxOVoXDTI5MDQwMjIyNTc1OVowEjEQMA4GA1UEAwwHcHJvdGVhbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ+U9d7LhfJpUvqSV6dFNW7aONZ1uecKXLPkabPGVQkciSlqs8EgmJyO5ZtKwdsAaQADuDj6I9c5ZlaBZgT7A1PV3+647CW+SyMyEAwmWOOGkg2bekUfoGpD4kL5cx8lv0aM2KZ4AyRe07Ew+63URdcUOEaa3wRfH8Cv8bFO6cW3qJucQx2Yc934sPLPu1HW5p2swx3wI1OfGlKyxoFUX1LLqB47bKbWJTiFxIn2njHrV2RPh4ai2ER0Dw2qeX2wSZe+9066LJ+zfZ5szeMdccRo/UqNtVguVG6ELPbACFYIs3OKJo2eWOETfRyx+xuGMCXLTZ7c5pyYQ7ovcwDvs0kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAVtmRKDb4OK5iSA46tagMBkp6L7WuPpCWuHGWwobEP+BecYsShW7zP3s12oA8SNSwbhvu0CRqgzxhuypgf3hKQFVU153Erv4hzkj+8S0s5LR/ZE7tDNY2lzJ3yQKXy3Md7EkuzzvOZ50MTrcSKAanWq/ZW1OTnrtGymj5zGJnTg7mMnJzEIGePxkvPu/QdchiPBLqxfZYm1jsFGY25djOC3N/KmVcRVmPRGuu6D8tBFHlKoPfZYPdbMvsvs24aupHKRcZ+ofTCpK+2Qo8c0pSSqeEYHGmuGqC6lC6ozxtxSABPO9Q1R1tZBU7Kg5HvXUwwmoVS3EGub46YbHqbmWMLg==" - ], "priority": ["100"] } }, { - "name": "hmac-generated", + "id": "1363f4aa-ae06-4a55-9376-c31f7c0f0201", + "name": "hmac-generated-hs512", "providerId": "hmac-generated", "subComponents": {}, "config": { - "kid": ["96afd00e-85cf-4d35-b18e-061d3813d8b2"], - "secret": ["qBFGKdUGf6xDgKphnRfoFzIzaFHJW4bYnZ9MinPFzN38X5_ctq-2u1q5RdZzeJukXvk2biHB8_s3DxWmmLZFsA"], "priority": ["100"], - "algorithm": ["HS256"] + "algorithm": ["HS512"] } }, { - "name": "aes-generated", - "providerId": "aes-generated", + "id": "5c94fa75-8150-4db7-aa6e-da88d67c1474", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", "subComponents": {}, "config": { - "kid": ["b04473d3-8395-4016-b455-19a9e951106b"], - "secret": ["x68mMOVdz3qKWzltzReV0g"], - "priority": ["100"] + "priority": ["100"], + "algorithm": ["RSA-OAEP"] } } ] @@ -1454,6 +1567,163 @@ "supportedLocales": [], "authenticationFlows": [ { + "id": "46c6ed70-ee65-46a2-a1fd-2371e14e0ec5", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "d2999497-dbc3-42d2-8be8-5148004546bd", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "cc5d143a-0ac4-42f9-897f-63aec02ab021", + "alias": "Browser - Conditional Organization", + "description": "Flow to determine if the organization identity-first login is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "organization", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "428b8da2-05e2-4601-b6c7-0aab7aa1bb11", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "5117692c-3fbe-4045-b65c-271ae79e2344", + "alias": "First Broker Login - Conditional Organization", + "description": "Flow to determine if the authenticator that adds organization members is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "idp-add-organization-member", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "8f94ad36-511b-43ed-85fb-85b617669288", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "099f500e-395a-4879-a72e-4c3cee6888d1", "alias": "Handle Existing Account", "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", "providerId": "basic-flow", @@ -1462,28 +1732,94 @@ "authenticationExecutions": [ { "authenticator": "idp-confirm-link", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { - "authenticator": "idp-email-verification", - "requirement": "ALTERNATIVE", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "26014e3f-0690-484f-9fa8-dbed734a820f", + "alias": "Organization", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional Organization", + "userSetupAllowed": false + } + ] + }, + { + "id": "c7c1227b-f12b-43a7-b9b3-74bd91394119", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "3e8053bb-b083-49f3-8d76-c634e9eb00f6", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false }, { + "authenticatorFlow": true, "requirement": "ALTERNATIVE", - "priority": 30, - "flowAlias": "Verify Existing Account by Re-authentication", - "userSetupAllowed": false, - "autheticatorFlow": true + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false } ] }, { + "id": "b407482e-7d44-4822-81af-4db07d2f5dbd", "alias": "Verify Existing Account by Re-authentication", "description": "Reauthentication of existing account", "providerId": "basic-flow", @@ -1492,58 +1828,74 @@ "authenticationExecutions": [ { "authenticator": "idp-username-password-form", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { - "authenticator": "auth-otp-form", - "requirement": "OPTIONAL", + "authenticatorFlow": true, + "requirement": "CONDITIONAL", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false } ] }, { + "id": "85139a07-dfcb-4572-adf3-d15b5cca05cb", "alias": "browser", - "description": "browser based authentication", + "description": "Browser based authentication", "providerId": "basic-flow", "topLevel": true, "builtIn": true, "authenticationExecutions": [ { "authenticator": "auth-cookie", + "authenticatorFlow": false, "requirement": "ALTERNATIVE", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "auth-spnego", + "authenticatorFlow": false, "requirement": "DISABLED", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, "requirement": "ALTERNATIVE", "priority": 25, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 26, + "autheticatorFlow": true, + "flowAlias": "Organization", + "userSetupAllowed": false }, { + "authenticatorFlow": true, "requirement": "ALTERNATIVE", "priority": 30, + "autheticatorFlow": true, "flowAlias": "forms", - "userSetupAllowed": false, - "autheticatorFlow": true + "userSetupAllowed": false } ] }, { + "id": "ed27884b-ffd1-474b-bbd0-39fdaecd51b8", "alias": "clients", "description": "Base authentication for clients", "providerId": "client-flow", @@ -1552,35 +1904,40 @@ "authenticationExecutions": [ { "authenticator": "client-secret", + "authenticatorFlow": false, "requirement": "ALTERNATIVE", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "client-jwt", + "authenticatorFlow": false, "requirement": "ALTERNATIVE", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "client-secret-jwt", + "authenticatorFlow": false, "requirement": "ALTERNATIVE", "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "client-x509", + "authenticatorFlow": false, "requirement": "ALTERNATIVE", "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, { + "id": "4b2df228-c9e5-4467-b1f7-bd93ddadca7f", "alias": "direct grant", "description": "OpenID Connect Resource Owner Grant", "providerId": "basic-flow", @@ -1589,28 +1946,32 @@ "authenticationExecutions": [ { "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { - "authenticator": "direct-grant-validate-otp", - "requirement": "OPTIONAL", + "authenticatorFlow": true, + "requirement": "CONDITIONAL", "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false } ] }, { + "id": "2071d972-f952-4f71-a940-c892fe4d5f59", "alias": "docker auth", "description": "Used by Docker clients to authenticate against the IDP", "providerId": "basic-flow", @@ -1619,14 +1980,16 @@ "authenticationExecutions": [ { "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, { + "id": "1f1445ea-00d7-4a86-ac66-331d95b2eec0", "alias": "first broker login", "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", "providerId": "basic-flow", @@ -1636,29 +1999,32 @@ { "authenticatorConfig": "review profile config", "authenticator": "idp-review-profile", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { - "authenticatorConfig": "create unique user config", - "authenticator": "idp-create-user-if-unique", - "requirement": "ALTERNATIVE", + "authenticatorFlow": true, + "requirement": "REQUIRED", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false }, { - "requirement": "ALTERNATIVE", - "priority": 30, - "flowAlias": "Handle Existing Account", - "userSetupAllowed": false, - "autheticatorFlow": true + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 50, + "autheticatorFlow": true, + "flowAlias": "First Broker Login - Conditional Organization", + "userSetupAllowed": false } ] }, { + "id": "299df424-e42d-466c-8df4-af95d55cdfbd", "alias": "forms", "description": "Username, password, otp and other auth forms.", "providerId": "basic-flow", @@ -1667,112 +2033,85 @@ "authenticationExecutions": [ { "authenticator": "auth-username-password-form", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "auth-otp-form", - "requirement": "OPTIONAL", - "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - } - ] - }, - { - "alias": "http challenge", - "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", - "providerId": "basic-flow", - "topLevel": true, - "builtIn": true, - "authenticationExecutions": [ - { - "authenticator": "no-cookie-redirect", - "requirement": "REQUIRED", - "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { - "authenticator": "basic-auth", - "requirement": "REQUIRED", + "authenticatorFlow": true, + "requirement": "CONDITIONAL", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "basic-auth-otp", - "requirement": "DISABLED", - "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "auth-spnego", - "requirement": "DISABLED", - "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false } ] }, { + "id": "ed1921d3-c5a1-4df7-9e88-3b80e465ec30", "alias": "registration", - "description": "registration flow", + "description": "Registration flow", "providerId": "basic-flow", "topLevel": true, "builtIn": true, "authenticationExecutions": [ { "authenticator": "registration-page-form", + "authenticatorFlow": true, "requirement": "REQUIRED", "priority": 10, + "autheticatorFlow": true, "flowAlias": "registration form", - "userSetupAllowed": false, - "autheticatorFlow": true + "userSetupAllowed": false } ] }, { + "id": "d4940941-f744-4061-9856-0e78c8757761", "alias": "registration form", - "description": "registration form", + "description": "Registration form", "providerId": "form-flow", "topLevel": false, "builtIn": true, "authenticationExecutions": [ { "authenticator": "registration-user-creation", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false - }, - { - "authenticator": "registration-profile-action", - "requirement": "REQUIRED", - "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "registration-password-action", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 50, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, "requirement": "DISABLED", "priority": 60, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-terms-and-conditions", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 70, + "autheticatorFlow": false, + "userSetupAllowed": false } ] }, { + "id": "27c8e661-d81a-4250-8d73-3d0d6c64a692", "alias": "reset credentials", "description": "Reset credentials for a user if they forgot their password or something", "providerId": "basic-flow", @@ -1781,35 +2120,40 @@ "authenticationExecutions": [ { "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "reset-credential-email", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 20, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { "authenticator": "reset-password", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 30, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false }, { - "authenticator": "reset-otp", - "requirement": "OPTIONAL", + "authenticatorFlow": true, + "requirement": "CONDITIONAL", "priority": 40, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false } ] }, { + "id": "ab7f0224-77bf-4413-a653-2f649498edd7", "alias": "saml ecp", "description": "SAML ECP Profile Authentication Flow", "providerId": "basic-flow", @@ -1818,22 +2162,25 @@ "authenticationExecutions": [ { "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, "requirement": "REQUIRED", "priority": 10, - "userSetupAllowed": false, - "autheticatorFlow": false + "autheticatorFlow": false, + "userSetupAllowed": false } ] } ], "authenticatorConfig": [ { + "id": "19098390-9480-4c06-9f2f-f5bb15210a1e", "alias": "create unique user config", "config": { "require.password.update.after.registration": "false" } }, { + "id": "1641002e-29dd-4aaa-8e86-8405259ba1d6", "alias": "review profile config", "config": { "update.profile.on.first.login": "missing" @@ -1851,9 +2198,9 @@ "config": {} }, { - "alias": "terms_and_conditions", + "alias": "TERMS_AND_CONDITIONS", "name": "Terms and Conditions", - "providerId": "terms_and_conditions", + "providerId": "TERMS_AND_CONDITIONS", "enabled": false, "defaultAction": false, "priority": 20, @@ -1885,6 +2232,60 @@ "defaultAction": false, "priority": 50, "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": true, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "VERIFY_PROFILE", + "name": "Verify Profile", + "providerId": "VERIFY_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 90, + "config": {} + }, + { + "alias": "delete_credential", + "name": "Delete Credential", + "providerId": "delete_credential", + "enabled": true, + "defaultAction": false, + "priority": 100, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} } ], "browserFlow": "browser", @@ -1893,104 +2294,91 @@ "resetCredentialsFlow": "reset credentials", "clientAuthenticationFlow": "clients", "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", "attributes": { - "_browser_header.xXSSProtection": "1; mode=block", - "_browser_header.xFrameOptions": "SAMEORIGIN", - "_browser_header.strictTransportSecurity": "max-age=31536000; includeSubDomains", - "permanentLockout": "false", - "quickLoginCheckMilliSeconds": "1000", - "_browser_header.xRobotsTag": "none", - "maxFailureWaitSeconds": "900", - "minimumQuickLoginWaitSeconds": "60", - "failureFactor": "30", - "actionTokenGeneratedByUserLifespan": "300", - "maxDeltaTimeSeconds": "43200", - "_browser_header.xContentTypeOptions": "nosniff", - "offlineSessionMaxLifespan": "5184000", - "actionTokenGeneratedByAdminLifespan": "43200", - "_browser_header.contentSecurityPolicyReportOnly": "", - "bruteForceProtected": "false", - "_browser_header.contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "waitIncrementSeconds": "60", - "offlineSessionMaxLifespanEnabled": "false" + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaAuthRequestedUserHint": "login_hint", + "clientOfflineSessionMaxLifespan": "0", + "oauth2DevicePollingInterval": "5", + "clientSessionIdleTimeout": "0", + "clientOfflineSessionIdleTimeout": "0", + "cibaInterval": "5", + "realmReusableOtpCode": "false", + "cibaExpiresIn": "120", + "oauth2DeviceCodeLifespan": "600", + "parRequestUriLifespan": "60", + "clientSessionMaxLifespan": "0", + "organizationsEnabled": "false" + }, + "keycloakVersion": "26.0.5", + "userManagedAccessAllowed": false, + "organizationsEnabled": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] }, "users": [ { "username": "admin", "enabled": true, - "totp": false, - "emailVerified": false, + "emailVerified": true, + "firstName": "Rootus", + "lastName": "Adminus", + "email": "local-admin@mail.com", "credentials": [ { "type": "password", - "hashedSaltedValue": "NICTtwsvSxJ5hL8hLAuleDUv9jwZcuXgxviMXvR++cciyPtiIEStEaJUyfA9DOir59awjPrHOumsclPVjNBplA==", - "salt": "T/2P5o5oxFJUEk68BRURRg==", - "hashIterations": 27500, - "counter": 0, - "algorithm": "pbkdf2-sha256", - "digits": 0, - "period": 0, - "createdDate": 1554245879354, - "config": {} + "value": "admin" } ], - "disableableCredentialTypes": ["password"], - "requiredActions": [], - "realmRoles": ["admin", "confidential", "user"], - "notBefore": 0, - "groups": [] + "realmRoles": ["admin", "user", "observer"] + }, + { + "username": "jdoe", + "enabled": true, + "emailVerified": true, + "firstName": "John", + "lastName": "Doe", + "email": "j-doe@mail.com", + "credentials": [ + { + "type": "password", + "value": "jdoe" + } + ], + "realmRoles": ["user", "observer"] }, { "username": "alice", "enabled": true, - "totp": false, - "emailVerified": false, + "emailVerified": true, + "firstName": "Alice", + "lastName": "Jane", + "email": "alice@mail.com", "credentials": [ { "type": "password", - "hashedSaltedValue": "A3okqV2T/ybXTVEgKfosoSjP8Yc9IZbFP/SY4cEd6hag7TABQrQ6nUSuwagGt96l8cw1DTijO75PqX6uiTXMzw==", - "salt": "sl4mXx6T9FypPH/s9TngfQ==", - "hashIterations": 27500, - "counter": 0, - "algorithm": "pbkdf2-sha256", - "digits": 0, - "period": 0, - "createdDate": 1554245879116, - "config": {} + "value": "alice" } ], - "disableableCredentialTypes": ["password"], - "requiredActions": [], - "realmRoles": ["user"], - "notBefore": 0, - "groups": [] + "realmRoles": ["user", "observer"] }, { - "username": "jdoe", + "username": "nobody", "enabled": true, - "totp": false, - "emailVerified": false, + "emailVerified": true, + "firstName": "No", + "lastName": "Body", + "email": "no-body@mail.com", "credentials": [ { "type": "password", - "hashedSaltedValue": "JV3DUNLjqOadjbBOtC4rvacQI553CGaDGAzBS8MR5ReCr7SwF3E6CsW3T7/XO8ITZAsch8+A/6loeuCoVLLJrg==", - "salt": "uCbOH7HZtyDtMd0E9DG/nw==", - "hashIterations": 27500, - "counter": 0, - "algorithm": "pbkdf2-sha256", - "digits": 0, - "period": 0, - "createdDate": 1554245879227, - "config": {} + "value": "nobody" } ], - "disableableCredentialTypes": ["password"], - "requiredActions": [], - "realmRoles": ["confidential", "user"], - "notBefore": 0, - "groups": [] + "realmRoles": ["observer"] } - ], - "keycloakVersion": "6.0.0", - "userManagedAccessAllowed": false + ] } diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/pom.xml b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/pom.xml new file mode 100644 index 00000000000..8e5da1edfad --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/pom.xml @@ -0,0 +1,134 @@ + + + + 4.0.0 + + org.kie + kie-tools-maven-base + ${revision} + ../../node_modules/@kie-tools/maven-base/pom.xml + + + + management-console-dev-webapp-runtime + 999-dev + + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-resteasy-jackson + + + io.quarkus + quarkus-smallrye-openapi + + + io.quarkus + quarkus-smallrye-health + + + + org.jbpm + jbpm-with-drools-quarkus + + + + org.kie + kie-addons-quarkus-process-management + + + org.kie + kogito-addons-quarkus-jobs-management + + + org.kie + kie-addons-quarkus-process-svg + + + org.kie + kie-addons-quarkus-source-files + + + + + io.quarkus + quarkus-jdbc-h2 + + + io.quarkus + quarkus-agroal + + + org.kie + kie-addons-quarkus-persistence-jdbc + + + + + org.kie + kogito-addons-quarkus-data-index-jpa + + + + + org.kie + kogito-addons-quarkus-jobs + + + org.kie.kogito + jobs-service-storage-jpa + + + + + org.kie + kogito-addons-quarkus-data-audit-jpa + + + org.kie + kogito-addons-quarkus-data-audit + + + + + ${project.artifactId} + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/java/org/kie/kogito/hr/CandidateData.java b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/java/org/kie/kogito/hr/CandidateData.java new file mode 100644 index 00000000000..eae14184da0 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/java/org/kie/kogito/hr/CandidateData.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.kie.kogito.hr; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class CandidateData { + + private String name; + + private String lastName; + + private String email; + + private Integer experience; + + private List skills; + + public CandidateData() { + } + + public CandidateData(String name, String lastName, String email, Integer experience, List skills) { + this.name = name; + this.lastName = lastName; + this.email = email; + this.experience = experience; + this.skills = skills; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Integer getExperience() { + return experience; + } + + public void setExperience(Integer experience) { + this.experience = experience; + } + + public List getSkills() { + return skills; + } + + public void setSkills(List skills) { + this.skills = skills; + } + + @JsonIgnore + public String getFullName() { + return name + " " + lastName; + } +} diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/java/org/kie/kogito/hr/Offer.java b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/java/org/kie/kogito/hr/Offer.java new file mode 100644 index 00000000000..a377b480aa0 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/java/org/kie/kogito/hr/Offer.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.kie.kogito.hr; + +public class Offer { + + private String category; + + private Integer salary; + + public Offer() { + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public Integer getSalary() { + return salary; + } + + public void setSalary(Integer salary) { + this.salary = salary; + } +} diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/META-INF/processSVG/hiring.svg b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/META-INF/processSVG/hiring.svg new file mode 100644 index 00000000000..37c2237d5ca --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/META-INF/processSVG/hiring.svg @@ -0,0 +1,1427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HR Interview + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IT Interview + + + + + + + + + + + + + + + + + + + + + + + + + + + New Hiring + + + + + + + + + + + + + + + + + + + + + + + + + + + Send + notification + HR Interview + avoided + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Application + denied + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Generate base + offer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Log Offer + + + + + + + + + + + + + + + + + + + + + + + + + + + Send Offer to + Candidate + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/NewHiringOffer.dmn b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/NewHiringOffer.dmn new file mode 100644 index 00000000000..dd172b5ce80 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/NewHiringOffer.dmn @@ -0,0 +1,190 @@ + + + + + + string + + + string + + + string + + + number + + + string + + + + + number + + + string + + "Software Engineer", "Senior Software Engineer", "Software Architect" + + + + + + + + + + + + + + + + + + count(CandidateData.skills) * 150 + + + + + + + + CandidateData.experience + + + + + "Software Engineer", "Senior Software Engineer", "Software Architect" + + + + + + + [0..5) + + + "Software Engineer" + + + 30000 + SalaryBonus + + + + + + + + [5..10) + + + "Senior Software Engineer" + + + 40000 + SalaryBonus + + + + + + + + >=10 + + + "Software Architect" + + + 50000 + SalaryBonus + + + + + + + + + + Offer + + + + + + + + + + 50 + 120 + 926 + + + 926 + + + 50 + 175 + 104 + 437 + 140 + + + 926 + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/application.properties b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/application.properties new file mode 100644 index 00000000000..36e4fc6ae37 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/application.properties @@ -0,0 +1,55 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +# quarkus.http.port= --> This is set on package.json. See 'start:runtime' script. +kogito.service.url=http://localhost:${quarkus.http.port} +kogito.jobs-service.url=http://localhost:${quarkus.http.port} +kogito.data-index.url=http://localhost:${quarkus.http.port} + +# Persistence +kie.flyway.enabled=true +kogito.persistence.type=jdbc +quarkus.datasource.db-kind=h2 +quarkus.datasource.username=kogito +quarkus.datasource.jdbc.url=jdbc:h2:mem:default;NON_KEYWORDS=VALUE,KEY + +# Security +kogito.security.auth.enabled=true +kogito.security.auth.impersonation.allowed-for-roles=admin + +quarkus.oidc.enabled=true +quarkus.oidc.auth-server-url=http://localhost:${dev-webapp.idp.port}/realms/management-console-dev-webapp-realm +quarkus.oidc.discovery-enabled=true +quarkus.oidc.tenant-enabled=true +quarkus.oidc.client-id=management-console-dev-webapp-runtime +quarkus.oidc.application-type=service +quarkus.http.auth.permission.authenticated.paths=/* +quarkus.http.auth.permission.authenticated.policy=authenticated +quarkus.http.auth.permission.public.paths=/q/*,/docs/*,/kogito/security/oidc/auth-server-url +quarkus.http.auth.permission.public.policy=permit + +quarkus.http.cors=true +quarkus.http.cors.origins=* + +# Misc. +quarkus.dev-ui.cors.enabled=false +quarkus.smallrye-openapi.path=/docs/openapi.json +quarkus.swagger-ui.always-include=true +quarkus.kogito.data-index.graphql.ui.always-include=true +quarkus.http.test-port=0 \ No newline at end of file diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/hiring.bpmn b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/hiring.bpmn new file mode 100644 index 00000000000..51bba169472 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/hiring.bpmn @@ -0,0 +1,1057 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _B11455DE-F77A-4251-A85B-4C66636E3CD9 + _7DDA574A-C220-4FEF-9784-22EF8052EDEC + System.out.println("###################################"); +System.out.println("To: " + candidateData.getEmail()); +System.out.println("Subject: Congratulations you made it!"); +System.out.println("Dear " + candidateData.getFullName() + ", we are happy to tell you that you've successfully went through the hiring process. You'll find the final Offer details in attached."); +System.out.println("Job Category: " + offer.getCategory()); +System.out.println("Base salary: " + offer.getSalary()); +System.out.println("###################################"); + + + + + + + + _9C33F5EA-89C7-4ED1-B3C2-CF18DE439AF5 + _ACEE7578-B7D2-4EDF-B104-9ECF3DD8A383 + System.out.println("###################################"); +System.out.println("Generated offer for candidate: " + candidateData.getFullName()); +System.out.println("Job Category: " + offer.getCategory()); +System.out.println("Base salary: " + offer.getSalary()); +System.out.println("###################################"); + + + _7DDA574A-C220-4FEF-9784-22EF8052EDEC + + + + + + + + _59F9A0E6-7F9C-43A9-8920-5B40A91169E6 + _9C33F5EA-89C7-4ED1-B3C2-CF18DE439AF5 + + + + + + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_fileNameInputX + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_namespaceInputX + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_modelInputX + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_CandidateDataInputX + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_OfferOutputX + + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_fileNameInputX + + + + + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_namespaceInputX + + + + + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_modelInputX + + + + + + + candidateData + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_CandidateDataInputX + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_OfferOutputX + offer + + + + _527D3164-4989-4D2C-B80B-9BA9D4C8FB89 + + + + + + + + _94172225-E124-4F14-98DA-C3D62C11254A + _527D3164-4989-4D2C-B80B-9BA9D4C8FB89 + System.out.println("###################################"); +System.out.println("Candidate " + candidateData.getFullName() + " don't meet the requirements for the position but we'll keep it on records for the future!"); +System.out.println("###################################"); + + + + _5334FFDC-1FCB-47E6-8085-36DC9A3D17B9 + _B7FC63DD-C08F-4CB3-A51A-79C1B8B18E6E + _C6E61C53-FD35-4347-B69E-30AA93AE4404 + _94172225-E124-4F14-98DA-C3D62C11254A + + + _5162ABF0-DD2E-4BDC-9A46-DDCFCB010287 + _C6E61C53-FD35-4347-B69E-30AA93AE4404 + _59F9A0E6-7F9C-43A9-8920-5B40A91169E6 + + + _C62F7EFB-A009-450A-81C7-57D36F0DF766 + _B7FC63DD-C08F-4CB3-A51A-79C1B8B18E6E + _B11455DE-F77A-4251-A85B-4C66636E3CD9 + + + + + + + + _7B41F971-C74D-4036-8A5E-EFF81C37986A + _5334FFDC-1FCB-47E6-8085-36DC9A3D17B9 + System.out.println("###################################"); +System.out.println("HR Interview have been avoided after reasonable time"); +System.out.println("###################################"); + + + + + + + + + _8863B46B-9B0F-40B9-AAB1-A7503CF9AA0A + _5162ABF0-DD2E-4BDC-9A46-DDCFCB010287 + System.out.println("New Hiring has been created for candidate: " + candidateData.getFullName()); + +kcontext.setVariable("hr_approval", false); +kcontext.setVariable("it_approval", false); + + + + + + + + _A76C6603-0406-423C-940B-3403948DCA1F + _C62F7EFB-A009-450A-81C7-57D36F0DF766 + + + + + + + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_TaskNameInputX + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_candidateInputX + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_offerInputX + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_approveInputX + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_SkippableInputX + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_approveOutputX + + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_TaskNameInputX + + + + + + + candidateData + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_candidateInputX + + + offer + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_offerInputX + + + it_approval + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_approveInputX + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_SkippableInputX + + + + + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_approveOutputX + it_approval + + + + jdoe + + + + + + + + + + _ACEE7578-B7D2-4EDF-B104-9ECF3DD8A383 + _A76C6603-0406-423C-940B-3403948DCA1F + + + + + + + + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_TaskNameInputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_candidateInputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_offerInputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_approveInputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_SkippableInputX + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_approveOutputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_offerOutputX + + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_TaskNameInputX + + + + + + + candidateData + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_candidateInputX + + + offer + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_offerInputX + + + hr_approval + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_approveInputX + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_SkippableInputX + + + + + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_approveOutputX + hr_approval + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_offerOutputX + offer + + + + jdoe + + + + + _8863B46B-9B0F-40B9-AAB1-A7503CF9AA0A + + + _7B41F971-C74D-4036-8A5E-EFF81C37986A + + PT1800S + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _-vqWYIS6ED27Zp-7CTfG5A + _-vqWYIS6ED27Zp-7CTfG5A + + diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/pom.xml b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/pom.xml new file mode 100644 index 00000000000..8e5da1edfad --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/pom.xml @@ -0,0 +1,134 @@ + + + + 4.0.0 + + org.kie + kie-tools-maven-base + ${revision} + ../../node_modules/@kie-tools/maven-base/pom.xml + + + + management-console-dev-webapp-runtime + 999-dev + + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-resteasy-jackson + + + io.quarkus + quarkus-smallrye-openapi + + + io.quarkus + quarkus-smallrye-health + + + + org.jbpm + jbpm-with-drools-quarkus + + + + org.kie + kie-addons-quarkus-process-management + + + org.kie + kogito-addons-quarkus-jobs-management + + + org.kie + kie-addons-quarkus-process-svg + + + org.kie + kie-addons-quarkus-source-files + + + + + io.quarkus + quarkus-jdbc-h2 + + + io.quarkus + quarkus-agroal + + + org.kie + kie-addons-quarkus-persistence-jdbc + + + + + org.kie + kogito-addons-quarkus-data-index-jpa + + + + + org.kie + kogito-addons-quarkus-jobs + + + org.kie.kogito + jobs-service-storage-jpa + + + + + org.kie + kogito-addons-quarkus-data-audit-jpa + + + org.kie + kogito-addons-quarkus-data-audit + + + + + ${project.artifactId} + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/java/org/kie/kogito/hr/CandidateData.java b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/java/org/kie/kogito/hr/CandidateData.java new file mode 100644 index 00000000000..eae14184da0 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/java/org/kie/kogito/hr/CandidateData.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.kie.kogito.hr; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class CandidateData { + + private String name; + + private String lastName; + + private String email; + + private Integer experience; + + private List skills; + + public CandidateData() { + } + + public CandidateData(String name, String lastName, String email, Integer experience, List skills) { + this.name = name; + this.lastName = lastName; + this.email = email; + this.experience = experience; + this.skills = skills; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Integer getExperience() { + return experience; + } + + public void setExperience(Integer experience) { + this.experience = experience; + } + + public List getSkills() { + return skills; + } + + public void setSkills(List skills) { + this.skills = skills; + } + + @JsonIgnore + public String getFullName() { + return name + " " + lastName; + } +} diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/java/org/kie/kogito/hr/Offer.java b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/java/org/kie/kogito/hr/Offer.java new file mode 100644 index 00000000000..a377b480aa0 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/java/org/kie/kogito/hr/Offer.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.kie.kogito.hr; + +public class Offer { + + private String category; + + private Integer salary; + + public Offer() { + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public Integer getSalary() { + return salary; + } + + public void setSalary(Integer salary) { + this.salary = salary; + } +} diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/META-INF/processSVG/hiring.svg b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/META-INF/processSVG/hiring.svg new file mode 100644 index 00000000000..37c2237d5ca --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/META-INF/processSVG/hiring.svg @@ -0,0 +1,1427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HR Interview + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IT Interview + + + + + + + + + + + + + + + + + + + + + + + + + + + New Hiring + + + + + + + + + + + + + + + + + + + + + + + + + + + Send + notification + HR Interview + avoided + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Application + denied + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Generate base + offer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Log Offer + + + + + + + + + + + + + + + + + + + + + + + + + + + Send Offer to + Candidate + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/NewHiringOffer.dmn b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/NewHiringOffer.dmn new file mode 100644 index 00000000000..dd172b5ce80 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/NewHiringOffer.dmn @@ -0,0 +1,190 @@ + + + + + + string + + + string + + + string + + + number + + + string + + + + + number + + + string + + "Software Engineer", "Senior Software Engineer", "Software Architect" + + + + + + + + + + + + + + + + + + count(CandidateData.skills) * 150 + + + + + + + + CandidateData.experience + + + + + "Software Engineer", "Senior Software Engineer", "Software Architect" + + + + + + + [0..5) + + + "Software Engineer" + + + 30000 + SalaryBonus + + + + + + + + [5..10) + + + "Senior Software Engineer" + + + 40000 + SalaryBonus + + + + + + + + >=10 + + + "Software Architect" + + + 50000 + SalaryBonus + + + + + + + + + + Offer + + + + + + + + + + 50 + 120 + 926 + + + 926 + + + 50 + 175 + 104 + 437 + 140 + + + 926 + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/application.properties b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/application.properties new file mode 100644 index 00000000000..bd06e365c87 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/application.properties @@ -0,0 +1,45 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +# quarkus.http.port= --> This is set on package.json. See 'start:runtime' script. +kogito.service.url=http://localhost:${quarkus.http.port} +kogito.jobs-service.url=http://localhost:${quarkus.http.port} +kogito.data-index.url=http://localhost:${quarkus.http.port} + +# Persistence +kie.flyway.enabled=true +kogito.persistence.type=jdbc +quarkus.datasource.db-kind=h2 +quarkus.datasource.username=kogito +quarkus.datasource.jdbc.url=jdbc:h2:mem:default;NON_KEYWORDS=VALUE,KEY + +# Security +kogito.security.auth.enabled=false + +quarkus.oidc.enabled=false + +quarkus.http.cors=true +quarkus.http.cors.origins=* + +# Misc. +quarkus.dev-ui.cors.enabled=false +quarkus.smallrye-openapi.path=/docs/openapi.json +quarkus.swagger-ui.always-include=true +quarkus.kogito.data-index.graphql.ui.always-include=true +quarkus.http.test-port=0 \ No newline at end of file diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/hiring.bpmn b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/hiring.bpmn new file mode 100644 index 00000000000..51bba169472 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/hiring.bpmn @@ -0,0 +1,1057 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _B11455DE-F77A-4251-A85B-4C66636E3CD9 + _7DDA574A-C220-4FEF-9784-22EF8052EDEC + System.out.println("###################################"); +System.out.println("To: " + candidateData.getEmail()); +System.out.println("Subject: Congratulations you made it!"); +System.out.println("Dear " + candidateData.getFullName() + ", we are happy to tell you that you've successfully went through the hiring process. You'll find the final Offer details in attached."); +System.out.println("Job Category: " + offer.getCategory()); +System.out.println("Base salary: " + offer.getSalary()); +System.out.println("###################################"); + + + + + + + + _9C33F5EA-89C7-4ED1-B3C2-CF18DE439AF5 + _ACEE7578-B7D2-4EDF-B104-9ECF3DD8A383 + System.out.println("###################################"); +System.out.println("Generated offer for candidate: " + candidateData.getFullName()); +System.out.println("Job Category: " + offer.getCategory()); +System.out.println("Base salary: " + offer.getSalary()); +System.out.println("###################################"); + + + _7DDA574A-C220-4FEF-9784-22EF8052EDEC + + + + + + + + _59F9A0E6-7F9C-43A9-8920-5B40A91169E6 + _9C33F5EA-89C7-4ED1-B3C2-CF18DE439AF5 + + + + + + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_fileNameInputX + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_namespaceInputX + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_modelInputX + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_CandidateDataInputX + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_OfferOutputX + + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_fileNameInputX + + + + + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_namespaceInputX + + + + + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_modelInputX + + + + + + + candidateData + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_CandidateDataInputX + + + _F4D56F6C-4CFE-4D5C-BF5E-67261F68EF1A_OfferOutputX + offer + + + + _527D3164-4989-4D2C-B80B-9BA9D4C8FB89 + + + + + + + + _94172225-E124-4F14-98DA-C3D62C11254A + _527D3164-4989-4D2C-B80B-9BA9D4C8FB89 + System.out.println("###################################"); +System.out.println("Candidate " + candidateData.getFullName() + " don't meet the requirements for the position but we'll keep it on records for the future!"); +System.out.println("###################################"); + + + + _5334FFDC-1FCB-47E6-8085-36DC9A3D17B9 + _B7FC63DD-C08F-4CB3-A51A-79C1B8B18E6E + _C6E61C53-FD35-4347-B69E-30AA93AE4404 + _94172225-E124-4F14-98DA-C3D62C11254A + + + _5162ABF0-DD2E-4BDC-9A46-DDCFCB010287 + _C6E61C53-FD35-4347-B69E-30AA93AE4404 + _59F9A0E6-7F9C-43A9-8920-5B40A91169E6 + + + _C62F7EFB-A009-450A-81C7-57D36F0DF766 + _B7FC63DD-C08F-4CB3-A51A-79C1B8B18E6E + _B11455DE-F77A-4251-A85B-4C66636E3CD9 + + + + + + + + _7B41F971-C74D-4036-8A5E-EFF81C37986A + _5334FFDC-1FCB-47E6-8085-36DC9A3D17B9 + System.out.println("###################################"); +System.out.println("HR Interview have been avoided after reasonable time"); +System.out.println("###################################"); + + + + + + + + + _8863B46B-9B0F-40B9-AAB1-A7503CF9AA0A + _5162ABF0-DD2E-4BDC-9A46-DDCFCB010287 + System.out.println("New Hiring has been created for candidate: " + candidateData.getFullName()); + +kcontext.setVariable("hr_approval", false); +kcontext.setVariable("it_approval", false); + + + + + + + + _A76C6603-0406-423C-940B-3403948DCA1F + _C62F7EFB-A009-450A-81C7-57D36F0DF766 + + + + + + + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_TaskNameInputX + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_candidateInputX + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_offerInputX + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_approveInputX + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_SkippableInputX + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_approveOutputX + + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_TaskNameInputX + + + + + + + candidateData + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_candidateInputX + + + offer + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_offerInputX + + + it_approval + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_approveInputX + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_SkippableInputX + + + + + + + _8962C15F-55EC-46F7-B926-5D5A1FD8D35E_approveOutputX + it_approval + + + + jdoe + + + + + + + + + + _ACEE7578-B7D2-4EDF-B104-9ECF3DD8A383 + _A76C6603-0406-423C-940B-3403948DCA1F + + + + + + + + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_TaskNameInputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_candidateInputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_offerInputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_approveInputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_SkippableInputX + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_approveOutputX + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_offerOutputX + + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_TaskNameInputX + + + + + + + candidateData + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_candidateInputX + + + offer + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_offerInputX + + + hr_approval + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_approveInputX + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_SkippableInputX + + + + + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_approveOutputX + hr_approval + + + _B8C4F63C-81AD-4291-9C1B-84967277EEF6_offerOutputX + offer + + + + jdoe + + + + + _8863B46B-9B0F-40B9-AAB1-A7503CF9AA0A + + + _7B41F971-C74D-4036-8A5E-EFF81C37986A + + PT1800S + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _-vqWYIS6ED27Zp-7CTfG5A + _-vqWYIS6ED27Zp-7CTfG5A + + diff --git a/packages/runtime-tools-management-console-webapp/dev/server/MockData/controllers.js b/packages/runtime-tools-management-console-webapp/dev/server/MockData/controllers.js deleted file mode 100644 index ea691bbf74d..00000000000 --- a/packages/runtime-tools-management-console-webapp/dev/server/MockData/controllers.js +++ /dev/null @@ -1,228 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -const restData = require("./rest"); -const graphData = require("./graphql"); -const path = require("path"); - -const processSvg = [ - "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - "a1e139d5-4e77-48c9-84ae-34578e904e5a", - "8035b580-6ae4-4aa8-9ec0-e18e19809e0blmnop", - "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", -]; -module.exports = controller = { - showError: (req, res) => { - console.log("called", req.params.processId, req.params.processInstanceId); - const { process } = restData.management; - const processId = process.filter((data) => { - return data.processId === req.params.processId; - }); - const error = processId[0].instances.filter((err) => { - return err.processInstanceId === req.params.processInstanceId; - }); - res.send(error[0].error); - }, - callRetrigger: (req, res) => { - const { process } = restData.management; - const processId = process.filter((data) => { - return data.processId === req.params.processId; - }); - const error = processId[0].instances.filter((err) => { - return err.processInstanceId === req.params.processInstanceId; - }); - switch (error[0].retrigger) { - case "success": - res.send(error[0].retrigger); - break; - case "Authentication failed": - res.status(401).send(error[0].retrigger); - break; - case "Authorization failed": - res.status(403).send(error[0].retrigger); - break; - case "Internal server error": - res.status(500).send(error[0].retrigger); - break; - } - }, - callSkip: (req, res) => { - const { process } = restData.management; - const processId = process.filter((data) => { - return data.processId === req.params.processId; - }); - const error = processId[0].instances.filter((err) => { - return err.processInstanceId === req.params.processInstanceId; - }); - switch (error[0].skip) { - case "success": - res.send(error[0].skip); - break; - case "Authentication failed": - res.status(401).send(error[0].skip); - break; - case "Authorization failed": - res.status(403).send(error[0].skip); - break; - case "Internal server error": - res.status(500).send(error[0].skip); - break; - } - }, - callAbort: (req, res) => { - const failedAbortInstances = ["8035b580-6ae4-4aa8-9ec0-e18e19809e0b2", "8035b580-6ae4-4aa8-9ec0-e18e19809e0b3"]; - const data = graphData.ProcessInstanceData.filter((data) => { - return data.id === req.params.processInstanceId; - }); - if (failedAbortInstances.includes(data[0].id)) { - res.status(404).send("process not found"); - } else { - data[0].state = "ABORTED"; - res.status(200).send("success"); - } - }, - callNodeRetrigger: (req, res) => { - const data = graphData.ProcessInstanceData.filter((data) => { - return data.id === req.params.processInstanceId; - }); - const nodeObject = data[0].nodes.filter((node) => node.id === req.params.nodeInstanceId); - if (nodeObject[0].name.includes("not found")) { - res.status(404).send("node not found"); - } else { - nodeObject[0].enter = new Date().toISOString(); - res.status(200).send(data[0]); - } - }, - callNodeCancel: (req, res) => { - const data = graphData.ProcessInstanceData.filter((data) => { - return data.id === req.params.processInstanceId; - }); - const nodeObject = data[0].nodes.filter((node) => node.id === req.params.nodeInstanceId); - if (nodeObject[0].name.includes("not found")) { - res.status(404).send("node not found"); - } else { - nodeObject[0].exit = new Date().toISOString(); - res.status(200).send(data[0]); - } - }, - handleJobReschedule: (req, res) => { - const data = graphData.JobsData.find((data) => { - return data.id === req.params.id; - }); - if ( - req.params.id !== "eff4ee-11qw23-6675-pokau97-qwedjut45a0fa_0" && - req.body.repeatInterval && - req.body.repeatLimit - ) { - data.expirationTime = req.body.expirationTime; - data.repeatInterval = req.body.repeatInterval; - data.repeatLimit = req.body.repeatLimit; - } else { - if (req.params.id !== "eff4ee-11qw23-6675-pokau97-qwedjut45a0fa_0") { - data.expirationTime = req.body.expirationTime; - } - } - if (req.params.id !== "eff4ee-11qw23-6675-pokau97-qwedjut45a0fa_0") { - res.status(200).send(data); - } else { - res.status(400).send("job not rescheduled"); - } - }, - - callNodeTrigger: (req, res) => { - const processInstance = graphData.ProcessInstanceData.filter((process) => { - return process.id === req.params.processInstanceId; - }); - const nodeObject = processInstance[0].nodes.filter((node, index) => { - if (index !== processInstance[0].nodes.length - 1) { - return node.id === req.params.nodeId; - } - }); - if (nodeObject.length === 0) { - res.status(404).send("node not found"); - } else { - const node = { ...nodeObject[0] }; - node.enter = new Date().toISOString(); - node.exit = null; - processInstance[0].nodes.unshift(node); - res.status(200).send({}); - } - }, - - getTriggerableNodes: (req, res) => { - if (req.params.processId !== null || req.params.processId !== undefined) { - res.send([ - { - nodeDefinitionId: "_BDA56801-1155-4AF2-94D4-7DAADED2E3C0", - name: "Send visa application", - id: 1, - type: "ActionNode", - uniqueId: "1", - }, - { - nodeDefinitionId: "_175DC79D-C2F1-4B28-BE2D-B583DFABF70D", - name: "Book", - id: 2, - type: "Split", - uniqueId: "2", - }, - { - nodeDefinitionId: "_E611283E-30B0-46B9-8305-768A002C7518", - name: "visasrejected", - id: 3, - type: "EventNode", - uniqueId: "3", - }, - ]); - } else { - res.send([]); - } - }, - - callJobCancel: (req, res) => { - const mockFailedJobs = ["dad3aa88-5c1e-4858-a919-6123c675a0fa_0"]; - const graphData = require("./graphql"); - const jobData = graphData.JobsData.filter((job) => job.id === req.params.jobId); - if (mockFailedJobs.includes(jobData[0].id) || jobData.length === 0) { - res.status(404).send("job not found"); - } else { - jobData[0].status = "CANCELED"; - jobData[0].lastUpdate = new Date().toISOString(); - res.status(200).send(jobData[0]); - } - }, - dispatchSVG: (req, res) => { - try { - if (processSvg.includes(req.params.id)) { - if (req.params.processId === "travels") { - console.log("travels"); - res.sendFile(path.resolve(__dirname + "/../static/travels.svg")); - } else if (req.params.processId === "flightBooking") { - res.sendFile(path.resolve(__dirname + "/../static/flightBooking.svg")); - } else if (req.params.processId === "hotelBooking") { - res.sendFile(path.resolve(__dirname + "/../static/hotelBooking.svg")); - } - } else { - res.send(null); - } - } catch (error) { - res.status(404).send(error); - } - }, -}; diff --git a/packages/runtime-tools-management-console-webapp/dev/server/MockData/graphql.js b/packages/runtime-tools-management-console-webapp/dev/server/MockData/graphql.js deleted file mode 100644 index b901728ffd3..00000000000 --- a/packages/runtime-tools-management-console-webapp/dev/server/MockData/graphql.js +++ /dev/null @@ -1,3421 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 = { - ProcessInstanceData: [ - { - id: "a1e139d5-4e77-48c9-84ae-34578e904e5a", - processId: "hotelBooking", - businessKey: "T1234HotelBooking01", - parentProcessInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - parentProcessInstance: { - id: "e4448857-fa0c-403b-ad69-f0a353458b9d", - processName: "travels", - businessKey: "T1234", - }, - processName: "HotelBooking", - rootProcessInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - roles: [], - state: "COMPLETED", - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - serviceUrl: null, - endpoint: "http://localhost:4000", - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-34578e904e6b", - message: "some thing went wrong", - }, - addons: [], - variables: - '{"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Bangalore","country":"India","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"hotel":{"address":{"city":"Bangalore","country":"India","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"traveller":{"address":{"city":"Bangalore","country":"US","street":"Bangalore","zipCode":"560093"},"email":"ajaganat@redhat.com","firstName":"Ajay","lastName":"Jaganathan","nationality":"US"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "27107f38-d888-4edf-9a4f-11b9e6d751b6", - enter: "2019-10-22T03:37:30.798Z", - exit: "2019-10-22T03:37:30.798Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book hotel", - definitionId: "ServiceTask_1", - id: "41b3f49e-beb3-4b5f-8130-efd28f82b971", - enter: "2019-10-22T03:37:30.795Z", - exit: "2019-10-22T03:37:30.798Z", - type: "WorkItemNode", - }, - { - nodeId: "2", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "4165a571-2c79-4fd0-921e-c6d5e7851b67", - enter: "2019-10-22T03:37:30.793Z", - exit: "2019-10-22T03:37:30.795Z", - type: "StartNode", - }, - ], - milestones: [ - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75i86", - name: "Manager decision", - status: "COMPLETED", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75m36", - name: "Milestone 1: Order placed", - status: "ACTIVE", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75m66", - name: "Milestone 2: Order shipped", - status: "AVAILABLE", - }, - ], - childProcessInstances: [], - }, - { - id: "a23e6c20-02c2-4c2b-8c5c-e988a0adf863", - processId: "flightBooking", - businessKey: "T1234FlightBooking01", - parentProcessInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - parentProcessInstance: { - id: "e4448857-fa0c-403b-ad69-f0a353458b9d", - processName: "travels", - businessKey: "T1234", - }, - processName: "FlightBooking", - rootProcessInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - roles: [], - state: "ERROR", - addons: ["jobs-management", "prometheus-monitoring", "process-management"], - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - error: { - nodeDefinitionId: "_a23e6c20-02c2-4c2b-8c5c-e988a0adf87c", - message: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim idest laborum.", - }, - start: "2019-10-22T03:40:44.089Z", - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Bangalore","country":"India","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Bangalore","country":"US","street":"Bangalore","zipCode":"560093"},"email":"ajaganat@redhat.com","firstName":"Ajay","lastName":"Jaganathan","nationality":"US"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "e6c20-02c2-4c2b-8c5c-e988a0adf87c", - id: "8ac1fc9d-6de2-4b23-864e-ba79315db317", - enter: "2019-10-22T03:37:30.804Z", - exit: "2019-10-22T03:37:30.804Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book flight", - definitionId: "_a23e6c20-02c2-4c2b-8c5c-e988a0adf87c", - id: "2efa0617-d155-44dc-9b1e-38efc0dcec02", - enter: "2019-10-22T03:37:30.804Z", - exit: "2019-10-22T03:37:30.804Z", - type: "WorkItemNode", - }, - { - nodeId: "3", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "849d5bf2-4032-4897-8b30-179ce9d3444b", - enter: "2019-10-22T03:37:30.804Z", - exit: "2019-10-22T03:37:30.804Z", - type: "StartNode", - }, - ], - milestones: [ - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75ze6", - name: "Manager decision", - status: "COMPLETED", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75a56", - name: "Milestone 1: Order placed", - status: "ACTIVE", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75q76", - name: "Milestone 2: Order shipped", - status: "AVAILABLE", - }, - ], - childProcessInstances: [], - }, - { - id: "a23e6c20-02c2-4c2b-8c5c-e988a0adf862", - processId: "flightBooking", - businessKey: "T1234FlightBooking02", - parentProcessInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - parentProcessInstance: { - id: "e4448857-fa0c-403b-ad69-f0a353458b9d", - processName: "travels", - businessKey: "T1234", - }, - processName: "FlightBooking", - rootProcessInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - roles: [], - state: "COMPLETED", - serviceUrl: null, - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - endpoint: "http://localhost:4000", - error: { - nodeDefinitionId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf823", - message: "some thing went wrong", - }, - addons: [], - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Bangalore","country":"India","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Bangalore","country":"US","street":"Bangalore","zipCode":"560093"},"email":"ajaganat@redhat.com","firstName":"Ajay","lastName":"Jaganathan","nationality":"US"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "8ac1fc9d-6de2-4b23-864e-ba79315db317", - enter: "2019-10-22T03:37:30.804Z", - exit: "2019-10-22T03:37:30.804Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book flight", - definitionId: "ServiceTask_1", - id: "2efa0617-d155-44dc-9b1e-38efc0dcec02", - enter: "2019-10-22T03:37:30.804Z", - exit: "2019-10-22T03:37:30.804Z", - type: "WorkItemNode", - }, - { - nodeId: "3", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "849d5bf2-4032-4897-8b30-179ce9d3444b", - enter: "2019-10-22T03:37:30.804Z", - exit: "2019-10-22T03:37:30.804Z", - type: "StartNode", - }, - ], - milestones: [ - { - id: "27107f38-d888-4edf-9a4f-11b9e6d751g6", - name: "Manager decision", - status: "COMPLETED", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75v36", - name: "Milestone 1: Order placed", - status: "ACTIVE", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75o96", - name: "Milestone 2: Order shipped", - status: "AVAILABLE", - }, - ], - childProcessInstances: [], - }, - { - id: "e4448857-fa0c-403b-ad69-f0a353458b9d", - processId: "travels", - businessKey: "T1234", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels", - roles: [], - state: "ERROR", - rootProcessInstanceId: null, - addons: ["jobs-management", "prometheus-monitoring", "process-management"], - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - error: { - nodeDefinitionId: "_2140F05A-364F-40B3-BB7B-B12927065DF8", - message: "Something went wrong", - }, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Bangalore","country":"India","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"hotel":{"address":{"city":"Bangalore","country":"India","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"traveller":{"address":{"city":"Bangalore","country":"US","street":"Bangalore","zipCode":"560093"},"email":"ajaganat@redhat.com","firstName":"Ajay","lastName":"Jaganathan","nationality":"US"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "870bdda0-be04-4e59-bb0b-f9b665eaacc9", - enter: "2019-10-22T03:37:38.586Z", - exit: "2019-10-22T03:37:38.586Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "6b4a4fe9-4aab-4e8c-bb79-27b8b6b88d1f", - enter: "2019-10-22T03:37:30.807Z", - exit: "2019-10-22T03:37:38.586Z", - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "dd33de7c-c39c-484a-83a8-3e1b007fce95", - enter: "2019-10-22T03:37:30.793Z", - exit: "2019-10-22T03:37:30.803Z", - type: "SubProcessNode", - }, - { - nodeId: "4", - name: "Join", - definitionId: "_2140F05A-364F-40B3-BB7B-B12927065DF8", - id: "08c153e8-2766-4675-81f7-29943efdf411", - enter: "2019-10-22T03:37:30.806Z", - exit: "2019-10-22T03:37:30.807Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "683cf307-f082-4a8e-9c85-d5a11b13903a", - enter: "2019-10-22T03:37:30.803Z", - exit: "2019-10-22T03:37:30.806Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "cf057e58-4113-46c0-be13-6de42ea8377e", - enter: "2019-10-22T03:37:30.792Z", - exit: "2019-10-22T03:37:30.803Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "415a52c0-dc1f-4a93-9238-862dc8072262", - enter: "2019-10-22T03:37:30.792Z", - exit: "2019-10-22T03:37:30.792Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "52d64298-3f28-4aba-a812-dba4077c9665", - enter: "2019-10-22T03:37:30.79Z", - exit: "2019-10-22T03:37:30.792Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "6fdee287-08f6-49c2-af2d-2d125ba76ab7", - enter: "2019-10-22T03:37:30.755Z", - exit: "2019-10-22T03:37:30.79Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "d98c1762-9d3c-4228-9ffc-bc3f423079c0", - enter: "2019-10-22T03:37:30.753Z", - exit: "2019-10-22T03:37:30.754Z", - type: "StartNode", - }, - ], - milestones: [ - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75m26", - name: "Manager decision", - status: "COMPLETED", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75uu26", - name: "Milestone 1: Order placed", - status: "ACTIVE", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75mi86", - name: "Milestone 2: Order shipped", - status: "AVAILABLE", - }, - ], - childProcessInstances: [ - { - id: "a23e6c20-02c2-4c2b-8c5c-e988a0adf862", - processName: "FlightBooking", - businessKey: "T1234FlightBooking02", - }, - { - id: "a1e139d5-4e77-48c9-84ae-34578e904e5a", - processName: "HotelBooking", - businessKey: "T1234HotelBooking01", - }, - { - id: "a23e6c20-02c2-4c2b-8c5c-e988a0adf863", - processName: "FlightBooking", - businessKey: "T1234FlightBooking01", - }, - ], - }, - - { - id: "tEE12-fo54-l665-mp112-akou112345566", - processId: "travels", - businessKey: "TEE12", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels", - roles: [], - state: "ERROR", - rootProcessInstanceId: null, - addons: ["jobs-management", "prometheus-monitoring", "process-management"], - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - error: { - nodeDefinitionId: "_2140F05A-364F-40B3-BB7B-B12927065DF8", - message: "Something went wrong", - }, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Bangalore","country":"India","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"hotel":{"address":{"city":"Bangalore","country":"India","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"traveller":{"address":{"city":"Bangalore","country":"US","street":"Bangalore","zipCode":"560093"},"email":"ajaganat@redhat.com","firstName":"Ajay","lastName":"Jaganathan","nationality":"US"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "870bdda0-be04-4e59-bb0b-f9b665eaacc9", - enter: "2019-10-22T03:37:38.586Z", - exit: "2019-10-22T03:37:38.586Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "6b4a4fe9-4aab-4e8c-bb79-27b8b6b88d1f", - enter: "2019-10-22T03:37:30.807Z", - exit: "2019-10-22T03:37:38.586Z", - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "dd33de7c-c39c-484a-83a8-3e1b007fce95", - enter: "2019-10-22T03:37:30.793Z", - exit: "2019-10-22T03:37:30.803Z", - type: "SubProcessNode", - }, - { - nodeId: "4", - name: "Join", - definitionId: "_2140F05A-364F-40B3-BB7B-B12927065DF8", - id: "08c153e8-2766-4675-81f7-29943efdf411", - enter: "2019-10-22T03:37:30.806Z", - exit: "2019-10-22T03:37:30.807Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "683cf307-f082-4a8e-9c85-d5a11b13903a", - enter: "2019-10-22T03:37:30.803Z", - exit: "2019-10-22T03:37:30.806Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "cf057e58-4113-46c0-be13-6de42ea8377e", - enter: "2019-10-22T03:37:30.792Z", - exit: "2019-10-22T03:37:30.803Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "415a52c0-dc1f-4a93-9238-862dc8072262", - enter: "2019-10-22T03:37:30.792Z", - exit: "2019-10-22T03:37:30.792Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "52d64298-3f28-4aba-a812-dba4077c9665", - enter: "2019-10-22T03:37:30.79Z", - exit: "2019-10-22T03:37:30.792Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "6fdee287-08f6-49c2-af2d-2d125ba76ab7", - enter: "2019-10-22T03:37:30.755Z", - exit: "2019-10-22T03:37:30.79Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "d98c1762-9d3c-4228-9ffc-bc3f423079c0", - enter: "2019-10-22T03:37:30.753Z", - exit: "2019-10-22T03:37:30.754Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [], - }, - { - id: "RZ11-tu77-hj321-bnfhe1-xdr2134", - processId: "travels", - businessKey: "MPTQ", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels", - roles: [], - state: "ERROR", - rootProcessInstanceId: null, - addons: ["jobs-management", "prometheus-monitoring", "process-management"], - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - error: { - nodeDefinitionId: "_2140F05A-364F-40B3-BB7B-B12927065DF8", - message: "Something went wrong", - }, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Bangalore","country":"India","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"hotel":{"address":{"city":"Bangalore","country":"India","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"traveller":{"address":{"city":"Bangalore","country":"US","street":"Bangalore","zipCode":"560093"},"email":"ajaganat@redhat.com","firstName":"Ajay","lastName":"Jaganathan","nationality":"US"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "870bdda0-be04-4e59-bb0b-f9b665eaacc9", - enter: "2019-10-22T03:37:38.586Z", - exit: "2019-10-22T03:37:38.586Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "6b4a4fe9-4aab-4e8c-bb79-27b8b6b88d1f", - enter: "2019-10-22T03:37:30.807Z", - exit: "2019-10-22T03:37:38.586Z", - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "dd33de7c-c39c-484a-83a8-3e1b007fce95", - enter: "2019-10-22T03:37:30.793Z", - exit: "2019-10-22T03:37:30.803Z", - type: "SubProcessNode", - }, - { - nodeId: "4", - name: "Join", - definitionId: "_2140F05A-364F-40B3-BB7B-B12927065DF8", - id: "08c153e8-2766-4675-81f7-29943efdf411", - enter: "2019-10-22T03:37:30.806Z", - exit: "2019-10-22T03:37:30.807Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "683cf307-f082-4a8e-9c85-d5a11b13903a", - enter: "2019-10-22T03:37:30.803Z", - exit: "2019-10-22T03:37:30.806Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "cf057e58-4113-46c0-be13-6de42ea8377e", - enter: "2019-10-22T03:37:30.792Z", - exit: "2019-10-22T03:37:30.803Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "415a52c0-dc1f-4a93-9238-862dc8072262", - enter: "2019-10-22T03:37:30.792Z", - exit: "2019-10-22T03:37:30.792Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "52d64298-3f28-4aba-a812-dba4077c9665", - enter: "2019-10-22T03:37:30.79Z", - exit: "2019-10-22T03:37:30.792Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "6fdee287-08f6-49c2-af2d-2d125ba76ab7", - enter: "2019-10-22T03:37:30.755Z", - exit: "2019-10-22T03:37:30.79Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "d98c1762-9d3c-4228-9ffc-bc3f423079c0", - enter: "2019-10-22T03:37:30.753Z", - exit: "2019-10-22T03:37:30.754Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [], - }, - { - id: "fc1b6535-d557-40df-82c8-b425b9dc531b", - processId: "flightBooking", - businessKey: "Tra234FlightBooking01", - parentProcessInstanceId: "538f9feb-5a14-4096-b791-2055b38da7c6", - parentProcessInstance: { - id: "538f9feb-5a14-4096-b791-2055b38da7c6", - processName: "travels", - businessKey: "Tra234", - }, - processName: "FlightBooking", - rootProcessInstanceId: "538f9feb-5a14-4096-b791-2055b38da7c6", - roles: [], - state: "ERROR", - addons: ["prometheus-monitoring"], - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - error: { - nodeDefinitionId: "_cq125e139d5-4e77-48c9-84ae-34578e90433n", - message: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim idest laborum.", - }, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-23T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-23T22:00:00Z[UTC]","city":"New York","country":"US","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Berlin","country":"Germany","street":"Bakers","zipCode":"100200"},"email":"cristiano@redhat.com","firstName":"Cristiano","lastName":"Nicolai","nationality":"German"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "18d9e3df-22d2-429c-98d7-f4f2a7b1b471", - enter: "2019-10-22T03:40:44.086Z", - exit: "2019-10-22T03:40:44.086Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book flight", - definitionId: "_cq125e139d5-4e77-48c9-84ae-34578e90433n", - id: "8a533611-9766-428f-b7ff-78156fc4851d", - enter: "2019-10-22T03:40:44.086Z", - exit: "2019-10-22T03:40:44.086Z", - type: "WorkItemNode", - }, - { - nodeId: "3", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "2f423120-13ea-4277-97f6-6b7a4b4630d0", - enter: "2019-10-22T03:40:44.086Z", - exit: "2019-10-22T03:40:44.086Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [], - }, - { - id: "ff65b793-bb88-4567-b7e3-73eee35772a4", - processId: "hotelBooking", - businessKey: "Tra234HotelBooking01", - parentProcessInstanceId: "538f9feb-5a14-4096-b791-2055b38da7c6", - parentProcessInstance: { - id: "538f9feb-5a14-4096-b791-2055b38da7c6", - processName: "travels", - businessKey: "Tra234", - }, - rootProcessInstanceId: "538f9feb-5a14-4096-b791-2055b38da7c6", - processName: "HotelBooking", - roles: [], - state: "ABORTED", - addons: ["process-management"], - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-34578ek1839b", - message: "Something went wrong", - }, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - variables: - '{"trip":{"begin":"2019-10-23T22:00:00Z[UTC]","city":"New York","country":"US","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"hotel":{"address":{"city":"New York","country":"US","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"traveller":{"address":{"city":"Berlin","country":"Germany","street":"Bakers","zipCode":"100200"},"email":"cristiano@redhat.com","firstName":"Cristiano","lastName":"Nicolai","nationality":"German"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "ed36cd72-5e52-4a53-9d0d-865c98781282", - enter: "2019-10-22T03:40:44.088Z", - exit: "2019-10-22T03:40:44.088Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book hotel", - definitionId: "ServiceTask_1", - id: "040cd02a-7f4c-4d41-bda5-4889f82e921f", - enter: "2019-10-22T03:40:44.088Z", - exit: "2019-10-22T03:40:44.088Z", - type: "WorkItemNode", - }, - { - nodeId: "3", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "8528c7bf-8ac8-401f-b7e5-6f3e69b9f9f2", - enter: "2019-10-22T03:40:44.088Z", - exit: "2019-10-22T03:40:44.088Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [], - }, - { - id: "538f9feb-5a14-4096-b791-2055b38da7c6", - processId: "travels", - businessKey: "Tra234", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels", - rootProcessInstanceId: null, - roles: [], - state: "ERROR", - addons: ["jobs-management", "prometheus-monitoring", "process-management"], - start: "2019-10-22T03:40:44.089Z", - error: { - nodeDefinitionId: "__a1e139d5-4e77-48c9-84ae-34578e9817n", - message: "Something went wrong", - }, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-23T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-23T22:00:00Z[UTC]","city":"New York","country":"US","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"hotel":{"address":{"city":"New York","country":"US","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"traveller":{"address":{"city":"Berlin","country":"Germany","street":"Bakers","zipCode":"100200"},"email":"cristiano@redhat.com","firstName":"Cristiano","lastName":"Nicolai","nationality":"German"}}', - nodes: [ - { - nodeId: "1", - name: "Confirm travel", - definitionId: "__a1e139d5-4e77-48c9-84ae-34578e9817n", - id: "69e0a0f5-2360-4174-a8f8-a892a31fc2f9", - enter: "2019-10-22T03:40:44.089Z", - exit: "2019-10-22T04:42:07.246Z", - type: "HumanTaskNode", - }, - { - nodeId: "2", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "4cb855b9-e3e4-488d-ae1a-9ea3b8490dba", - enter: "2019-10-22T03:40:44.086Z", - exit: "2019-10-22T03:40:44.087Z", - type: "SubProcessNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "1da9af80-c70e-47b8-9c87-964468fc0b46", - enter: "2019-10-22T03:40:44.089Z", - exit: "2019-10-22T03:40:44.089Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "f9b90c32-51da-4986-9603-8c800a6b71b1", - enter: "2019-10-22T03:40:44.087Z", - exit: "2019-10-22T03:40:44.089Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "f8d7fe9e-0f3e-4919-8fa7-82e0b6821aa9", - enter: "2019-10-22T03:40:44.085Z", - exit: "2019-10-22T03:40:44.087Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "55fd6d56-e4d4-4021-b6c6-02c3c5cb86ce", - enter: "2019-10-22T03:40:44.085Z", - exit: "2019-10-22T03:40:44.085Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "fe6b2d9e-6cfd-415a-8e92-5d2be541c3ff", - enter: "2019-10-22T03:40:44.085Z", - exit: "2019-10-22T03:40:44.085Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "3bd30bf9-96ba-4f5d-9ed0-981963288418", - enter: "2019-10-22T03:40:44.07Z", - exit: "2019-10-22T03:40:44.085Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "739fc473-157d-4b4e-8ad6-e4c28499d24e", - enter: "2019-10-22T03:40:44.07Z", - exit: "2019-10-22T03:40:44.07Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "fc1b6535-d557-40df-82c8-b425b9dc531b", - processName: "FlightBooking", - businessKey: "Tra234FlightBooking01", - }, - { - id: "ff65b793-bb88-4567-b7e3-73eee35772a4", - processName: "HotelBooking", - businessKey: "Tra234HotelBooking01", - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - processId: "travels", - businessKey: null, - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - addons: ["jobs-management", "prometheus-monitoring", "process-management"], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "_175DC79D-C2F1-4B28-BE2D-B583DFABF70D", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0blmnop", - processId: "travels", - businessKey: "Tr1122", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - addons: ["process-management"], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-12-22T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel not found", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [ - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75i86", - name: "Manager decision", - status: "COMPLETED", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75m36", - name: "Milestone 1: Order placed", - status: "ACTIVE", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75m66", - name: "Milestone 2: Order shipped", - status: "AVAILABLE", - }, - { - id: "27107f38-d888-4edf-9a4f-11b9e6d75m88", - name: "Milestone 3: Order delivered and closed with customer sign off", - status: "ACTIVE", - }, - ], - childProcessInstances: [], - }, - { - id: "e735128t-6tt7-4aa8-9ec0-e18e19809e0b", - processId: "travels", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels", - roles: [], - businessKey: null, - state: "COMPLETED", - rootProcessInstanceId: null, - serviceUrl: null, - endpoint: "http://localhost:4000", - addons: ["process-management"], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-12-22T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0bccddee", - processId: "travels", - businessKey: null, - parentProcessInstanceId: null, - processName: "travels", - roles: [], - state: "SUSPENDED", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - addons: ["jobs-management", "prometheus-monitoring", "process-management"], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [], - }, - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processId: "flightBooking", - businessKey: "Trrr", - parentProcessInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - parentProcessInstance: { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - processName: "travels", - businessKey: null, - }, - processName: "FlightBooking", - rootProcessInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - roles: [], - state: "COMPLETED", - serviceUrl: null, - endpoint: "http://localhost:4000", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-81c77-48c9-84ae-34578e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "7244ba1b-75ec-4789-8c65-499a0c5b1a6f", - enter: "2019-10-22T04:43:01.144Z", - exit: "2019-10-22T04:43:01.144Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book flight", - definitionId: "ServiceTask_1", - id: "2f588da5-a323-4111-9017-3093ef9319d1", - enter: "2019-10-22T04:43:01.144Z", - exit: "2019-10-22T04:43:01.144Z", - type: "WorkItemNode", - }, - { - nodeId: "3", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "6ed7aa17-4bb1-48e3-b34a-5a4c5773dff2", - enter: "2019-10-22T04:43:01.144Z", - exit: "2019-10-22T04:43:01.144Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21eaccd", - processName: "FlightBooking test 1", - businessKey: null, - }, - ], - }, - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21eaccd", - processId: "flightBooking test1", - parentProcessInstanceId: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - parentProcessInstance: { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - businessKey: null, - processName: "FlightBooking test 1", - rootProcessInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - roles: [], - state: "SUSPENDED", - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-81c77-48c9-84ae-34578e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "7244ba1b-75ec-4789-8c65-499a0c5b1a6f", - enter: "2019-10-22T04:43:01.144Z", - exit: "2019-10-22T04:43:01.144Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book flight", - definitionId: "ServiceTask_1", - id: "2f588da5-a323-4111-9017-3093ef9319d1", - enter: "2019-10-22T04:43:01.144Z", - exit: "2019-10-22T04:43:01.144Z", - type: "WorkItemNode", - }, - { - nodeId: "3", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "6ed7aa17-4bb1-48e3-b34a-5a4c5773dff2", - enter: "2019-10-22T04:43:01.144Z", - exit: "2019-10-22T04:43:01.144Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21eajabbcc", - processName: "FlightBooking test 2", - businessKey: null, - }, - ], - }, - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21eajabbcc", - processId: "flightBooking test2", - businessKey: "TP444", - parentProcessInstanceId: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21eaccd", - parentProcessInstance: { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21eaccd", - processName: "FlightBooking test 1", - businessKey: null, - }, - rootProcessInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - processName: "FlightBooking test 2", - roles: [], - state: "COMPLETED", - serviceUrl: null, - endpoint: "http://localhost:4000", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-81c77-48c9-84ae-34578e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "7244ba1b-75ec-4789-8c65-499a0c5b1a6f", - enter: "2019-10-22T04:43:01.144Z", - exit: "2019-10-22T04:43:01.144Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book flight", - definitionId: "ServiceTask_1", - id: "2f588da5-a323-4111-9017-3093ef9319d1", - enter: "2019-10-22T04:43:01.144Z", - exit: "2019-10-22T04:43:01.144Z", - type: "WorkItemNode", - }, - { - nodeId: "3", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "6ed7aa17-4bb1-48e3-b34a-5a4c5773dff2", - enter: "2019-10-22T04:43:01.144Z", - exit: "2019-10-22T04:43:01.144Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [], - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processId: "hotelBooking", - businessKey: "TM111", - parentProcessInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - parentProcessInstance: { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - processName: "travels", - businessKey: null, - }, - rootProcessInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - processName: "HotelBooking", - roles: [], - state: "COMPLETED", - serviceUrl: null, - endpoint: "http://localhost:4000", - addons: ["jobs-management", "prometheus-monitoring"], - error: { - nodeDefinitionId: "a1qa139d5-4e77-181x8c9-84ae-34578e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - variables: - '{"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "7a770672-8493-4566-8288-515c0b5360a8", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.146Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book hotel", - definitionId: "ServiceTask_1", - id: "f10ed686-84f0-48b6-844e-5cfafa32a7bc", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.146Z", - type: "WorkItemNode", - }, - { - nodeId: "3", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "5a6bd73e-1d3d-43d9-8f27-8081c3014716", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.146Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0basadadads", - processId: "travels", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels", - roles: [], - state: "ABORTED", - businessKey: "TL111", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-12-22T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88abc", - processName: "hotelBooking", - businessKey: "Hotel11", - }, - ], - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88abc", - processId: "hotelBooking", - parentProcessInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0basadadads", - parentProcessInstance: { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0basadadads", - processName: "travels", - businessKey: null, - }, - rootProcessInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0basadadads", - processName: "HotelBooking", - businessKey: "Hotel11", - roles: [], - state: "COMPLETED", - serviceUrl: null, - endpoint: "http://localhost:4000", - addons: ["jobs-management", "prometheus-monitoring"], - error: { - nodeDefinitionId: "a1qa139d5-4e77-181x8c9-84ae-34578e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: "2019-10-22T05:40:44.089Z", - variables: - '{"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "End Event 1", - definitionId: "EndEvent_1", - id: "7a770672-8493-4566-8288-515c0b5360a8", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.146Z", - type: "EndNode", - }, - { - nodeId: "2", - name: "Book hotel", - definitionId: "ServiceTask_1", - id: "f10ed686-84f0-48b6-844e-5cfafa32a7bc", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.146Z", - type: "WorkItemNode", - }, - { - nodeId: "3", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "5a6bd73e-1d3d-43d9-8f27-8081c3014716", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.146Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b1", - processId: "travels", - businessKey: "travels001", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels1", - roles: [], - state: "ACTIVE", - serviceUrl: "http://localhost:4000", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000/", - addons: ["process-management"], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b2", - processId: "travels", - businessKey: "Tp111", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels2", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000/", - addons: ["process-management"], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b3", - processId: "travels", - businessKey: "Travels@123", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels3", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000/", - endpoint: "http://localhost:4000/", - addons: ["process-management"], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b4", - processId: "travels", - businessKey: "TTTTT", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels4", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: null, - endpoint: "http://localhost:4000/", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b5", - processId: "travels", - businessKey: "Tr11111111", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels5", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000/", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b6", - processId: "travels", - businessKey: "Trav99", - parentProcessInstance: null, - parentProcessInstanceId: null, - processName: "travels6", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: null, - endpoint: "http://localhost:4000/", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b8", - processId: "travels", - businessKey: null, - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels8", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: null, - endpoint: "http://localhost:4000/", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b9", - processId: "travels", - businessKey: null, - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels9", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000/", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b10", - processId: "travels", - businessKey: "newTravels", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels10", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000/", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b11", - processId: "travels", - businessKey: "Trav11test", - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels11", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: "http://localhost:4000", - endpoint: "http://localhost:4000/", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b12", - processId: "travels", - businessKey: null, - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels12", - roles: [], - state: "ACTIVE", - rootProcessInstanceId: null, - serviceUrl: null, - endpoint: "http://localhost:4000/", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - { - id: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b13abbccccc", - processId: "travels", - businessKey: null, - parentProcessInstanceId: null, - parentProcessInstance: null, - processName: "travels13", - roles: [], - state: "COMPLETED", - rootProcessInstanceId: null, - serviceUrl: null, - endpoint: "http://localhost:4000/", - addons: [], - error: { - nodeDefinitionId: "a1e139d5-4e77-48c9-84ae-3459188e90433n", - message: "Something went wrong", - }, - start: "2019-10-22T03:40:44.089Z", - lastUpdate: "2019-12-25T03:40:44.089Z", - end: null, - variables: - '{"flight":{"arrival":"2019-10-30T22:00:00Z[UTC]","departure":"2019-10-22T22:00:00Z[UTC]","flightNumber":"MX555"},"hotel":{"address":{"city":"Berlin","country":"Germany","street":"street","zipCode":"12345"},"bookingNumber":"XX-012345","name":"Perfect hotel","phone":"09876543"},"trip":{"begin":"2019-10-22T22:00:00Z[UTC]","city":"Berlin","country":"Germany","end":"2019-10-30T22:00:00Z[UTC]","visaRequired":false},"traveller":{"address":{"city":"Karkow","country":"Poland","street":"palna","zipCode":"200300"},"email":"rob@redhat.com","firstName":"Rob","lastName":"Rob","nationality":"Polish"}}', - nodes: [ - { - nodeId: "1", - name: "Book Flight", - definitionId: "CallActivity_2", - id: "7cdeba99-cd36-4425-980d-e59d44769a3e", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "SubProcessNode", - }, - { - nodeId: "2", - name: "Confirm travel", - definitionId: "UserTask_2", - id: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - enter: "2019-10-22T04:43:01.148Z", - exit: null, - type: "HumanTaskNode", - }, - { - nodeId: "3", - name: "Join", - definitionId: "ParallelGateway_2", - id: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - enter: "2019-10-22T04:43:01.148Z", - exit: "2019-10-22T04:43:01.148Z", - type: "Join", - }, - { - nodeId: "4", - name: "Book Hotel", - definitionId: "CallActivity_1", - id: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - enter: "2019-10-22T04:43:01.146Z", - exit: "2019-10-22T04:43:01.148Z", - type: "SubProcessNode", - }, - { - nodeId: "5", - name: "Book", - definitionId: "ParallelGateway_1", - id: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.146Z", - type: "Split", - }, - { - nodeId: "6", - name: "Join", - definitionId: "ExclusiveGateway_2", - id: "b2761011-3043-4f48-82bd-1395bf651a91", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Join", - }, - { - nodeId: "7", - name: "is visa required", - definitionId: "ExclusiveGateway_1", - id: "a91a2600-d0cd-46ff-a6c6-b3081612d1af", - enter: "2019-10-22T04:43:01.143Z", - exit: "2019-10-22T04:43:01.143Z", - type: "Split", - }, - { - nodeId: "8", - name: "Visa check", - definitionId: "BusinessRuleTask_1", - id: "1baa5de4-47cc-45a8-8323-005388191e4f", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.143Z", - type: "RuleSetNode", - }, - { - nodeId: "9", - name: "StartProcess", - definitionId: "StartEvent_1", - id: "90e5a337-1c26-4fcc-8ee2-d20e6ba2a1a3", - enter: "2019-10-22T04:43:01.135Z", - exit: "2019-10-22T04:43:01.135Z", - type: "StartNode", - }, - ], - milestones: [], - childProcessInstances: [ - { - id: "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", - processName: "FlightBooking", - businessKey: null, - }, - { - id: "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - processName: "HotelBooking", - businessKey: null, - }, - ], - }, - ], - JobsData: [ - { - id: "6e74a570-31c8-4020-bd70-19be2cb625f3_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: null, - status: "EXECUTED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/6e74a570-31c8-4020-bd70-19be2cb625f3_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: "0", - retries: 1, - lastUpdate: "2020-08-27T03:35:50.147Z", - expirationTime: null, - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95", - executionCounter: 2, - }, - { - id: "dad3aa88-5c1e-4858-a919-6123c675a0fa_1", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "SCHEDULED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 3, - lastUpdate: "2020-07-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "843bd287-fb6e-4ee7-a304-ba9b430e52d8_1", - executionCounter: 6, - }, - { - id: "2234dde-npce1-2908-b3131-6123c675a0fa_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "CANCELED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 2, - lastUpdate: "2020-08-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c", - executionCounter: 0, - }, - { - id: "T3113e-vbg43-2234-lo89-cpmw3214ra0fa_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "ERROR", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: 30300, - repeatLimit: 3, - scheduledId: null, - retries: 7, - lastUpdate: "2020-08-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "af0d984c-4abd-4f5c-83a8-426e6b3d102a_1", - executionCounter: 3, - }, - { - id: "bff4ee-11qw23-6675-po987-qwedfrt45a0fa_5", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "RETRY", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 15, - lastUpdate: "2020-08-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "b2761011-3043-4f48-82bd-1395bf651a91", - executionCounter: 2, - }, - { - id: "eff4ee-11qw23-6675-pokau97-qwedjut45a0fa_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "SCHEDULED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 2, - lastUpdate: "2020-06-29T03:35:54.635Z", - expirationTime: "2020-08-29T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: null, - executionCounter: 0, - }, - { - id: "dad3aa88-5c1e-4858-a919-uey23c675a0fa_0", - processId: "travels", - processInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - rootProcessId: "", - status: "SCHEDULED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 5, - lastUpdate: "2020-08-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "08c153e8-2766-4675-81f7-29943efdf411_1", - executionCounter: 0, - }, - { - id: "6e74a570-31c8-4020-bd70-o413be2cb625f3_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: null, - status: "EXECUTED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/6e74a570-31c8-4020-bd70-19be2cb625f3_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: "0", - retries: 0, - lastUpdate: "2020-08-27T03:35:50.147Z", - expirationTime: null, - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "fd2e12d5-6a4b-4c75-9f31-028d3f032a95_1", - executionCounter: 5, - }, - { - id: "dad3aa88-5c1e-4858-a919-61ai21c675a0fa_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "SCHEDULED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 0, - lastUpdate: "2020-08-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "843bd287-fb6e-4ee7-a304-ba9b430e52d8", - executionCounter: 7, - }, - { - id: "2234dde-npce1-2908-b3131-i15333c675a0fa_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "CANCELED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 0, - lastUpdate: "2020-08-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "7f7d74c1-78f7-49be-b5ad-8d132f46a49c_1", - executionCounter: 3, - }, - { - id: "T3113e-vbg43-2234-lo89-u8103214ra0fa_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "ERROR", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: 30300, - repeatLimit: 3, - scheduledId: null, - retries: 0, - lastUpdate: "2020-08-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "af0d984c-4abd-4f5c-83a8-426e6b3d102a", - executionCounter: 2, - }, - { - id: "bff4ee-11qw23-6675-po987-qwedfrt45a0fa_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "RETRY", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 0, - lastUpdate: "2020-08-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "b2761011-3043-4f48-82bd-1395bf651a91_1", - executionCounter: 9, - }, - { - id: "eff4ee-11qw23-6675-pokau97-ql10s5ut45a0fa_0", - processId: "travels", - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - rootProcessId: "", - status: "SCHEDULED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 0, - lastUpdate: "2020-08-29T03:35:54.635Z", - expirationTime: "2020-08-29T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: null, - executionCounter: 1, - }, - { - id: "dad3aa88-5c1e-4858-a919-781ns75a0fa_0", - processId: "travels", - processInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - rootProcessId: "", - status: "SCHEDULED", - priority: 0, - callbackEndpoint: - "http://localhost:8080/management/jobs/travels/instances/5c56eeff-4cbf-3313-a325-4c895e0afced/timers/dad3aa88-5c1e-4858-a919-6123c675a0fa_0", - repeatInterval: null, - repeatLimit: null, - scheduledId: null, - retries: 0, - lastUpdate: "2020-08-27T03:35:54.635Z", - expirationTime: "2020-08-27T04:35:54.631Z", - endpoint: "http://localhost:4000/jobs", - nodeInstanceId: "08c153e8-2766-4675-81f7-29943efdf411", - executionCounter: 8, - }, - ], -}; diff --git a/packages/runtime-tools-management-console-webapp/dev/server/MockData/mutationRest.js b/packages/runtime-tools-management-console-webapp/dev/server/MockData/mutationRest.js deleted file mode 100644 index 4e7c60c0b89..00000000000 --- a/packages/runtime-tools-management-console-webapp/dev/server/MockData/mutationRest.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 = restData = { - management: { - process: [ - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf863", - skip: "Internal server error", - retrigger: "success", - aborted: "Internal server error", - }, - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf864", - skip: "success", - retrigger: "success", - aborted: "Internal server error", - }, - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf865", - skip: "failed", - retrigger: "failed", - aborted: "Internal server error", - }, - { - processInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - skip: "success", - retrigger: "Authentication failed", - aborted: "Authorization failed", - }, - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf867", - skip: "failed", - retrigger: "failed", - aborted: "Internal server error", - }, - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf868", - skip: "success", - retrigger: "success", - aborted: "Internal server error", - }, - { - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - skip: "success", - retrigger: "Authentication failed", - aborted: "success", - }, - { - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0bccddee", - skip: "failed", - retrigger: "success", - aborted: "success", - }, - { - processInstanceId: "538f9feb-5a14-4096-b791-2055b38da7c6", - skip: "success", - retrigger: "Authentication failed", - aborted: "Internal server error", - }, - { - processInstanceId: "tEE12-fo54-l665-mp112-akou112345566", - skip: "Authentication failed", - retrigger: "success", - aborted: "Internal server error", - }, - { - processInstanceId: "RZ11-tu77-hj321-bnfhe1-xdr2134", - skip: "success", - retrigger: "Authentication failed", - aborted: "Internal server error", - }, - { - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b1", - skip: "success", - retrigger: "Authentication failed", - aborted: "Internal server error", - }, - { - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b2", - skip: "success", - retrigger: "Authentication failed", - aborted: "Internal server error", - }, - ], - }, -}; diff --git a/packages/runtime-tools-management-console-webapp/dev/server/MockData/rest.js b/packages/runtime-tools-management-console-webapp/dev/server/MockData/rest.js deleted file mode 100644 index 99a0f1cb2ef..00000000000 --- a/packages/runtime-tools-management-console-webapp/dev/server/MockData/rest.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 = restData = { - management: { - process: [ - { - processId: "flightBooking", - instances: [ - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf863", - skip: "Internal server error", - retrigger: "success", - aborted: "Internal server error", - }, - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf864", - skip: "success", - retrigger: "success", - aborted: "Internal server error", - }, - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf865", - skip: "failed", - retrigger: "failed", - aborted: "Internal server error", - }, - ], - }, - { - processId: "travels", - instances: [ - { - processInstanceId: "e4448857-fa0c-403b-ad69-f0a353458b9d", - skip: "success", - retrigger: "Authentication failed", - aborted: "Authorization failed", - }, - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf867", - skip: "failed", - retrigger: "failed", - aborted: "Internal server error", - }, - { - processInstanceId: "a23e6c20-02c2-4c2b-8c5c-e988a0adf868", - skip: "success", - retrigger: "success", - aborted: "Internal server error", - }, - { - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - skip: "success", - retrigger: "Authentication failed", - aborted: "success", - }, - { - processInstanceId: "8035b580-6ae4-4aa8-9ec0-e18e19809e0bccddee", - skip: "failed", - retrigger: "success", - aborted: "success", - }, - { - processInstanceId: "538f9feb-5a14-4096-b791-2055b38da7c6", - skip: "success", - retrigger: "Authentication failed", - aborted: "Internal server error", - }, - { - processInstanceId: "tEE12-fo54-l665-mp112-akou112345566", - skip: "Authentication failed", - retrigger: "success", - aborted: "Internal server error", - }, - { - processInstanceId: "RZ11-tu77-hj321-bnfhe1-xdr2134", - skip: "success", - retrigger: "Authentication failed", - aborted: "Internal server error", - }, - ], - }, - ], - }, -}; diff --git a/packages/runtime-tools-management-console-webapp/dev/server/MockData/types.js b/packages/runtime-tools-management-console-webapp/dev/server/MockData/types.js deleted file mode 100644 index bd0772cff6b..00000000000 --- a/packages/runtime-tools-management-console-webapp/dev/server/MockData/types.js +++ /dev/null @@ -1,662 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -const { gql } = require("apollo-server-express"); -module.exports = typeDefs = gql` - scalar DateTime - - schema { - query: Query - subscription: Subscription - mutation: Mutation - } - - type Mutation { - ProcessInstanceSkip(id: String): String - ProcessInstanceAbort(id: String): String - ProcessInstanceRetry(id: String): String - ProcessInstanceUpdateVariables(id: String, variables: String): String - NodeInstanceTrigger(id: String, nodeId: String): String - NodeInstanceCancel(id: String, nodeInstanceId: String): String - NodeInstanceRetrigger(id: String, nodeInstanceId: String): String - JobCancel(id: String): String - JobReschedule(id: String, data: String): String - } - - type Query { - ProcessInstances( - where: ProcessInstanceArgument - orderBy: ProcessInstanceOrderBy - pagination: Pagination - ): [ProcessInstance] - UserTaskInstances( - where: UserTaskInstanceArgument - orderBy: UserTaskInstanceOrderBy - pagination: Pagination - ): [UserTaskInstance] - Travels(where: TravelsArgument, orderBy: TravelsOrderBy, pagination: Pagination): [Travels] - VisaApplications( - where: VisaApplicationsArgument - orderBy: VisaApplicationsOrderBy - pagination: Pagination - ): [VisaApplications] - Jobs(where: JobArgument, orderBy: JobOrderBy, pagination: Pagination): [Job] - } - - type ProcessInstance { - id: String! - processId: String! - processName: String - parentProcessInstanceId: String - parentProcessInstance: ProcessInstance - rootProcessInstanceId: String - rootProcessId: String - roles: [String!] - state: ProcessInstanceState! - serviceUrl: String - endpoint: String! - nodes: [NodeInstance!]! - nodeDefinitions: [Node!] - milestones: [Milestones!] - variables: String - start: DateTime! - end: DateTime - businessKey: String - childProcessInstances: [ProcessInstance!] - error: ProcessInstanceError - addons: [String!] - lastUpdate: DateTime! - diagram: String - source: String - } - - type KogitoMetadata { - lastUpdate: DateTime! - processInstances: [ProcessInstanceMeta] - userTasks: [UserTaskInstanceMeta] - } - - input KogitoMetadataOrderBy { - lastUpdate: OrderBy - } - - input KogitoMetadataArgument { - lastUpdate: DateArgument - processInstances: ProcessInstanceMetaArgument - userTasks: UserTaskInstanceMetaArgument - } - - type ProcessInstanceMeta { - id: String! - processId: String! - processName: String - parentProcessInstanceId: String - rootProcessInstanceId: String - rootProcessId: String - roles: [String!] - state: ProcessInstanceState! - endpoint: String! - start: DateTime! - end: DateTime - lastUpdate: DateTime! - businessKey: String - serviceUrl: String - } - - type ProcessInstanceError { - nodeDefinitionId: String! - message: String - } - - enum ProcessInstanceState { - PENDING - ACTIVE - COMPLETED - ABORTED - SUSPENDED - ERROR - } - - type NodeInstance { - id: String! - name: String! - type: String! - enter: DateTime! - exit: DateTime - definitionId: String! - nodeId: String! - } - - type Node { - id: String! - nodeDefinitionId: String! - name: String! - type: String! - uniqueId: String! - } - - type Milestones { - id: String! - name: String! - status: MilestoneStatus! - } - enum MilestoneStatus { - ACTIVE - AVAILABLE - COMPLETED - } - - input ProcessInstanceOrderBy { - processId: OrderBy - processName: OrderBy - rootProcessId: OrderBy - state: OrderBy - start: OrderBy - end: OrderBy - error: ProcessInstanceErrorOrderBy - lastUpdate: OrderBy - } - - input ProcessInstanceErrorOrderBy { - nodeDefinitionId: OrderBy - message: OrderBy - } - - input ProcessInstanceArgument { - and: [ProcessInstanceArgument!] - or: [ProcessInstanceArgument!] - id: IdArgument - processId: StringArgument - processName: StringArgument - parentProcessInstanceId: IdArgument - rootProcessInstanceId: IdArgument - rootProcessId: StringArgument - state: ProcessInstanceStateArgument - error: ProcessInstanceErrorArgument - nodes: NodeInstanceArgument - endpoint: StringArgument - roles: StringArrayArgument - start: DateArgument - end: DateArgument - addons: StringArrayArgument - lastUpdate: DateArgument - businessKey: StringArgument - } - - input ProcessInstanceErrorArgument { - nodeDefinitionId: StringArgument - message: StringArgument - } - - input ProcessInstanceMetaArgument { - id: IdArgument - processId: StringArgument - processName: StringArgument - parentProcessInstanceId: IdArgument - rootProcessInstanceId: IdArgument - rootProcessId: StringArgument - state: ProcessInstanceStateArgument - endpoint: StringArgument - roles: StringArrayArgument - start: DateArgument - end: DateArgument - } - - input NodeInstanceArgument { - id: IdArgument - name: StringArgument - definitionId: StringArgument - nodeId: StringArgument - type: StringArgument - enter: DateArgument - exit: DateArgument - } - - input StringArrayArgument { - contains: String - containsAll: [String!] - containsAny: [String!] - isNull: Boolean - } - - input IdArgument { - in: [String!] - equal: String - isNull: Boolean - } - - input StringArgument { - in: [String!] - like: String - isNull: Boolean - equal: String - } - - input BooleanArgument { - isNull: Boolean - equal: Boolean - } - - input NumericArgument { - in: [Int!] - isNull: Boolean - equal: Int - greaterThan: Int - greaterThanEqual: Int - lessThan: Int - lessThanEqual: Int - between: NumericRange - } - - input NumericRange { - from: Int! - to: Int! - } - - input DateArgument { - isNull: Boolean - equal: DateTime - greaterThan: DateTime - greaterThanEqual: DateTime - lessThan: DateTime - lessThanEqual: DateTime - between: DateRange - } - - input DateRange { - from: DateTime! - to: DateTime! - } - - input ProcessInstanceStateArgument { - equal: ProcessInstanceState - in: [ProcessInstanceState] - } - - type UserTaskInstance { - id: String! - description: String - name: String - priority: String - processInstanceId: String! - processId: String! - rootProcessInstanceId: String - rootProcessId: String - state: String! - actualOwner: String - adminGroups: [String!] - adminUsers: [String!] - completed: DateTime - started: DateTime! - excludedUsers: [String!] - potentialGroups: [String!] - potentialUsers: [String!] - inputs: String - outputs: String - referenceName: String - lastUpdate: DateTime! - } - - type UserTaskInstanceMeta { - id: String! - description: String - name: String - priority: String - processInstanceId: String! - state: String! - actualOwner: String - adminGroups: [String!] - adminUsers: [String!] - completed: DateTime - started: DateTime! - excludedUsers: [String!] - potentialGroups: [String!] - potentialUsers: [String!] - referenceName: String - lastUpdate: DateTime! - } - - input UserTaskInstanceArgument { - and: [UserTaskInstanceArgument!] - or: [UserTaskInstanceArgument!] - state: StringArgument - id: IdArgument - description: StringArgument - name: StringArgument - priority: StringArgument - processInstanceId: IdArgument - actualOwner: StringArgument - potentialUsers: StringArrayArgument - potentialGroups: StringArrayArgument - excludedUsers: StringArrayArgument - adminGroups: StringArrayArgument - adminUsers: StringArrayArgument - completed: DateArgument - started: DateArgument - referenceName: StringArgument - lastUpdate: DateArgument - } - - input UserTaskInstanceMetaArgument { - state: StringArgument - id: IdArgument - description: StringArgument - name: StringArgument - priority: StringArgument - processInstanceId: IdArgument - actualOwner: StringArgument - potentialUsers: StringArrayArgument - potentialGroups: StringArrayArgument - excludedUsers: StringArrayArgument - adminGroups: StringArrayArgument - adminUsers: StringArrayArgument - completed: DateArgument - started: DateArgument - referenceName: StringArgument - } - - input UserTaskInstanceOrderBy { - state: OrderBy - actualOwner: OrderBy - description: OrderBy - name: OrderBy - priority: OrderBy - completed: OrderBy - started: OrderBy - referenceName: OrderBy - lastUpdate: OrderBy - } - - type Subscription { - ProcessInstanceAdded: ProcessInstance! - ProcessInstanceUpdated: ProcessInstance! - UserTaskInstanceAdded: UserTaskInstance! - UserTaskInstanceUpdated: UserTaskInstance! - } - - enum OrderBy { - ASC - DESC - } - - input Pagination { - limit: Int - offset: Int - } - - type Travels { - flight: Flight - hotel: Hotel - id: String - traveller: Traveller - trip: Trip - visaApplication: VisaApplication - metadata: KogitoMetadata - } - - type Flight { - arrival: String - departure: String - flightNumber: String - gate: String - seat: String - } - - type Hotel { - address: Address - bookingNumber: String - name: String - phone: String - room: String - } - - type Address { - city: String - country: String - street: String - zipCode: String - } - - type Traveller { - address: Address - email: String - firstName: String - lastName: String - nationality: String - } - - type Trip { - begin: String - city: String - country: String - end: String - visaRequired: Boolean - } - - type VisaApplication { - approved: Boolean - city: String - country: String - duration: Int - firstName: String - lastName: String - nationality: String - passportNumber: String - } - - input TravelsArgument { - and: [TravelsArgument!] - or: [TravelsArgument!] - flight: FlightArgument - hotel: HotelArgument - id: IdArgument - traveller: TravellerArgument - trip: TripArgument - visaApplication: VisaApplicationArgument - metadata: KogitoMetadataArgument - } - - input FlightArgument { - arrival: StringArgument - departure: StringArgument - flightNumber: StringArgument - gate: StringArgument - seat: StringArgument - } - - input HotelArgument { - address: AddressArgument - bookingNumber: StringArgument - name: StringArgument - phone: StringArgument - room: StringArgument - } - - input AddressArgument { - city: StringArgument - country: StringArgument - street: StringArgument - zipCode: StringArgument - } - - input TravellerArgument { - address: AddressArgument - email: StringArgument - firstName: StringArgument - lastName: StringArgument - nationality: StringArgument - } - - input TripArgument { - begin: StringArgument - city: StringArgument - country: StringArgument - end: StringArgument - visaRequired: BooleanArgument - } - - input VisaApplicationArgument { - approved: BooleanArgument - city: StringArgument - country: StringArgument - duration: NumericArgument - firstName: StringArgument - lastName: StringArgument - nationality: StringArgument - passportNumber: StringArgument - } - - input TravelsOrderBy { - flight: FlightOrderBy - hotel: HotelOrderBy - traveller: TravellerOrderBy - trip: TripOrderBy - visaApplication: VisaApplicationOrderBy - metadata: KogitoMetadataOrderBy - } - - input FlightOrderBy { - arrival: OrderBy - departure: OrderBy - flightNumber: OrderBy - gate: OrderBy - seat: OrderBy - } - - input HotelOrderBy { - address: AddressOrderBy - bookingNumber: OrderBy - name: OrderBy - phone: OrderBy - room: OrderBy - } - - input AddressOrderBy { - city: OrderBy - country: OrderBy - street: OrderBy - zipCode: OrderBy - } - - input TravellerOrderBy { - address: AddressOrderBy - email: OrderBy - firstName: OrderBy - lastName: OrderBy - nationality: OrderBy - } - - input TripOrderBy { - begin: OrderBy - city: OrderBy - country: OrderBy - end: OrderBy - visaRequired: OrderBy - } - - input VisaApplicationOrderBy { - approved: OrderBy - city: OrderBy - country: OrderBy - duration: OrderBy - firstName: OrderBy - lastName: OrderBy - nationality: OrderBy - passportNumber: OrderBy - } - - type VisaApplications { - id: String - visaApplication: VisaApplication - metadata: KogitoMetadata - } - - input VisaApplicationsArgument { - and: [VisaApplicationsArgument!] - or: [VisaApplicationsArgument!] - id: IdArgument - visaApplication: VisaApplicationArgument - metadata: KogitoMetadataArgument - } - - input VisaApplicationsOrderBy { - visaApplication: VisaApplicationOrderBy - metadata: KogitoMetadataOrderBy - } - - input JobArgument { - and: [JobArgument!] - or: [JobArgument!] - id: IdArgument - processId: StringArgument - processInstanceId: IdArgument - rootProcessInstanceId: IdArgument - rootProcessId: StringArgument - status: JobStatusArgument - expirationTime: DateArgument - priority: NumericArgument - scheduledId: IdArgument - lastUpdate: DateArgument - endpoint: StringArgument - nodeInstanceId: StringArgument - } - - input JobOrderBy { - processId: OrderBy - rootProcessId: OrderBy - status: OrderBy - expirationTime: OrderBy - priority: OrderBy - retries: OrderBy - lastUpdate: OrderBy - executionCounter: OrderBy - } - - input JobStatusArgument { - equal: JobStatus - in: [JobStatus] - } - - type Job { - id: String! - processId: String - processInstanceId: String - rootProcessInstanceId: String - rootProcessId: String - status: JobStatus! - expirationTime: DateTime - priority: Int - callbackEndpoint: String - repeatInterval: Int - repeatLimit: Int - scheduledId: String - retries: Int - lastUpdate: DateTime - executionCounter: Int - endpoint: String - nodeInstanceId: String - } - - enum JobStatus { - ERROR - EXECUTED - SCHEDULED - RETRY - CANCELED - } -`; diff --git a/packages/runtime-tools-management-console-webapp/dev/server/server.js b/packages/runtime-tools-management-console-webapp/dev/server/server.js deleted file mode 100644 index 91857507b09..00000000000 --- a/packages/runtime-tools-management-console-webapp/dev/server/server.js +++ /dev/null @@ -1,414 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -// HTTP SERVER -const express = require("express"); -var cors = require("cors"); -const app = express(); -const { ApolloServer, gql } = require("apollo-server-express"); -var bodyParser = require("body-parser"); -// GraphQL - Apollo -const { GraphQLScalarType } = require("graphql"); -const { v1: uuidv1 } = require("uuid"); -const _ = require("lodash"); -// Config -const config = require("./config"); - -//Mock data -const data = require("./MockData/graphql"); -const controller = require("./MockData/controllers"); -const typeDefs = require("./MockData/types"); -const mutationRestData = require("./MockData/mutationRest"); -function setPort(port = 4000) { - app.set("port", parseInt(port, 10)); -} - -function listen() { - const port = app.get("port") || config.port; - app.listen(port, () => { - console.log(`The server is running and listening at http://localhost:${port}`); - }); -} -// parse application/x-www-form-urlencoded -app.use(bodyParser.urlencoded({ extended: false })); - -// parse application/json -app.use(bodyParser.json()); -app.use( - cors({ - origin: config.corsDomain, // Be sure to switch to your production domain - optionsSuccessStatus: 200, - }) -); - -//Rest Api's -// http://localhost:4000/management/processes/{processId}/instances/{processInstanceId}/error -app.post("/management/processes/:processId/instances/:processInstanceId/error", controller.showError); -app.post("/management/processes/:processId/instances/:processInstanceId/skip", controller.callSkip); -app.post("/management/processes/:processId/instances/:processInstanceId/retrigger", controller.callRetrigger); -app.delete("/management/processes/:processId/instances/:processInstanceId", controller.callAbort); -app.post( - "/management/processes/:processId/instances/:processInstanceId/nodeInstances/:nodeInstanceId", - controller.callNodeRetrigger -); -app.delete( - "/management/processes/:processId/instances/:processInstanceId/nodeInstances/:nodeInstanceId", - controller.callNodeCancel -); -app.patch("/jobs/:id", controller.handleJobReschedule); -app.post("/management/processes/:processId/instances/:processInstanceId/nodes/:nodeId", controller.callNodeTrigger); -app.get("/management/processes/:processId/nodes", controller.getTriggerableNodes); -app.delete("/jobs/:jobId", controller.callJobCancel); -app.get("/svg/processes/:processId/instances/:id", controller.dispatchSVG); - -function timeout(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -function setProcessInstanceState(processInstanceId, state) { - const processInstance = data.ProcessInstanceData.filter((data) => data.id === processInstanceId); - processInstance[0].state = state; -} - -const processSvg = [ - "8035b580-6ae4-4aa8-9ec0-e18e19809e0b", - "a1e139d5-4e77-48c9-84ae-34578e904e5a", - "8035b580-6ae4-4aa8-9ec0-e18e19809e0blmnop", - "2d962eef-45b8-48a9-ad4e-9cde0ad6af88", - "c54ca5b0-b975-46e2-a9a0-6a86bf7ac21e", -]; -const fs = require("fs"); - -//init svg -data.ProcessInstanceData.forEach((datum) => { - if (processSvg.includes(datum.id)) { - if (datum.processId === "travels") { - console.log("travels"); - datum.diagram = fs.readFileSync(__dirname + "/static/travels.svg", "utf8"); - } else if (datum.processId === "flightBooking") { - datum.diagram = fs.readFileSync(__dirname + "/static/flightBooking.svg"); - } else if (datum.processId === "hotelBooking") { - datum.diagram = fs.readFileSync(__dirname + "/static/hotelBooking.svg"); - } - } else { - datum.diagram = null; - } - if (datum.processId !== null || datum.processId !== undefined) { - datum.nodes = [ - { - definitionId: "_BDA56801-1155-4AF2-94D4-7DAADED2E3C0", - name: "Send visa application", - id: 1, - type: "ActionNode", - uniqueId: "1", - }, - { - definitionId: "_175DC79D-C2F1-4B28-BE2D-B583DFABF70D", - name: "Book", - id: 2, - type: "Split", - uniqueId: "2", - }, - { - definitionId: "_E611283E-30B0-46B9-8305-768A002C7518", - name: "visasrejected", - id: 3, - type: "EventNode", - uniqueId: "3", - }, - ]; - } else { - datum.nodeDefinition = null; - } -}); - -function paginatedResult(arr, offset, limit) { - let paginatedArray = arr.slice(offset, offset + limit); - console.log("offset : ", offset); - console.log("limit : ", limit); - if (offset > arr.length && paginatedArray.length === 0) { - let prevData = arr.slice(offset - limit, limit); - return prevData; - } - return paginatedArray; -} -// Provide resolver functions for your schema fields -const resolvers = { - Mutation: { - ProcessInstanceRetry: async (parent, args) => { - const successRetryInstances = ["8035b580-6ae4-4aa8-9ec0-e18e19809e0b2", "8035b580-6ae4-4aa8-9ec0-e18e19809e0b3"]; - const { process } = mutationRestData.management; - const processInstance = process.filter((data) => { - return data.processInstanceId === args["id"]; - }); - if (successRetryInstances.includes(processInstance[0].id)) { - setProcessInstanceState(processInstance[0].processInstanceId, "ACTIVE"); - processInstance[0].state = "ACTIVE"; - } - return processInstance[0].retrigger; - }, - ProcessInstanceSkip: async (parent, args) => { - const { process } = mutationRestData.management; - const processInstance = process.filter((data) => { - return data.processInstanceId === args["id"]; - }); - - return processInstance[0].skip; - }, - - ProcessInstanceAbort: async (parent, args) => { - const failedAbortInstances = ["8035b580-6ae4-4aa8-9ec0-e18e19809e0b2", "8035b580-6ae4-4aa8-9ec0-e18e19809e0b3"]; - const { process } = mutationRestData.management; - const processInstance = process.filter((data) => { - return data.processInstanceId === args["id"]; - }); - if (failedAbortInstances.includes(processInstance[0].id)) { - return "process not found"; - } else { - setProcessInstanceState(processInstance[0].processInstanceId, "ABORTED"); - processInstance[0].state = "ABORTED"; - return processInstance[0].abort; - } - }, - - ProcessInstanceUpdateVariables: async (parent, args) => { - const processInstance = data.ProcessInstanceData.filter((datum) => { - return datum.id === args["id"]; - }); - processInstance[0].variables = args["variables"]; - return processInstance[0].variables; - }, - - NodeInstanceTrigger: async (parent, args) => { - const nodeData = data.ProcessInstanceData.filter((data) => { - return data.id === args["id"]; - }); - const nodeObject = nodeData[0].nodes.filter((node, index) => { - if (index !== nodeData[0].nodes.length - 1) { - return node.id === args["nodeId"]; - } - }); - if (nodeObject.length === 0) { - throw new Error("node not found"); - } else { - const node = { ...nodeObject[0] }; - node.enter = new Date().toISOString(); - node.exit = null; - nodeData[0].nodes.unshift(node); - return nodeData[0]; - } - }, - - NodeInstanceCancel: async (parent, args) => { - const nodeData = data.ProcessInstanceData.filter((data) => { - return data.id === args["id"]; - }); - const nodeObject = nodeData[0].nodes.filter((node) => node.id === args["nodeInstanceId"]); - if (nodeObject[0].name.includes("not found")) { - throw new Error("node not found"); - } else { - nodeObject[0].exit = new Date().toISOString(); - return nodeObject[0]; - } - }, - - NodeInstanceRetrigger: async (parent, args) => { - const nodeData = data.ProcessInstanceData.filter((data) => { - return data.id === args["id"]; - }); - const nodeObject = nodeData[0].nodes.filter((node) => node.id === args["nodeInstanceId"]); - if (nodeObject[0].name.includes("not found")) { - throw new Error("node not found"); - } else { - nodeObject[0].exit = new Date().toISOString(); - return nodeObject[0]; - } - }, - - JobCancel: async (parent, args) => { - const mockFailedJobs = ["dad3aa88-5c1e-4858-a919-6123c675a0fa_0"]; - const jobData = data.JobsData.filter((job) => job.id === args["id"]); - if (mockFailedJobs.includes(jobData[0].id) || jobData.length === 0) { - return "job not found"; - } else { - jobData[0].status = "CANCELED"; - jobData[0].lastUpdate = new Date().toISOString(); - return jobData[0]; - } - }, - - JobReschedule: async (parent, args) => { - const data = data.JobsData.find((data) => { - return data.id === args["id"]; - }); - if ( - args["id"] !== "eff4ee-11qw23-6675-pokau97-qwedjut45a0fa_0" && - args["data"].repeatInterval && - args["data"].repeatLimit - ) { - data.expirationTime = args["data"].expirationTime; - data.repeatInterval = args["data"].repeatInterval; - data.repeatLimit = args["data"].repeatLimit; - } else { - if (args["id"] !== "eff4ee-11qw23-6675-pokau97-qwedjut45a0fa_0") { - data.expirationTime = args["data"].expirationTime; - } - } - if (args["id"] !== "eff4ee-11qw23-6675-pokau97-qwedjut45a0fa_0") { - return data; - } else { - return "job not rescheduled"; - } - }, - }, - Query: { - ProcessInstances: async (parent, args) => { - let result = data.ProcessInstanceData.filter((datum) => { - console.log("args", args["where"]); - if (args["where"].id && args["where"].id.equal) { - return datum.id == args["where"].id.equal; - } else if (args["where"].rootProcessInstanceId && args["where"].rootProcessInstanceId.equal) { - return datum.rootProcessInstanceId == args["where"].rootProcessInstanceId.equal; - } else if (args["where"].parentProcessInstanceId && args["where"].parentProcessInstanceId.equal) { - return datum.parentProcessInstanceId == args["where"].parentProcessInstanceId.equal; - } else if (args["where"].parentProcessInstanceId.isNull) { - if (args["where"].or === undefined || (args["where"].or && args["where"].or.length === 0)) { - return datum.parentProcessInstanceId == null && args["where"].state.in.includes(datum.state); - } else { - if ( - datum.parentProcessInstanceId === null && - args["where"].state.in.includes(datum.state) && - datum.businessKey !== null - ) { - for (let i = 0; i < args["where"].or.length; i++) { - if ( - datum.businessKey && - datum.businessKey.toLowerCase().indexOf(args["where"].or[i].businessKey.like.toLowerCase()) > -1 - ) { - return true; - } - } - return false; - } - } - } else { - return false; - } - }); - if (args["orderBy"]) { - console.log("orderBy args: ", args["orderBy"]); - result = _.orderBy( - result, - _.keys(args["orderBy"]).map((key) => key), - _.values(args["orderBy"]).map((value) => value.toLowerCase()) - ); - } - await timeout(2000); - if (args["pagination"]) { - result = paginatedResult(result, args["pagination"].offset, args["pagination"].limit); - } - console.log("result length: " + result.length); - return result; - }, - Jobs: async (parent, args) => { - if (Object.keys(args).length > 0) { - const result = data.JobsData.filter((jobData) => { - console.log("Job data args->", args["where"].processInstanceId); - if (args["where"].processInstanceId && args["where"].processInstanceId.equal) { - return jobData.processInstanceId == args["where"].processInstanceId.equal; - } else if (args["where"].status && args["where"].status.in) { - return args["where"].status.in.includes(jobData.status); - } - }); - console.log("orderby", args["orderBy"]); - await timeout(2000); - if (args["orderBy"] && Object.values(args["orderBy"])[0] === "ASC") { - const orderArg = Object.keys(args["orderBy"])[0]; - result.sort((a, b) => { - if (orderArg === "lastUpdate" || orderArg === "expirationTime") { - return new Date(a[orderArg]) - new Date(b[orderArg]); - } else if (orderArg === "status") { - return a[orderArg].localeCompare(b[orderArg]); - } else { - return a[orderArg] - b[orderArg]; - } - }); - } else if (args["orderBy"] && Object.values(args["orderBy"])[0] === "DESC") { - const orderArg = Object.keys(args["orderBy"])[0]; - result.sort((a, b) => { - if (orderArg === "lastUpdate" || orderArg === "expirationTime") { - return new Date(b[orderArg]) - new Date(a[orderArg]); - } else if (orderArg === "status") { - return b[orderArg].localeCompare(a[orderArg]); - } else { - return b[orderArg] - a[orderArg]; - } - }); - } - if (args["pagination"]) { - return paginatedResult(result, args["pagination"].offset, args["pagination"].limit); - } - - return result; - } - }, - }, - - DateTime: new GraphQLScalarType({ - name: "DateTime", - description: "DateTime custom scalar type", - parseValue(value) { - return value; - }, - serialize(value) { - return value; - }, - parseLiteral(ast) { - return null; - }, - }), -}; - -const mocks = { - DateTime: () => new Date().toUTCString(), - Travels: () => ({ - id: () => uuidv1(), - }), - VisaApplications: () => ({ - id: () => uuidv1(), - }), -}; - -const server = new ApolloServer({ - typeDefs, - resolvers, - mocks, - mockEntireSchema: false, - introspection: true, - playground: true, -}); - -server.start().then(() => { - server.applyMiddleware({ app }); -}); - -module.exports = { - getApp: () => app, - setPort, - listen, -}; diff --git a/packages/runtime-tools-management-console-webapp/dev/server/static/flightBooking.svg b/packages/runtime-tools-management-console-webapp/dev/server/static/flightBooking.svg deleted file mode 100644 index 1659bf4f4dc..00000000000 --- a/packages/runtime-tools-management-console-webapp/dev/server/static/flightBooking.svg +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Flight Booked - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Book - - - flight - - - - - - - - - - - - - - - - - - - - - - StartProcess - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/runtime-tools-management-console-webapp/dev/server/static/hotelBooking.svg b/packages/runtime-tools-management-console-webapp/dev/server/static/hotelBooking.svg deleted file mode 100644 index 39967c5d95e..00000000000 --- a/packages/runtime-tools-management-console-webapp/dev/server/static/hotelBooking.svg +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Hotel Booked - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Book - - - hotel - - - - - - - - - - - - - - - - - - - - - - StartProcess - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/runtime-tools-management-console-webapp/dev/server/static/travels.svg b/packages/runtime-tools-management-console-webapp/dev/server/static/travels.svg deleted file mode 100644 index 17024e1267a..00000000000 --- a/packages/runtime-tools-management-console-webapp/dev/server/static/travels.svg +++ /dev/null @@ -1,1744 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Book Hotel - - - - - - - - - - - - - - - - - - - - - - StartProcess - - - - - - - - - - - - - - - - - - - - - - - - - - - - - is visa required - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - wait for visa decision - - - - - - - - - - - - - - - - - - - - - - Travel Confirmed - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Visa Rejected - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Book Flight - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Email - - - rejection - - - notice - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Confirm - - - travel - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Apply - - - for visa - - - - - - - - - - - - - - - - - - - - - - - Visa - - - check - - - - - - - - - - - - - - - - - - - - - - - - - - - - - visasapproved - - - - - - - - - - - - - - - - - - - - - - - - - - - - - visasrejected - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Book - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Send visa application - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - no need for visa - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - visa - - - required - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/runtime-tools-management-console-webapp/env/index.js b/packages/runtime-tools-management-console-webapp/env/index.js index 214cc368e07..f127c935e04 100644 --- a/packages/runtime-tools-management-console-webapp/env/index.js +++ b/packages/runtime-tools-management-console-webapp/env/index.js @@ -18,33 +18,53 @@ */ const { varsWithName, composeEnv, getOrDefault } = require("@kie-tools-scripts/build-env"); +const rootEnv = require("@kie-tools/root-env/env"); module.exports = composeEnv([require("@kie-tools/root-env/env")], { vars: varsWithName({ - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__kogitoDataIndexUrl: { - default: "http://localhost:4000/graphql", - description: "URL for the Data Index service", - }, - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__kogitoEnvMode: { - default: "DEV", - description: "DEV or PROD. PROD enables Keycloak integration", - }, - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__host: { + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__dev_host: { default: "localhost", - description: "Webpack server hostname", + description: "Webpack dev server hostname", }, - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__port: { + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__dev_port: { default: "9025", - description: "Webpack server port", + description: "Webpack dev server port", + }, + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__buildInfo: { + default: `dev (${process.env.USER}) @ ${new Date().toISOString()}`, + description: "Build information to be shown in the 'About' modal.", + }, + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__appName: { + default: "Apache KIEā„¢ Management Console", + description: "The name used to refer to a particular KIE Management Console distribution.", + }, + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__oidcClientClientId: { + default: "management-console-dev-webapp", + description: "Client ID used for OpenID Connect client configuration.", }, }), get env() { return { runtimeToolsManagementConsoleWebapp: { - kogitoDataIndexUrl: getOrDefault(this.vars.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__kogitoDataIndexUrl), - kogitoEnvMode: getOrDefault(this.vars.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__kogitoEnvMode), - host: getOrDefault(this.vars.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__host), - port: getOrDefault(this.vars.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__port), + dev: { + host: getOrDefault(this.vars.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__dev_host), + port: getOrDefault(this.vars.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__dev_port), + idp: { + port: 9071, + }, + securedRuntime: { + port: 8080, + }, + unsecuredRuntime: { + port: 8081, + }, + }, + oidcClient: { + clientId: getOrDefault(this.vars.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__oidcClientClientId), + }, + appName: getOrDefault(this.vars.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__appName), + buildInfo: getOrDefault(this.vars.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_WEBAPP__buildInfo), + version: require("../package.json").version, }, }; }, diff --git a/packages/runtime-tools-management-console-webapp/package.json b/packages/runtime-tools-management-console-webapp/package.json index b35f35f7946..27cbe4e4ccc 100644 --- a/packages/runtime-tools-management-console-webapp/package.json +++ b/packages/runtime-tools-management-console-webapp/package.json @@ -16,13 +16,16 @@ "scripts": { "build:dev": "rimraf dist && webpack --env dev", "build:prod": "pnpm lint && rimraf dist && webpack", - "dev": "concurrently 'pnpm start' 'pnpm run dev:server'", - "dev:rest-server": "nodemon ./server/restServer.js", - "dev:server": "nodemon ./dev/server/app.js", "lint": "run-script-if --bool \"$(build-env linters.run)\" --then \"kie-tools--eslint ./src\"", - "start": "webpack serve --host 0.0.0.0 --env dev" + "start": "webpack serve --host 0.0.0.0 --env dev", + "start:idp": "docker run -it --rm -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin -v ./dev-webapp/keycloak:/opt/keycloak/data/import -p 9071:8080 quay.io/keycloak/keycloak:26.0.5 start-dev --import-realm", + "start:idp-mock": "pnpm exec oauth2-mock-server -p 9071", + "start:secured-runtime": "mvn -nsu -f dev-webapp/secured-runtime quarkus:dev -Dquarkus.http.port=\"$(build-env runtimeToolsManagementConsoleWebapp.dev.securedRuntime.port)\" -Ddev-webapp.idp.port=\"$(build-env runtimeToolsManagementConsoleWebapp.dev.idp.port)\" -Drevision=\"$(build-env runtimeToolsManagementConsoleWebapp.version)\"", + "start:unsecured-runtime": "mvn -nsu -f dev-webapp/unsecured-runtime quarkus:dev -Dquarkus.http.port=\"$(build-env runtimeToolsManagementConsoleWebapp.dev.unsecuredRuntime.port)\" -Ddev-webapp.idp.port=\"$(build-env runtimeToolsManagementConsoleWebapp.dev.idp.port)\" -Drevision=\"$(build-env runtimeToolsManagementConsoleWebapp.version)\"" }, "dependencies": { + "@kie-tools-core/react-hooks": "workspace:*", + "@kie-tools-core/workspaces-git-fs": "workspace:*", "@kie-tools/runtime-tools-components": "workspace:*", "@kie-tools/runtime-tools-process-enveloped-components": "workspace:*", "@kie-tools/runtime-tools-process-gateway-api": "workspace:*", @@ -32,14 +35,19 @@ "@kie-tools/runtime-tools-shared-webapp-components": "workspace:*", "@patternfly/patternfly": "^4.224.2", "@patternfly/react-core": "^4.276.6", + "@patternfly/react-icons": "^4.93.6", + "@patternfly/react-styles": "^4.92.6", "apollo-cache-inmemory": "1.6.6", "apollo-client": "2.6.10", + "apollo-link": "^1.2.14", "apollo-link-context": "^1.0.20", "apollo-link-error": "1.1.13", "apollo-link-http": "1.5.17", "axios": "^1.7.4", "graphql": "14.3.1", "history": "^4.9.0", + "oidc-client-ts": "^3.1.0", + "openid-client": "^6.1.3", "react": "^17.0.2", "react-apollo": "3.1.3", "react-apollo-hooks": "^0.5.0", @@ -58,23 +66,26 @@ "@graphql-codegen/typescript-react-apollo": "^3.3.7", "@kie-tools-core/envelope": "workspace:*", "@kie-tools-core/envelope-bus": "workspace:*", + "@kie-tools-core/patternfly-base": "workspace:*", "@kie-tools-core/webpack-base": "workspace:*", "@kie-tools/eslint": "workspace:*", + "@kie-tools/maven-base": "workspace:*", "@kie-tools/root-env": "workspace:*", "@kie-tools/tsconfig": "workspace:*", + "@types/history": "^4.7.3", "@types/react": "^17.0.6", "@types/react-dom": "^17.0.5", "@types/react-router": "^5.1.20", "@types/react-router-dom": "^5.3.3", + "@types/uuid": "^8.3.0", "apollo-server-express": "^3.13.0", "body-parser": "^1.20.3", - "concurrently": "^8.2.2", "copy-webpack-plugin": "^11.0.0", "core-js": "3.6.5", "cors": "^2.8.5", "css-loader": "^5.2.6", "css-minimizer-webpack-plugin": "^5.0.1", - "express": "^4.21.1", + "express": "^4.21.0", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.3.2", "https-browserify": "^1.0.0", @@ -82,6 +93,7 @@ "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.7.6", "nodemon": "^3.1.4", + "oauth2-mock-server": "^7.1.2", "rimraf": "^3.0.2", "sass-loader": "^12.3.0", "serve": "^12.0.1", diff --git a/packages/runtime-tools-management-console-webapp/serve.json b/packages/runtime-tools-management-console-webapp/serve.json deleted file mode 100644 index a6a2350fd07..00000000000 --- a/packages/runtime-tools-management-console-webapp/serve.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "rewrites": [{ "source": "**/*", "destination": "/index.html" }] -} diff --git a/packages/runtime-tools-management-console-webapp/src/aboutModal/AboutButton.tsx b/packages/runtime-tools-management-console-webapp/src/aboutModal/AboutButton.tsx new file mode 100644 index 00000000000..431b2e8a73d --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/aboutModal/AboutButton.tsx @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback } from "react"; +import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button"; +import { Modal, ModalVariant } from "@patternfly/react-core/dist/js/components/Modal"; +import InfoAltIcon from "@patternfly/react-icons/dist/js/icons/info-alt-icon"; +import { Brand } from "@patternfly/react-core/dist/js/components/Brand"; +import { useRoutes } from "../navigation/Hooks"; +import { MastheadBrand } from "@patternfly/react-core/dist/js/components/Masthead"; +import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex"; +import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye"; +import { Divider } from "@patternfly/react-core/dist/js/components/Divider"; +import { + DescriptionList, + DescriptionListTerm, + DescriptionListGroup, + DescriptionListDescription, +} from "@patternfly/react-core/dist/js/components/DescriptionList"; +import { useEnv } from "../env/hooks/EnvContext"; + +export const AboutButton: React.FunctionComponent = () => { + const [isModalOpen, setIsModalOpen] = React.useState(false); + const { env } = useEnv(); + const routes = useRoutes(); + const buildInfo = process.env.WEBPACK_REPLACE__buildInfo; + const kogitoRuntimesVersion = process.env.WEBPACK_REPLACE__kogitoVersion; + const commitSha = process.env.WEBPACK_REPLACE__commitHash; + + const handleModalToggle = useCallback(() => { + setIsModalOpen((prev) => !prev); + }, []); + + return ( + + + + + + + + + + + + } + variant={ModalVariant.small} + isOpen={isModalOpen} + aria-label="About Modal" + aria-describedby="modal-title-icon-description" + onClose={handleModalToggle} + > + +
+ + + + Build version: + {buildInfo} + + + Kogito version: + {kogitoRuntimesVersion} + + + OIDC Client (client_id): + + {env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_OIDC_CLIENT_CLIENT_ID} + + + + Commit SHA: + {commitSha} + + + +
+
+
+ ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionApi.ts b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionApi.ts new file mode 100644 index 00000000000..01e4c35dbd3 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionApi.ts @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { LfsFsCache } from "@kie-tools-core/workspaces-git-fs/dist/lfs/LfsFsCache"; +import { LfsStorageService } from "@kie-tools-core/workspaces-git-fs/dist/lfs/LfsStorageService"; +import { IDToken, ServerMetadata, TokenEndpointResponse, UserInfoResponse } from "openid-client"; + +export const authSessionFsCache = new LfsFsCache(); +export const authSessionFsService = new LfsStorageService(); +export const authSessionBroadcastChannel = new BroadcastChannel("auth_sessions"); + +export const AUTH_SESSIONS_FILE_PATH = "/authSessions.json"; +export const AUTH_SESSIONS_FS_NAME = "auth_sessions"; +export const AUTH_SESSIONS_VERSION_NUMBER = 1; +export const AUTH_SESSIONS_FS_NAME_WITH_VERSION = `${AUTH_SESSIONS_FS_NAME}_v${AUTH_SESSIONS_VERSION_NUMBER.toString()}`; + +export const AUTH_SESSION_TEMP_OPENID_AUTH_DATA_STORAGE_KEY = "temporaryOpenIdAuthData"; +export const AUTH_SESSION_RUNTIME_AUTH_SERVER_URL_ENDPOINT = "kogito/security/oidc/auth-server-url"; +export const AUTH_SESSION_RUNTIME_ME_ENDPOINT = "kogito/security/me"; + +export function mapSerializer(_: string, value: any) { + if (value instanceof Map) { + return { + __$$jsClassName: "Map", + value: Array.from(value.entries()), + }; + } + return value; +} + +export function mapDeSerializer(_: string, value: any) { + if (typeof value === "object" && value) { + if (value.__$$jsClassName === "Map") { + return new Map(value.value); + } + } + return value; +} + +export type OpenIDConfiguration = { + issuer: string; + token_endpoint: string; + authorization_endpoint: string; + userinfo_endpoint: string; + token_endpoint_auth_methods_supported?: string[]; + jwks_uri: string; + response_types_supported?: string[]; + grant_types_supported?: string[]; + token_endpoint_auth_signing_alg_values_supported?: string[]; + response_modes_supported?: string[]; + id_token_signing_alg_values_supported?: string[]; + revocation_endpoint: string; + subject_types_supported?: string[]; + end_session_endpoint: string; + introspection_endpoint: string; +}; + +export enum AuthSessionType { + OPENID_CONNECT = "oidc", + UNAUTHENTICATED = "unauthenticaded", +} + +export type OpenIDConnectAuthSession = { + id: string; + type: AuthSessionType.OPENID_CONNECT; + version: number; + name: string; + tokens: TokenEndpointResponse; + username?: string; + roles?: string[]; + impersonator?: boolean; + claims: IDToken; + issuer: string; + userInfo: UserInfoResponse; + clientId: string; + clientSecret?: string; + runtimeUrl: string; + status: AuthSessionStatus; + createdAtDateISO: string; + tokensRefreshedAtDateISO: string; +}; + +export type UnauthenticatedAuthSession = { + id: string; + type: AuthSessionType.UNAUTHENTICATED; + version: number; + name: string; + impersonator: true; + runtimeUrl: string; + status: AuthSessionStatus; + createdAtDateISO: string; +}; + +export type AuthSession = OpenIDConnectAuthSession | UnauthenticatedAuthSession; + +export type OidcAuthUrlParameters = { + redirect_uri: string; + scope: string; + code_verifier: string; + code_challenge: string; + code_challenge_method: string; + nonce?: string; + prompt?: string; +}; + +export type TemporaryAuthSessionData = + | { + isAuthenticationRequired: true; + runtimeUrl: string; + clientId: string; + name: string; + parameters: OidcAuthUrlParameters; + serverMetadata: ServerMetadata; + } + | { + isAuthenticationRequired: false; + runtimeUrl: string; + name: string; + }; + +export enum AuthSessionStatus { + VALID, + INVALID, +} + +export function isOpenIdConnectAuthSession(authSession?: AuthSession): authSession is OpenIDConnectAuthSession { + return authSession?.type === AuthSessionType.OPENID_CONNECT; +} + +export function isUnauthenticatedAuthSession(authSession?: AuthSession): authSession is UnauthenticatedAuthSession { + return authSession?.type === AuthSessionType.UNAUTHENTICATED; +} + +export function getAuthSessionDisplayInfo(authSession: AuthSession) { + // username @ http://runtime.url + const shortDisplayName = `${isOpenIdConnectAuthSession(authSession) ? `${authSession.username ?? "Unknown user"} @ ` : "Unknown user @ "}${authSession.runtimeUrl}`; + // Session Name [username @ http://runtime.url] + const fullDisplayName = `${authSession.name} (${shortDisplayName})`; + // username @ Auth Session Name + const userFriendlyName = `${isOpenIdConnectAuthSession(authSession) ? `${authSession.username ?? "Unknown user"} @ ` : "Unknown user @ "}${authSession.name}`; + // OpenID Connect | Unauthenticaded + const type = isOpenIdConnectAuthSession(authSession) ? "OpenID Connect" : "Unauthenticaded"; + + return { + shortDisplayName, + fullDisplayName, + userFriendlyName, + type, + }; +} + +export function parseJwtToken(token: string) { + const base64Url = token.split(".")[1]; + const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/"); + const jsonPayload = decodeURIComponent( + window + .atob(base64) + .split("") + .map((c) => { + return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); + }) + .join("") + ); + + return JSON.parse(jsonPayload); +} diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionMigrations.ts b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionMigrations.ts new file mode 100644 index 00000000000..d8fcf560c9d --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionMigrations.ts @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { decoder } from "@kie-tools-core/workspaces-git-fs/dist/encoderdecoder/EncoderDecoder"; +import { + AUTH_SESSIONS_FILE_PATH, + AUTH_SESSIONS_FS_NAME, + AUTH_SESSIONS_VERSION_NUMBER, + AuthSession, + authSessionFsCache, + authSessionFsService, + mapDeSerializer, +} from "./AuthSessionApi"; + +export async function getAuthSessionsFromVersion(version?: number) { + const authSessionFsName = version && version >= 0 ? `${AUTH_SESSIONS_FS_NAME}_v${version}` : AUTH_SESSIONS_FS_NAME; + const fs = authSessionFsCache.getOrCreateFs(authSessionFsName); + const authSessionsFile = await authSessionFsService.getFile(fs, AUTH_SESSIONS_FILE_PATH); + if (!authSessionsFile) { + return []; + } + const content = await authSessionsFile.getFileContents(); + const parsedAuthSessions = Array.from(JSON.parse(decoder.decode(content), mapDeSerializer)); + return parsedAuthSessions; +} + +export async function getAllAuthSessions() { + let allAuthSessions: any[] = []; + for (let i = AUTH_SESSIONS_VERSION_NUMBER; i >= 0; i--) { + const authSessions = await getAuthSessionsFromVersion(i); + allAuthSessions = allAuthSessions.concat(authSessions); + } + return allAuthSessions; +} + +export async function deleteOlderAuthSessionsStorage() { + for (let i = AUTH_SESSIONS_VERSION_NUMBER - 1; i >= 0; i--) { + const authSessionFsName = i && i >= 0 ? `${AUTH_SESSIONS_FS_NAME}_v${i}` : AUTH_SESSIONS_FS_NAME; + const fs = authSessionFsCache.getOrCreateFs(authSessionFsName); + if (await authSessionFsService.exists(fs, AUTH_SESSIONS_FILE_PATH)) { + await authSessionFsService.deleteFile(fs, AUTH_SESSIONS_FILE_PATH); + } + await fs.deactivate(); + indexedDB.deleteDatabase(authSessionFsName); + } +} + +export async function migrateAuthSessions() { + const olderAuthSessions = await getAllAuthSessions(); + const migratedAuthSessions = new Map(); + for (const [key, authSession] of olderAuthSessions) { + try { + const migratedAuthSession = await applyAuthSessionMigrations(authSession); + migratedAuthSessions.set(key, migratedAuthSession); + } catch (e) { + console.error("Failed to apply migrations to auth session", { + id: authSession.id, + authProvider: authSession.authProviderId, + host: authSession.host, + }); + } + } + return migratedAuthSessions; +} + +export async function applyAuthSessionMigrations(authSession: any): Promise { + if (authSession.version && authSession.version > AUTH_SESSIONS_VERSION_NUMBER) { + throw new Error( + `Failed to apply migration script to AuthSession: ${authSession.id}. Version is greater than current version.` + ); + } + const newAuthSession = { + ...authSession, + }; + + switch (authSession.version) { + case undefined: + case 1: + // Already at current version. Nothing to do. + default: + break; + } + + return newAuthSession; +} diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionsContext.tsx b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionsContext.tsx new file mode 100644 index 00000000000..9547a8657ea --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionsContext.tsx @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { createContext, PropsWithChildren, useCallback, useContext, useEffect, useMemo, useState } from "react"; +import { useCancelableEffect } from "@kie-tools-core/react-hooks/dist/useCancelableEffect"; +import { decoder, encoder } from "@kie-tools-core/workspaces-git-fs/dist/encoderdecoder/EncoderDecoder"; +import { LfsStorageFile } from "@kie-tools-core/workspaces-git-fs/dist/lfs/LfsStorageService"; +import { + AuthSession, + AuthSessionStatus, + authSessionFsCache, + authSessionFsService, + mapDeSerializer, + AUTH_SESSIONS_FILE_PATH, + AUTH_SESSIONS_FS_NAME_WITH_VERSION, + mapSerializer, + authSessionBroadcastChannel, + isOpenIdConnectAuthSession, + isUnauthenticatedAuthSession, +} from "./AuthSessionApi"; +import { deleteOlderAuthSessionsStorage, migrateAuthSessions } from "./AuthSessionMigrations"; +import { AuthSessionsService } from "./AuthSessionsService"; +import { useEnv } from "../env/hooks/EnvContext"; + +export type AuthSessionsContextType = { + authSessions: Map; + isNewAuthSessionModalOpen: boolean; + isAuthSessionsReady: boolean; + currentAuthSession?: AuthSession; + onSelectAuthSession?: (authSession: AuthSession) => void; +}; + +export type AuthSessionsDispatchContextType = { + reauthAllAndUpdateStatus: () => void; + add: (authSession: AuthSession) => Promise; + remove: (authSession: AuthSession) => void; + setIsNewAuthSessionModalOpen: React.Dispatch>; + setCurrentAuthSession: React.Dispatch>; + setOnSelectAuthSession: React.Dispatch void) | undefined>>; +}; + +const AuthSessionsContext = createContext({} as AuthSessionsContextType); +const AuthSessionsDispatchContext = createContext( + {} as AuthSessionsDispatchContextType +); + +export function useAuthSessions() { + return useContext(AuthSessionsContext); +} + +export function useAuthSessionsDispatch() { + return useContext(AuthSessionsDispatchContext); +} + +export function AuthSessionsContextProvider(props: PropsWithChildren<{}>) { + const [authSessions, setAuthSessions] = useState>(new Map()); + const [isNewAuthSessionModalOpen, setIsNewAuthSessionModalOpen] = useState(false); + const [isAuthSessionsReady, setIsAuthSessionsReady] = useState(false); + const [currentAuthSession, setCurrentAuthSession] = useState(); + const [onSelectAuthSession, setOnSelectAuthSession] = useState<(authSession: AuthSession) => void>(); + const { env } = useEnv(); + + const getAuthSessionsFromFile = useCallback(async () => { + const fs = authSessionFsCache.getOrCreateFs(AUTH_SESSIONS_FS_NAME_WITH_VERSION); + if (await authSessionFsService.exists(fs, AUTH_SESSIONS_FILE_PATH)) { + const content = await (await authSessionFsService.getFile(fs, AUTH_SESSIONS_FILE_PATH))?.getFileContents(); + const parsedAuthSessions = JSON.parse(decoder.decode(content), mapDeSerializer); + return parsedAuthSessions; + } + return []; + }, []); + + const refresh = useCallback(async () => { + setAuthSessions(await getAuthSessionsFromFile()); + }, [getAuthSessionsFromFile]); + + const persistAuthSessions = useCallback( + async (map: Map) => { + const fs = authSessionFsCache.getOrCreateFs(AUTH_SESSIONS_FS_NAME_WITH_VERSION); + await authSessionFsService.createOrOverwriteFile( + fs, + new LfsStorageFile({ + path: AUTH_SESSIONS_FILE_PATH, + getFileContents: async () => encoder.encode(JSON.stringify(map, mapSerializer)), + }) + ); + + // This goes to other broadcast channel instances, on other tabs + authSessionBroadcastChannel.postMessage("UPDATE_AUTH_SESSIONS"); + + // This updates this tab + await refresh(); + }, + [refresh] + ); + + const add = useCallback( + async (authSession: AuthSession) => { + const n = new Map(authSessions?.entries() ?? []); + n.forEach((existingAuthSession) => { + if (isOpenIdConnectAuthSession(authSession)) { + if ( + isOpenIdConnectAuthSession(existingAuthSession) && + existingAuthSession.runtimeUrl === authSession.runtimeUrl && + existingAuthSession.username === authSession.username + ) { + console.log("Authenticated AuthSession with same runtimeUrl and username found. Replacing it!"); + authSession.id = existingAuthSession.id; + } + } else { + if ( + isUnauthenticatedAuthSession(existingAuthSession) && + existingAuthSession.runtimeUrl === authSession.runtimeUrl + ) { + console.log("Unauthenticated AuthSession with same runtimeUrl found. Replacing it!"); + authSession.id = existingAuthSession.id; + } + } + }); + n?.set(authSession.id, authSession); + await persistAuthSessions(n); + }, + [authSessions, persistAuthSessions] + ); + + const remove = useCallback( + (authSession: AuthSession) => { + const n = new Map(authSessions?.entries() ?? []); + n?.delete(authSession.id); + persistAuthSessions(n); + }, + [authSessions, persistAuthSessions] + ); + + // Update after persisted + useEffect(() => { + authSessionBroadcastChannel.onmessage = refresh; + }, [refresh]); + + const reauthSessionsAndCalculateStatus = useCallback( + async (authSessions: Map) => { + const updatedSessions = await Promise.all( + [...(authSessions?.values() ?? [])].map(async (authSession) => { + try { + if (isOpenIdConnectAuthSession(authSession)) { + const newAuthSessionData = await AuthSessionsService.reauthenticate({ + authSession, + clientId: env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_OIDC_CLIENT_CLIENT_ID, + }); + return { + ...authSession, + ...newAuthSessionData, + }; + } else { + return { + ...authSession, + status: AuthSessionStatus.VALID, + }; + } + } catch (e) { + return { ...authSession, status: AuthSessionStatus.INVALID }; + } + }) + ); + + return new Map(updatedSessions.map((authSession) => [authSession.id, authSession])); + }, + [env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_OIDC_CLIENT_CLIENT_ID] + ); + + // Init + useCancelableEffect( + useCallback( + ({ canceled }) => { + const run = async () => { + const migratedAuthSessions = await migrateAuthSessions(); + if (canceled.get()) { + return; + } + + const updatedAuthSessions = await reauthSessionsAndCalculateStatus(migratedAuthSessions); + + if (canceled.get()) { + return; + } + + await persistAuthSessions(updatedAuthSessions); + await deleteOlderAuthSessionsStorage(); + }; + run().then(() => { + setIsAuthSessionsReady(true); + }); + }, + [persistAuthSessions, reauthSessionsAndCalculateStatus] + ) + ); + + const reauthAllAndUpdateStatus = useCallback(async () => { + const updatedAuthSessions = await reauthSessionsAndCalculateStatus(authSessions); + await persistAuthSessions(updatedAuthSessions); + }, [authSessions, persistAuthSessions, reauthSessionsAndCalculateStatus]); + + const dispatch = useMemo(() => { + return { + add, + remove, + reauthAllAndUpdateStatus, + setIsNewAuthSessionModalOpen, + setCurrentAuthSession, + setOnSelectAuthSession, + }; + }, [add, reauthAllAndUpdateStatus, remove, setOnSelectAuthSession]); + + const value = useMemo(() => { + return { + authSessions, + isNewAuthSessionModalOpen, + isAuthSessionsReady, + currentAuthSession, + onSelectAuthSession, + }; + }, [authSessions, isNewAuthSessionModalOpen, isAuthSessionsReady, currentAuthSession, onSelectAuthSession]); + + return ( + <> + {value && isAuthSessionsReady && ( + + {props.children} + + )} + + ); +} + +export function useAuthSession(authSessionId?: string) { + const { authSessions } = useAuthSessions(); + + const authSession = useMemo(() => { + if (!authSessionId) { + return undefined; + } else { + return authSessions.get(authSessionId); + } + }, [authSessionId, authSessions]); + return { authSession }; +} diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionsService.ts b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionsService.ts new file mode 100644 index 00000000000..413a11dc3c6 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionsService.ts @@ -0,0 +1,304 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 * as client from "openid-client"; +import { + AUTH_SESSION_RUNTIME_AUTH_SERVER_URL_ENDPOINT, + AUTH_SESSION_RUNTIME_ME_ENDPOINT, + AUTH_SESSION_TEMP_OPENID_AUTH_DATA_STORAGE_KEY, + AUTH_SESSIONS_VERSION_NUMBER, + AuthSession, + AuthSessionStatus, + AuthSessionType, + isUnauthenticatedAuthSession, + OidcAuthUrlParameters, + OpenIDConnectAuthSession, + TemporaryAuthSessionData, + UnauthenticatedAuthSession, +} from "./AuthSessionApi"; +import path from "path"; +import { v4 as uuid } from "uuid"; + +export class AuthSessionsService { + static async getIdentityProviderConfig(args: { authServerUrl: string; clientId: string }) { + const authUrl = new URL(args.authServerUrl); + const options = authUrl.protocol === "http:" ? { execute: [client.allowInsecureRequests] } : {}; + const config: client.Configuration = await client.discovery(authUrl, args.clientId, undefined, undefined, options); + return config; + } + + static async buildAuthParameters(args: { + config: client.Configuration; + loginSuccessRoute: string; + forceLoginPrompt?: boolean; + }) { + const code_challenge_method = "S256"; + /** + * The following (code_verifier and potentially nonce) MUST be generated for + * every redirect to the authorization_endpoint. You must store the + * code_verifier and nonce in the end-user session such that it can be recovered + * as the user gets redirected from the authorization server back to your + * application. + */ + const code_verifier = client.randomPKCECodeVerifier(); + const code_challenge = await client.calculatePKCECodeChallenge(code_verifier); + let nonce: string | undefined = undefined; + + // redirect user to as.authorization_endpoint + const parameters: OidcAuthUrlParameters = { + redirect_uri: args.loginSuccessRoute, + scope: "openid email", + code_verifier, + code_challenge, + code_challenge_method, + ...(args.forceLoginPrompt ? { prompt: "login" } : {}), + }; + + /** + * We cannot be sure the AS supports PKCE so we're going to use nonce too. Use + * of PKCE is backwards compatible even if the AS doesn't support it which is + * why we're using it regardless. + */ + if (!args.config.serverMetadata().supportsPKCE()) { + nonce = client.randomNonce(); + parameters.nonce = nonce; + } + + return parameters; + } + + static async redirectToIdentityProviderLogin(args: { + name: string; + runtimeUrl: string; + clientId: string; + config: client.Configuration; + parameters: OidcAuthUrlParameters; + }) { + const redirectTo = client.buildAuthorizationUrl(args.config, args.parameters); + + const tempOpenIdAuthData: TemporaryAuthSessionData = { + isAuthenticationRequired: true, + runtimeUrl: args.runtimeUrl, + clientId: args.clientId, + name: args.name, + parameters: args.parameters, + serverMetadata: args.config.serverMetadata(), + }; + + window.localStorage.setItem(AUTH_SESSION_TEMP_OPENID_AUTH_DATA_STORAGE_KEY, JSON.stringify(tempOpenIdAuthData)); + + window.location.href = redirectTo.href; + } + + static async getIdentityProviderUrl(runtimeUrl: string) { + const newPath = path.join(new URL(runtimeUrl).pathname, AUTH_SESSION_RUNTIME_AUTH_SERVER_URL_ENDPOINT); + const response = await fetch(new URL(newPath, runtimeUrl)); + if (response.status !== 200) { + throw new Error("No authentication endpoint found."); + } + return await response.text(); + } + + static async checkIfAuthenticationRequired(runtimeUrl: string): Promise< + | { + isAuthenticationRequired: true; + authServerUrl: string; + } + | { isAuthenticationRequired: false } + > { + try { + const authServerUrl = await AuthSessionsService.getIdentityProviderUrl(runtimeUrl); + return { + isAuthenticationRequired: true, + authServerUrl, + }; + } catch (authServerError) { + // Maybe not required? + // Does the runtime exist? + // If 200, then runtime exists and is not asking for authentication + const response = await fetch(runtimeUrl); + if (response.status === 200 || response.status === 404) { + return { + isAuthenticationRequired: false, + }; + } else if (response.status === 401 || response.status === 403) { + throw new Error( + `Runtime server ${runtimeUrl} requires authentication but didn't provide the Identity Provider URL!` + ); + } else { + throw new Error(`Ivalid response from runtime server: ${runtimeUrl}! Is the URL correct?`); + } + } + } + + static async authenticate(args: { + runtimeUrl: string; + authServerUrl: string; + clientId: string; + name: string; + forceLoginPrompt?: boolean; + loginSuccessRoute: string; + }) { + const config = await AuthSessionsService.getIdentityProviderConfig(args); + + const parameters = await AuthSessionsService.buildAuthParameters({ + config, + loginSuccessRoute: args.loginSuccessRoute, + forceLoginPrompt: args.forceLoginPrompt, + }); + + await AuthSessionsService.redirectToIdentityProviderLogin({ ...args, config, parameters }); + } + + static async logout(args: { authSession: AuthSession; clientId: string }) { + if (isUnauthenticatedAuthSession(args.authSession)) { + return; + } + + const config = await AuthSessionsService.getIdentityProviderConfig({ + authServerUrl: args.authSession.issuer, + clientId: args.clientId, + }); + + if (!args.authSession.tokens.refresh_token) { + throw new Error(`No refresh_token found for AuthSession ${args.authSession.id}!`); + } + + const endSessionUrl = client.buildEndSessionUrl(config, { + post_logout_redirect_uri: window.location.href, + id_token_hint: args.authSession.tokens.id_token!, + }); + + window.location.href = endSessionUrl.toString(); + } + + static async reauthenticate(args: { authSession: OpenIDConnectAuthSession; clientId: string }) { + const config = await AuthSessionsService.getIdentityProviderConfig({ + authServerUrl: args.authSession.issuer, + clientId: args.clientId, + }); + + if (!args.authSession.tokens.refresh_token) { + throw new Error(`No refresh_token found for AuthSession ${args.authSession.id}!`); + } + + const tokens = await client.refreshTokenGrant(config, args.authSession.tokens.refresh_token); + + const { access_token } = tokens; + const claims = tokens.claims(); + if (!claims) { + // expires_in was not returned by the authorization server + throw new Error("Failed to extract claims from token."); + } + const { sub } = claims; + const userInfo = await client.fetchUserInfo(config, access_token, sub); + + return { + tokens, + claims, + userInfo, + tokensRefreshedAtDateISO: new Date(Date.now()).toISOString(), + status: AuthSessionStatus.VALID, + }; + } + + static getTemporaryAuthSessionData() { + return JSON.parse( + window.localStorage.getItem(AUTH_SESSION_TEMP_OPENID_AUTH_DATA_STORAGE_KEY)! + ) as TemporaryAuthSessionData; + } + + static cleanTemporaryAuthSessionData() { + window.localStorage.removeItem(AUTH_SESSION_TEMP_OPENID_AUTH_DATA_STORAGE_KEY); + } + + static async buildAuthSession(temporaryAuthSessionData: TemporaryAuthSessionData): Promise { + if (!temporaryAuthSessionData.isAuthenticationRequired) { + const authSession: UnauthenticatedAuthSession = { + id: uuid(), + type: AuthSessionType.UNAUTHENTICATED, + version: AUTH_SESSIONS_VERSION_NUMBER, + name: temporaryAuthSessionData.name, + impersonator: true, + runtimeUrl: temporaryAuthSessionData.runtimeUrl, + status: AuthSessionStatus.VALID, + createdAtDateISO: new Date(Date.now()).toISOString(), + }; + return Promise.resolve(authSession); + } + + const config = new client.Configuration(temporaryAuthSessionData.serverMetadata, temporaryAuthSessionData.clientId); + if (new URL(temporaryAuthSessionData.serverMetadata.issuer).protocol === "http:") { + client.allowInsecureRequests(config); + } + + // Authorization Code Grant + const currentUrl: URL = new URL(window.location.href); + const tokens = await client.authorizationCodeGrant(config, currentUrl, { + pkceCodeVerifier: temporaryAuthSessionData.parameters.code_verifier, + expectedNonce: temporaryAuthSessionData.parameters.nonce, + idTokenExpected: true, + }); + + const { access_token } = tokens; + const claims = tokens.claims(); + if (!claims) { + // expires_in was not returned by the authorization server + throw new Error("Failed to extract claims from token."); + } + const { sub } = claims; + const userInfo = await client.fetchUserInfo(config, access_token, sub); + + const meEndpointPath = path.join( + new URL(temporaryAuthSessionData.runtimeUrl).pathname, + AUTH_SESSION_RUNTIME_ME_ENDPOINT + ); + + const meEndpointUrl = new URL(meEndpointPath, temporaryAuthSessionData.runtimeUrl); + + const runtimeUserInfoResponse = await fetch(meEndpointUrl, { + headers: { + Authorization: `Bearer ${access_token}`, + }, + }); + + const runtimeUserInfoData = await runtimeUserInfoResponse.json(); + + const authSession: OpenIDConnectAuthSession = { + id: uuid(), + type: AuthSessionType.OPENID_CONNECT, + version: AUTH_SESSIONS_VERSION_NUMBER, + name: temporaryAuthSessionData.name, + username: runtimeUserInfoData.name ?? userInfo.preferred_username, + roles: runtimeUserInfoData.roles ?? [], + impersonator: runtimeUserInfoData.impersonator, + clientId: temporaryAuthSessionData.clientId, + tokens, + claims, + runtimeUrl: temporaryAuthSessionData.runtimeUrl, + issuer: temporaryAuthSessionData.serverMetadata.issuer, + userInfo: userInfo, + status: AuthSessionStatus.VALID, + createdAtDateISO: new Date(Date.now()).toISOString(), + tokensRefreshedAtDateISO: new Date(Date.now()).toISOString(), + }; + + return authSession; + } +} diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/components/AuthSessionSelect.tsx b/packages/runtime-tools-management-console-webapp/src/authSessions/components/AuthSessionSelect.tsx new file mode 100644 index 00000000000..ff80ef0892d --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/components/AuthSessionSelect.tsx @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback } from "react"; +import { + Select, + SelectOption, + SelectPosition, + SelectProps, + SelectVariant, +} from "@patternfly/react-core/dist/js/components/Select"; +import { useAuthSessionsDispatch, useAuthSessions } from "../AuthSessionsContext"; +import { useMemo, useState } from "react"; +import { ValidatedOptions } from "@patternfly/react-core/dist/js/helpers"; +import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button"; +import { PlusIcon } from "@patternfly/react-icons/dist/js/icons/plus-icon"; +import { ExclamationCircleIcon } from "@patternfly/react-icons/dist/js/icons/exclamation-circle-icon"; +import { UserIcon } from "@patternfly/react-icons/dist/js/icons/user-icon"; +import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex"; +import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip"; +import { AuthSession, AuthSessionStatus, getAuthSessionDisplayInfo } from "../AuthSessionApi"; +import { useRoutes } from "../../navigation/Hooks"; +import { useHistory } from "react-router"; + +export type AuthSessionSelectProps = { + isPlain: boolean; + position?: SelectPosition; + menuAppendTo?: SelectProps["menuAppendTo"]; +}; + +export function AuthSessionSelect({ isPlain, position, menuAppendTo }: AuthSessionSelectProps) { + const [isAuthSessionSelectorOpen, setAuthSessionSelectorOpen] = useState(false); + const { authSessions } = useAuthSessions(); + const { setIsNewAuthSessionModalOpen } = useAuthSessionsDispatch(); + const { currentAuthSession, onSelectAuthSession } = useAuthSessions(); + const routes = useRoutes(); + const history = useHistory(); + + const validated = useMemo(() => { + if (!currentAuthSession) { + return ValidatedOptions.warning; // no authSession selected + } + return ValidatedOptions.default; + }, [currentAuthSession]); + + const unfilteredItems = useMemo(() => { + return [...authSessions.values()].map((authSession) => { + return { + authSession, + status: authSession.status, + }; + }); + }, [authSessions]); + + const onSelect = useCallback( + (e: React.ChangeEvent, value: string) => { + e.stopPropagation(); + setAuthSessionSelectorOpen(false); + if (!value) { + return; + } + + const selectedAuthSession = authSessions.get(value); + if (selectedAuthSession) { + onSelectAuthSession?.(selectedAuthSession); + } + }, + [authSessions, onSelectAuthSession] + ); + + return ( + + ); +} + +export function InvalidAuthSessionIcon() { + return ( + + <> + + + + ); +} diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/components/AuthSessionsList.tsx b/packages/runtime-tools-management-console-webapp/src/authSessions/components/AuthSessionsList.tsx new file mode 100644 index 00000000000..d763b19220e --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/components/AuthSessionsList.tsx @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button"; +import { + Card, + CardActions, + CardBody, + CardExpandableContent, + CardHeader, + CardHeaderMain, +} from "@patternfly/react-core/dist/js/components/Card"; +import { Stack } from "@patternfly/react-core/dist/js/layouts/Stack"; +import { useAuthSessions, useAuthSessionsDispatch } from "../AuthSessionsContext"; +import React, { useCallback, useState } from "react"; +import { + DescriptionList, + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, +} from "@patternfly/react-core/dist/js/components/DescriptionList"; +import { Divider } from "@patternfly/react-core/dist/js/components/Divider"; +import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text"; +import ExclamationCircleIcon from "@patternfly/react-icons/dist/js/icons/exclamation-circle-icon"; +import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip"; +import { + AuthSession, + AuthSessionStatus, + getAuthSessionDisplayInfo, + isOpenIdConnectAuthSession, +} from "../AuthSessionApi"; +import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex"; + +export function AuthSessionsList({ + onSelectAuthSession, +}: { + onSelectAuthSession: undefined | ((authSession: AuthSession) => void); +}) { + const { authSessions } = useAuthSessions(); + + return ( + <> + + {[...authSessions.values()].map((authSession) => ( + + ))} + + + ); +} + +function AuthSessionCard({ + authSession, + onSelectAuthSession, +}: { + authSession: AuthSession; + onSelectAuthSession: undefined | ((authSession: AuthSession) => void); +}) { + const authSessionsDispatch = useAuthSessionsDispatch(); + const [isExpanded, setExpanded] = useState(false); + + const onSelect = useCallback(() => { + if (authSession.status === AuthSessionStatus.VALID) { + onSelectAuthSession?.(authSession); + } + }, [authSession, onSelectAuthSession]); + + return ( + + { + e.stopPropagation(); + return setExpanded((prev) => !prev); + }} + > + + {authSession.status === AuthSessionStatus.INVALID && ( + + + + )} + + + + + + {`${getAuthSessionDisplayInfo(authSession).userFriendlyName}`} + + + + + + + <> +
+ +
+ + +
+
+
+ ); +} + +export function AuthSessionDescriptionList(props: { authSession: AuthSession }) { + return ( + <> + + + Name: + {props.authSession.name} + + <> + + Runtime URL: + {props.authSession.runtimeUrl} + + {isOpenIdConnectAuthSession(props.authSession) && ( + <> + + Token: + + {obfuscate(props.authSession.tokens.access_token)} +   + {`(...plus ${(props.authSession.tokens.access_token ?? "").length - 16} hidden characters)`} + + + + Refresh Token: + + {obfuscate(props.authSession.tokens.refresh_token ?? "")} +   + {`(...plus ${(props.authSession.tokens.refresh_token ?? "").length - 16} hidden characters)`} + + + + Issuer: + {props.authSession.issuer} + + + )} + + Can impersonate: + {props.authSession.impersonator ? "Yes" : "No"} + + + Created at: + {props.authSession.createdAtDateISO} + + + + + ); +} + +export function obfuscate(token: string) { + if (token.length <= 8) { + return token; + } + + const stars = new Array(token.length - 8).join("*"); + const pieceToObfuscate = token.substring(4, token.length - 4); + return token.replace(pieceToObfuscate, stars).replace(/[*]{8,}/g, "********"); +} diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/components/NewAuthSessionLoginSuccessPage.tsx b/packages/runtime-tools-management-console-webapp/src/authSessions/components/NewAuthSessionLoginSuccessPage.tsx new file mode 100644 index 00000000000..7d3a336b77a --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/components/NewAuthSessionLoginSuccessPage.tsx @@ -0,0 +1,73 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useEffect, useRef } from "react"; +import { useAuthSessions, useAuthSessionsDispatch } from "../AuthSessionsContext"; +import { useHistory } from "react-router"; +import { AuthSessionsService } from "../AuthSessionsService"; +import { ManagementConsolePageLayout } from "../../managementConsole/ManagementConsolePageLayout"; +import { useRoutes } from "../../navigation/Hooks"; +import { AuthSession } from "../AuthSessionApi"; +import { PageSection } from "@patternfly/react-core/dist/js/components/Page"; +import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye"; + +type Props = { + onAddAuthSession?: (authSession: AuthSession) => void; +}; + +export const NewAuthSessionLoginSuccessPage: React.FC = ({ onAddAuthSession }) => { + const { add } = useAuthSessionsDispatch(); + const { isAuthSessionsReady } = useAuthSessions(); + const history = useHistory(); + const routes = useRoutes(); + + // Since Code Grants can only be used once we want to make sure that the + // addAuthSession function in the useEffect is only called once. + const isGettingTokens = useRef(false); + + useEffect(() => { + if (!isAuthSessionsReady || isGettingTokens.current) { + return; + } + const addAuthSession = async () => { + isGettingTokens.current = true; + const authSession = await AuthSessionsService.buildAuthSession(AuthSessionsService.getTemporaryAuthSessionData()); + await add(authSession); + AuthSessionsService.cleanTemporaryAuthSessionData(); + if (onAddAuthSession) { + onAddAuthSession(authSession); + } else { + history.push(routes.home.path({})); + } + }; + + addAuthSession(); + }, [add, history, isAuthSessionsReady, onAddAuthSession, routes.home]); + + return ( + + + +

Login success!

+

Redirecting...

+
+
+
+ ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/components/NewAuthSessionModal.tsx b/packages/runtime-tools-management-console-webapp/src/authSessions/components/NewAuthSessionModal.tsx new file mode 100644 index 00000000000..9836f5dcdea --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/components/NewAuthSessionModal.tsx @@ -0,0 +1,187 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback, useState } from "react"; +import { Modal, ModalVariant } from "@patternfly/react-core/dist/js/components/Modal"; +import { Button, ButtonType, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button"; +import { useAuthSessions, useAuthSessionsDispatch } from "../AuthSessionsContext"; +import { AuthSessionsService } from "../AuthSessionsService"; +import { useEnv } from "../../env/hooks/EnvContext"; +import { useRoutes } from "../../navigation/Hooks"; +import { AuthSession } from "../AuthSessionApi"; +import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput"; +import { Form, FormGroup, ActionGroup } from "@patternfly/react-core/dist/js/components/Form"; +import { Checkbox } from "@patternfly/react-core/dist/js/components/Checkbox"; + +type Props = { + onAddAuthSession: (authSession: AuthSession) => void; +}; + +export const NewAuthSessionModal: React.FC = ({ onAddAuthSession }) => { + const [runtimeUrl, setRuntimeUrl] = useState(); + const [alias, setAlias] = useState(); + const [forceLoginPrompt, setForceLoginPrompt] = useState(false); + const routes = useRoutes(); + const { env } = useEnv(); + + const { isNewAuthSessionModalOpen } = useAuthSessions(); + const { setIsNewAuthSessionModalOpen, add } = useAuthSessionsDispatch(); + const [error, setError] = useState(null); + const [isLoading, setLoading] = useState(false); + + const onCancel = useCallback(() => { + setIsNewAuthSessionModalOpen(false); + setRuntimeUrl(""); + setAlias(""); + }, [setIsNewAuthSessionModalOpen]); + + const onConnect = useCallback( + (e) => { + e.stopPropagation(); + e.preventDefault(); + + async function c() { + try { + setError(null); + + if (!runtimeUrl || !alias) { + setError("Both Alias and URL are required."); + return; + } + + try { + new URL(runtimeUrl); + } catch (e) { + setError("Invalid URL."); + return; + } + + const checkResults = await AuthSessionsService.checkIfAuthenticationRequired(runtimeUrl); + + if (checkResults.isAuthenticationRequired) { + await AuthSessionsService.authenticate({ + runtimeUrl, + authServerUrl: checkResults.authServerUrl, + clientId: env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_OIDC_CLIENT_CLIENT_ID, + name: alias, + forceLoginPrompt, + loginSuccessRoute: routes.login.url({ base: window.location.origin, pathParams: {} }), + }); + } else { + const authSession = await AuthSessionsService.buildAuthSession({ + runtimeUrl, + name: alias, + isAuthenticationRequired: checkResults.isAuthenticationRequired, + }); + + await add(authSession); + + AuthSessionsService.cleanTemporaryAuthSessionData(); + + onAddAuthSession(authSession); + setIsNewAuthSessionModalOpen(false); + } + } catch (e) { + console.log(e); + setError(`Could not communicate with runtime running at '${runtimeUrl}'`); + } finally { + setLoading(false); + } + } + + setLoading(true); + c(); + }, + [ + runtimeUrl, + alias, + forceLoginPrompt, + env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_OIDC_CLIENT_CLIENT_ID, + routes.login, + add, + onAddAuthSession, + setIsNewAuthSessionModalOpen, + ] + ); + + return ( + +
+ + + + + + + + setForceLoginPrompt(checked)} + label={ + + Force login prompt (for secured runtimes only) + + } + tabIndex={3} + /> + + + + + + +
+
+ ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/components/index.ts b/packages/runtime-tools-management-console-webapp/src/authSessions/components/index.ts new file mode 100644 index 00000000000..6d50c799520 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/components/index.ts @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 * from "./AuthSessionSelect"; +export * from "./AuthSessionsList"; +export * from "./NewAuthSessionLoginSuccessPage"; +export * from "./NewAuthSessionModal"; diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/index.ts b/packages/runtime-tools-management-console-webapp/src/authSessions/index.ts new file mode 100644 index 00000000000..4683757ed65 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/index.ts @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 * from "./components"; +export * from "./AuthSessionApi"; +export * from "./AuthSessionMigrations"; +export * from "./AuthSessionsContext"; +export * from "./AuthSessionsService"; diff --git a/packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsole/ManagementConsole.tsx b/packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsole/ManagementConsole.tsx deleted file mode 100644 index dea6d49fa17..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsole/ManagementConsole.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 * as React from "react"; -import { useCallback } from "react"; -import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; -import { ApolloProvider } from "react-apollo"; -import { ApolloClient } from "apollo-client"; -import ManagementConsoleNav from "../ManagementConsoleNav/ManagementConsoleNav"; -import managementConsoleLogo from "../../../static/managementConsoleLogo.svg"; -import { - KogitoAppContextProvider, - UserContext, -} from "@kie-tools/runtime-tools-components/dist/contexts/KogitoAppContext"; -import { PageLayout } from "@kie-tools/runtime-tools-components/dist/components/PageLayout"; -import { ProcessListContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/ProcessList"; -import { ProcessDetailsContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/ProcessDetails"; -import { JobsManagementContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/JobsManagement"; -import { TaskInboxContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/TaskInbox"; -import { TaskFormContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/TaskForms"; - -interface IOwnProps { - apolloClient: ApolloClient; - userContext: UserContext; - children: React.ReactElement; -} - -const ManagementConsole: React.FC = ({ apolloClient, userContext, children }) => { - const renderPage = useCallback( - (routeProps) => { - return ( - routeProps.history.push("/")} - withHeader={true} - PageNav={} - ouiaId="management-console" - > - {children} - - ); - }, - [children] - ); - - return ( - - - - - - - - - - - - - - - - - - - - ); -}; - -export default ManagementConsole; diff --git a/packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsoleNav/ManagementConsoleNav.tsx b/packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsoleNav/ManagementConsoleNav.tsx deleted file mode 100644 index 279d056c599..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsoleNav/ManagementConsoleNav.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 * as React from "react"; -import { Nav, NavItem, NavList } from "@patternfly/react-core/dist/js/components/Nav"; -import { Link } from "react-router-dom"; -import { ouiaAttribute } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; - -interface IOwnProps { - pathname: string; -} - -const ManagementConsoleNav: React.FC = ({ pathname }) => { - return ( - - ); -}; - -export default ManagementConsoleNav; diff --git a/packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsoleRoutes/ManagementConsoleRoutes.tsx b/packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsoleRoutes/ManagementConsoleRoutes.tsx deleted file mode 100644 index 18be1aabe22..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/console/ManagementConsoleRoutes/ManagementConsoleRoutes.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 * as React from "react"; -import { Redirect, Route, Switch } from "react-router-dom"; -import { JobsPage, ProcessListPage, ProcessDetailsPage, TasksPage, TaskDetailsPage } from "../../pages"; -import { PageNotFound } from "@kie-tools/runtime-tools-shared-webapp-components/dist/PageNotFound"; -import { NoData } from "@kie-tools/runtime-tools-shared-webapp-components/dist/NoData"; - -const ManagementConsoleRoutes: React.FC = () => { - return ( - - } /> - - - - - } /> - } - /> - } - /> - - ); -}; - -export default ManagementConsoleRoutes; diff --git a/packages/runtime-tools-management-console-webapp/src/components/containers/JobsContainer/JobsContainer.tsx b/packages/runtime-tools-management-console-webapp/src/components/containers/JobsContainer/JobsContainer.tsx deleted file mode 100644 index 4bc5e8611ad..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/containers/JobsContainer/JobsContainer.tsx +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 * as React from "react"; -import { OUIAProps } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { EmbeddedJobsManagement } from "@kie-tools/runtime-tools-process-enveloped-components/dist/jobsManagement"; -import { - JobsManagementGatewayApi, - useJobsManagementGatewayApi, -} from "@kie-tools/runtime-tools-process-webapp-components/dist/JobsManagement"; - -const JobsContainer: React.FC = () => { - const gatewayApi: JobsManagementGatewayApi = useJobsManagementGatewayApi(); - return ; -}; - -export default JobsContainer; diff --git a/packages/runtime-tools-management-console-webapp/src/components/containers/ProcessDetailsContainer/ProcessDetailsContainer.tsx b/packages/runtime-tools-management-console-webapp/src/components/containers/ProcessDetailsContainer/ProcessDetailsContainer.tsx deleted file mode 100644 index 0701ee94bf3..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/containers/ProcessDetailsContainer/ProcessDetailsContainer.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 * as React from "react"; -import { useEffect } from "react"; -import { useHistory } from "react-router-dom"; -import { OUIAProps, componentOuiaProps } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { ProcessInstance } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; -import { - ProcessDetailsGatewayApi, - useProcessDetailsGatewayApi, -} from "@kie-tools/runtime-tools-process-webapp-components/dist/ProcessDetails"; -import { EmbeddedProcessDetails } from "@kie-tools/runtime-tools-process-enveloped-components/dist/processDetails"; - -interface ProcessDetailsContainerProps { - processInstance: ProcessInstance; -} - -const ProcessDetailsContainer: React.FC = ({ - processInstance, - ouiaId, - ouiaSafe, -}) => { - const history = useHistory(); - const gatewayApi: ProcessDetailsGatewayApi = useProcessDetailsGatewayApi(); - useEffect(() => { - const unSubscribeHandler = gatewayApi.onOpenProcessInstanceDetailsListener({ - onOpen(id: string) { - history.push(`/`); - history.push(`/Process/${id}`); - }, - }); - - return () => { - unSubscribeHandler.unSubscribe(); - }; - }, [gatewayApi, history, processInstance]); - - return ( - - ); -}; - -export default ProcessDetailsContainer; diff --git a/packages/runtime-tools-management-console-webapp/src/components/containers/ProcessListContainer/ProcessListContainer.tsx b/packages/runtime-tools-management-console-webapp/src/components/containers/ProcessListContainer/ProcessListContainer.tsx deleted file mode 100644 index c99e632268e..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/containers/ProcessListContainer/ProcessListContainer.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 * as React from "react"; -import { useEffect } from "react"; -import { useHistory } from "react-router-dom"; -import { - ProcessListGatewayApi, - useProcessListGatewayApi, -} from "@kie-tools/runtime-tools-process-webapp-components/dist/ProcessList"; -import { ProcessInstance, ProcessListState } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; -import { OUIAProps } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { EmbeddedProcessList } from "@kie-tools/runtime-tools-process-enveloped-components/dist/processList"; - -interface ProcessListContainerProps { - initialState: ProcessListState; -} - -const ProcessListContainer: React.FC = ({ initialState, ouiaId, ouiaSafe }) => { - const history = useHistory(); - const gatewayApi: ProcessListGatewayApi = useProcessListGatewayApi(); - - useEffect(() => { - const unsubscriber = gatewayApi.onOpenProcessListen({ - onOpen(process: ProcessInstance) { - history.push({ - pathname: `/Process/${process.id}`, - state: gatewayApi.processListState, - }); - }, - }); - return () => { - unsubscriber.unSubscribe(); - }; - }, [gatewayApi, history]); - - return ( - - ); -}; - -export default ProcessListContainer; diff --git a/packages/runtime-tools-management-console-webapp/src/components/containers/TasksContainer/TasksContainer.tsx b/packages/runtime-tools-management-console-webapp/src/components/containers/TasksContainer/TasksContainer.tsx deleted file mode 100644 index 07daf8e161c..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/containers/TasksContainer/TasksContainer.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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, { useEffect } from "react"; -import { useHistory } from "react-router-dom"; -import { OUIAProps, componentOuiaProps } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { - TaskInboxGatewayApi, - useTaskInboxGatewayApi, -} from "@kie-tools/runtime-tools-process-webapp-components/dist/TaskInbox"; -import { EmbeddedTaskInbox } from "@kie-tools/runtime-tools-process-enveloped-components/dist/taskInbox"; -import { getActiveTaskStates, getAllTaskStates } from "@kie-tools/runtime-tools-process-webapp-components/dist/utils"; -import { UserTaskInstance } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; - -const TaskInboxContainer: React.FC = ({ ouiaId, ouiaSafe }) => { - const history = useHistory(); - const gatewayApi: TaskInboxGatewayApi = useTaskInboxGatewayApi(); - - useEffect(() => { - const unsubscriber = gatewayApi.onOpenTaskListen({ - onOpen(task: UserTaskInstance) { - history.push(`/TaskDetails/${task.id}`); - }, - }); - - return () => { - unsubscriber.unSubscribe(); - }; - }, []); - - return ( - - ); -}; - -export default TaskInboxContainer; diff --git a/packages/runtime-tools-management-console-webapp/src/components/pages/JobsPage/JobsPage.tsx b/packages/runtime-tools-management-console-webapp/src/components/pages/JobsPage/JobsPage.tsx deleted file mode 100644 index dac2da378a8..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/pages/JobsPage/JobsPage.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 * as React from "react"; -import { useEffect } from "react"; -import { Card } from "@patternfly/react-core/dist/js/components/Card"; -import { PageSection } from "@patternfly/react-core/dist/js/components/Page"; -import JobsContainer from "../../containers/JobsContainer/JobsContainer"; -import "../../styles.css"; -import { OUIAProps, ouiaPageTypeAndObjectId } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { PageSectionHeader } from "@kie-tools/runtime-tools-components/dist/components/PageSectionHeader"; - -const JobsPage: React.FC = () => { - useEffect(() => { - return ouiaPageTypeAndObjectId("jobs"); - }); - - return ( - - - - - - - - - ); -}; - -export default JobsPage; diff --git a/packages/runtime-tools-management-console-webapp/src/components/pages/ProcessDetailsPage/ProcessDetailsPage.tsx b/packages/runtime-tools-management-console-webapp/src/components/pages/ProcessDetailsPage/ProcessDetailsPage.tsx deleted file mode 100644 index 1c4536764a7..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/pages/ProcessDetailsPage/ProcessDetailsPage.tsx +++ /dev/null @@ -1,159 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 * as React from "react"; -import { useState, useEffect, useCallback, useMemo } from "react"; -import { Card } from "@patternfly/react-core/dist/js/components/Card"; -import { PageSection } from "@patternfly/react-core/dist/js/components/Page"; -import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye"; -import { RouteComponentProps } from "react-router-dom"; -import ProcessDetailsContainer from "../../containers/ProcessDetailsContainer/ProcessDetailsContainer"; -import { StaticContext, useHistory } from "react-router"; -import * as H from "history"; -import "../../styles.css"; -import { OUIAProps, ouiaPageTypeAndObjectId } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { ProcessInstance } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; -import { ServerErrors } from "@kie-tools/runtime-tools-components/dist/components/ServerErrors"; -import { KogitoSpinner } from "@kie-tools/runtime-tools-components/dist/components/KogitoSpinner"; -import { PageSectionHeader } from "@kie-tools/runtime-tools-components/dist/components/PageSectionHeader"; -import { - useProcessDetailsGatewayApi, - ProcessDetailsGatewayApi, -} from "@kie-tools/runtime-tools-process-webapp-components/dist/ProcessDetails"; - -interface MatchProps { - instanceID: string; -} - -const ProcessDetailsPage: React.FC & OUIAProps> = ({ - ...props -}) => { - const processId = props.match.params.instanceID; - useEffect(() => { - return ouiaPageTypeAndObjectId("process-instances", processId); - }); - - const gatewayApi: ProcessDetailsGatewayApi = useProcessDetailsGatewayApi(); - - const history = useHistory(); - const [processInstance, setProcessInstance] = useState(); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(); - - useEffect(() => { - window.onpopstate = () => { - props.history.push({ state: Object.assign({}, props.location.state) }); - }; - }); - - const fetchDetails = useCallback(async () => { - try { - setIsLoading(true); - const response = await gatewayApi.processDetailsQuery(processId); - setProcessInstance(response); - } catch (error) { - setError(error); - } finally { - setIsLoading(false); - } - }, [gatewayApi, processId]); - - useEffect(() => { - /* istanbul ignore else */ - if (processId) { - fetchDetails(); - } - }, [processId, fetchDetails]); - - useEffect(() => { - // Redirecting to NoData page if the ProcessInstance cannot be found. - if (!isLoading && !error && !processInstance) { - let currentPage = JSON.parse(window.localStorage.getItem("state")); - let prevPath; - /* istanbul ignore else */ - if (currentPage) { - currentPage = Object.assign({}, currentPage, props.location.state); - const tempPath = currentPage.prev.split("/"); - prevPath = tempPath.filter((item) => item); - } - history.push({ - pathname: "/NoData", - state: { - prev: currentPage ? currentPage.prev : "/ProcessInstances", - title: "ProcessĀ notĀ found", - description: `Process instance with the id ${processId} not found`, - buttonText: currentPage - ? `Go to ${prevPath[0] - .replace(/([A-Z])/g, " $1") - .trim() - .toLowerCase()}` - : "Go to process instances", - rememberedData: Object.assign({}, props.location.state), - }, - }); - } - }, [error, history, isLoading, processId, processInstance, props.location.state]); - - const body = useMemo(() => { - // Loading State - if (isLoading) { - return ( - - - - ); - } - - // Error State - if (error) { - return ( - <> - - - - - - - ); - } - - // Process Instance Details - if (processInstance) { - return ; - } - }, [error, isLoading, processInstance]); - - return ( - - - {body} - - ); -}; - -export default ProcessDetailsPage; diff --git a/packages/runtime-tools-management-console-webapp/src/components/pages/ProcessListPage/ProcessListPage.tsx b/packages/runtime-tools-management-console-webapp/src/components/pages/ProcessListPage/ProcessListPage.tsx deleted file mode 100644 index 191cfdeb533..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/pages/ProcessListPage/ProcessListPage.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 * as React from "react"; -import { useEffect } from "react"; -import { Card } from "@patternfly/react-core/dist/js/components/Card"; -import { PageSection } from "@patternfly/react-core/dist/js/components/Page"; -import { RouteComponentProps } from "react-router-dom"; -import ProcessListContainer from "../../containers/ProcessListContainer/ProcessListContainer"; -import { StaticContext } from "react-router"; -import * as H from "history"; -import "../../styles.css"; -import { - OUIAProps, - componentOuiaProps, - ouiaPageTypeAndObjectId, -} from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { ProcessListState } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; -import { PageSectionHeader } from "@kie-tools/runtime-tools-components/dist/components/PageSectionHeader"; - -interface MatchProps { - instanceID: string; -} - -const ProcessListPage: React.FC & OUIAProps> = ( - props -) => { - useEffect(() => { - return ouiaPageTypeAndObjectId("process-instances"); - }); - const initialState: ProcessListState = props.location && (props.location.state as ProcessListState); - - return ( - <> - - - - - - - - ); -}; - -export default ProcessListPage; diff --git a/packages/runtime-tools-management-console-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx b/packages/runtime-tools-management-console-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx deleted file mode 100644 index 9ec3ca2f88d..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx +++ /dev/null @@ -1,280 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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, { useEffect, useState } from "react"; -import { Link, RouteComponentProps } from "react-router-dom"; -import { Breadcrumb, BreadcrumbItem } from "@patternfly/react-core/dist/js/components/Breadcrumb"; -import { - Drawer, - DrawerActions, - DrawerCloseButton, - DrawerContent, - DrawerContentBody, - DrawerHead, - DrawerPanelBody, - DrawerPanelContent, -} from "@patternfly/react-core/dist/js/components/Drawer"; -import { Card, CardBody } from "@patternfly/react-core/dist/js/components/Card"; -import { Button } from "@patternfly/react-core/dist/js/components/Button"; -import { Title } from "@patternfly/react-core/dist/js/components/Title"; -import { PageSection } from "@patternfly/react-core/dist/js/components/Page"; -import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye"; -import { Grid, GridItem } from "@patternfly/react-core/dist/js/layouts/Grid"; -import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex"; -import TaskFormContainer from "../../containers/TaskFormContainer/TaskFormContainer"; -import FormNotification, { Notification } from "./components/FormNotification/FormNotification"; -import { - TaskInboxGatewayApi, - useTaskInboxGatewayApi, -} from "@kie-tools/runtime-tools-process-webapp-components/dist/TaskInbox"; -import "../../styles.css"; -import { - OUIAProps, - componentOuiaProps, - ouiaPageTypeAndObjectId, -} from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { KogitoSpinner } from "@kie-tools/runtime-tools-components/dist/components/KogitoSpinner"; -import { ServerErrors } from "@kie-tools/runtime-tools-components/dist/components/ServerErrors"; -import { - KogitoEmptyState, - KogitoEmptyStateType, -} from "@kie-tools/runtime-tools-components/dist/components/KogitoEmptyState"; -import { PageTitle } from "@kie-tools/runtime-tools-components/dist/components/PageTitle"; -import { EmbeddedTaskDetails } from "@kie-tools/runtime-tools-process-enveloped-components/dist/taskDetails"; -import { UserTaskInstance } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; -import { TaskState } from "@kie-tools/runtime-tools-process-enveloped-components/dist/taskDetails"; - -interface Props { - taskId?: string; -} - -const TaskDetailsPage: React.FC & OUIAProps> = ({ ouiaId, ouiaSafe, ...props }) => { - const taskInboxGatewayApi: TaskInboxGatewayApi = useTaskInboxGatewayApi(); - - const [taskId] = useState(props.match.params.taskId); - const [isLoading, setIsLoading] = useState(true); - const [userTask, setUserTask] = useState(); - const [notification, setNotification] = useState(); - const [error, setError] = useState(); - const [isDetailsExpanded, setIsDetailsExpanded] = useState(false); - - useEffect(() => { - return ouiaPageTypeAndObjectId("task-details-page", taskId); - }); - - const loatTask = async () => { - try { - const task = await taskInboxGatewayApi.getTaskById(taskId); - setUserTask(task); - } catch (err) { - setError(err); - } finally { - setIsLoading(false); - } - }; - - useEffect(() => { - loatTask(); - }, []); - - const showNotification = ( - notificationType: "error" | "success", - submitMessage: string, - notificationDetails?: string - ) => { - setNotification({ - type: notificationType, - message: submitMessage, - details: notificationDetails, - customAction: { - label: "Go to Tasks", - onClick: () => { - setNotification(null); - goToInbox(); - }, - }, - close: () => { - setNotification(null); - }, - }); - }; - - const goToInbox = () => { - taskInboxGatewayApi.clearOpenTask(); - props.history.push("/Tasks"); - }; - - const onSubmitSuccess = (phase: string) => { - const message = `Task '${userTask.referenceName}' successfully transitioned to phase '${phase}'.`; - - showNotification("success", message); - }; - - const onSubmitError = (phase, details?: string) => { - const message = `Task '${userTask.referenceName}' couldn't transition to phase '${phase}'.`; - - showNotification("error", message, details); - }; - - if (isLoading) { - return ( - - - - - - - - - - - - ); - } - - if (error) { - return ( - - - - - - - - - - - - ); - } - - if (!userTask) { - return ( - - - - - - - - - - ); - } - - const onViewDetailsClick = () => { - setIsDetailsExpanded(!isDetailsExpanded); - }; - - const onDetailsCloseClick = () => { - setIsDetailsExpanded(false); - }; - - const panelContent = ( - - - - - Details - - - - - - - - - - - ); - - return ( - - - - - { - taskInboxGatewayApi.clearOpenTask(); - }} - > - Tasks - - - {userTask.referenceName} - - - - } /> - - - - - - {notification && ( -
- -
- )} -
- - - - - - - - - - - - - - - - - -
- ); -}; - -export default TaskDetailsPage; diff --git a/packages/runtime-tools-management-console-webapp/src/components/pages/TasksPage/TasksPage.tsx b/packages/runtime-tools-management-console-webapp/src/components/pages/TasksPage/TasksPage.tsx deleted file mode 100644 index 8c5a04f836b..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/pages/TasksPage/TasksPage.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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, { useEffect } from "react"; -import TasksContainer from "../../containers/TasksContainer/TasksContainer"; -import "../../styles.css"; -import { - OUIAProps, - componentOuiaProps, - ouiaPageTypeAndObjectId, -} from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { PageSection } from "@patternfly/react-core/dist/js/components/Page"; -import { PageTitle } from "@kie-tools/runtime-tools-components/dist/components/PageTitle"; -import { Grid, GridItem } from "@patternfly/react-core/dist/js/layouts/Grid"; -import { Card } from "@patternfly/react-core/dist/js/components/Card"; - -const TasksPage: React.FC = (ouiaId, ouiaSafe) => { - useEffect(() => { - return ouiaPageTypeAndObjectId("tasks-page"); - }); - - return ( - - - - - - - - - - - - - - - ); -}; - -export default TasksPage; diff --git a/packages/runtime-tools-management-console-webapp/src/components/pages/index.ts b/packages/runtime-tools-management-console-webapp/src/components/pages/index.ts deleted file mode 100644 index 3c6fc5986bd..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/components/pages/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 { default as JobsPage } from "./JobsPage/JobsPage"; -export { default as ProcessListPage } from "./ProcessListPage/ProcessListPage"; -export { default as ProcessDetailsPage } from "./ProcessDetailsPage/ProcessDetailsPage"; -export { default as TaskDetailsPage } from "./TaskDetailsPage/TaskDetailsPage"; -export { default as TasksPage } from "./TasksPage/TasksPage"; diff --git a/packages/runtime-tools-management-console-webapp/src/env/EnvJson.ts b/packages/runtime-tools-management-console-webapp/src/env/EnvJson.ts index 0504b322029..661d6392e0d 100644 --- a/packages/runtime-tools-management-console-webapp/src/env/EnvJson.ts +++ b/packages/runtime-tools-management-console-webapp/src/env/EnvJson.ts @@ -17,11 +17,7 @@ * under the License. */ -import { KogitoConsolesKeycloakEnv } from "@kie-tools/runtime-tools-components/dist/utils/KeycloakClient"; - -export interface EnvJson extends KogitoConsolesKeycloakEnv { - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_KOGITO_ENV_MODE: "DEV" | "PROD"; - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_KOGITO_APP_NAME: string; - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_KOGITO_APP_VERSION: string; - RUNTIME_TOOLS_MANAGEMENT_CONSOLE_DATA_INDEX_ENDPOINT: string; +export interface EnvJson { + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME: string; + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_OIDC_CLIENT_CLIENT_ID: string; } diff --git a/packages/runtime-tools-management-console-webapp/src/env/hooks/EnvContext.tsx b/packages/runtime-tools-management-console-webapp/src/env/hooks/EnvContext.tsx new file mode 100644 index 00000000000..bcb557f4a86 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/env/hooks/EnvContext.tsx @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 * as React from "react"; +import { useContext } from "react"; +import { EnvJson } from "../EnvJson"; + +export interface EnvContextType { + env: EnvJson; +} + +export const EnvContext = React.createContext({} as any); + +export function useEnv() { + return useContext(EnvContext); +} diff --git a/packages/runtime-tools-management-console-webapp/src/env/hooks/EnvContextProvider.tsx b/packages/runtime-tools-management-console-webapp/src/env/hooks/EnvContextProvider.tsx new file mode 100644 index 00000000000..8fdaa6bde75 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/env/hooks/EnvContextProvider.tsx @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 * as React from "react"; +import { useCallback, useMemo, useState } from "react"; +import { useCancelableEffect } from "@kie-tools-core/react-hooks/dist/useCancelableEffect"; +import { ENV_FILE_PATH } from "../EnvConstants"; +import { EnvJson } from "../EnvJson"; +import { EnvContext } from "./EnvContext"; + +interface Props { + children: React.ReactNode; +} + +export function EnvContextProvider(props: Props) { + const [env, setEnv] = useState(); + const [fetchDone, setFetchDone] = useState(false); + + useCancelableEffect( + useCallback(({ canceled }) => { + fetch(ENV_FILE_PATH) + .then(async (response) => { + if (canceled.get()) { + return; + } + + if (!response.ok) { + throw new Error(`Failed to fetch ${ENV_FILE_PATH}: ${response.statusText}`); + } + + const envJson = await response.json(); + setEnv((prev) => ({ ...(prev ?? {}), ...envJson })); + }) + .catch((e) => { + console.error(e); + }) + .finally(() => { + setFetchDone(true); + }); + }, []) + ); + + const value = useMemo( + () => ({ + env: env!, + }), + [env] + ); + + return {fetchDone && props.children}; +} diff --git a/packages/runtime-tools-management-console-webapp/src/favicon.ico b/packages/runtime-tools-management-console-webapp/src/favicon.ico deleted file mode 100755 index c050c8c7fc8ff175fd2fd215e5f4876057f3f616..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1371 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstUx|vage(c z!@6@aFM%9|WRD45bDP46hOx7_4S6Fo+k-*%fF5)Ylf^ z6XMDpRm2fd093{loDF0M#+C9$7qf=t0ohC;ISj$stl{}Ap?QAoGk~OWRs&E_A)}5d zBv&}09LN?+st`-80P127FW`>MXACQrj>%*WFOrW*XOAdg3(sc^-*O)TRIb|Nr~{zi!1ApT@q%dGkBw&uv+vsLmj&syM2?>TsQb@08Ucy))hFI%@V^X*znR zcTYBcbrXMxi6rpBe0=0Y3a_g9cSa0 z?Cd>#f7<2elP*4+c;Ts8!}Rpk2c}H%+T`v&QcAR35-+! zo_%TYO8%bg&6|v|?^U08|EOeMA#&09o%XRm;-z;O)%#zvxExrWs8&;VkfoEC$Bv5fEmKo;a5qsDRni#W6(Uvgo<1VNQu6ED!4CcLl$E_l{5S%{wuc zOkp3Xdw1T(oc*Pj#;aJuHu>nYf}JvE-6t0aA9~!b%(PHLN|cjzqQQK32c6EN!Y4zt zW_BD`Nm5Xly43h)jNSaxX_t&Nn`$zbZiv#E+Lhhrl^BP zKsFy=f1khK`E#aO3k0_8>OQ^t_3YcbtLKU_I>fKD3CZ62DtYM|_B#d=uY1#0-_0|X zE?vxcFy&pz{CV+l_wVhN-OPC~>Frm0yZ!s>>wep=W<8iz&eOK|V~UB4#Tzr0S(l&A zJNNAK%`0z4m8X`Og>i;uOyl;5*r@GBzU>K>ExJHzu zB$lLFB^RXvDF!10LrYx)ATkayG_o=@vobW-HZZUCO>_-Rbq$Ra0u9X+GD=Dc ztn~HE%ggmLL8^fms9G<-DE&^`TcCjq5+D;pGD>rktgKw}lS^|`^Gd9&0)R@384Q>I z->r|P25hI5RYq!NdPWI@p`{T&Ls2VGjX07yP&MJ1DJ2;oC70JIasZV`A}R6B%uOw+ zEJ$SlyGp+xFWr7qm>-%sz9B$W42Gs==B9>5mgeS)QZ{FRO8Ak?3C^raWiW7ZnzG35 z4Nxi!Nh&nRlOZiLCl%;@{oK5gocwhCw8XN^j8D>0o@nh^zT2=1_n=8KbLh*2~7Y+cLA~h diff --git a/packages/runtime-tools-management-console-webapp/src/resources/form-displayer.ts b/packages/runtime-tools-management-console-webapp/src/forms/form-displayer-envelope.ts similarity index 89% rename from packages/runtime-tools-management-console-webapp/src/resources/form-displayer.ts rename to packages/runtime-tools-management-console-webapp/src/forms/form-displayer-envelope.ts index 08764142230..0bc6e9b6b81 100644 --- a/packages/runtime-tools-management-console-webapp/src/resources/form-displayer.ts +++ b/packages/runtime-tools-management-console-webapp/src/forms/form-displayer-envelope.ts @@ -16,11 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { init } from "@kie-tools/runtime-tools-shared-enveloped-components/dist/formDisplayer"; +import * as FormDisplayerEnvelope from "@kie-tools/runtime-tools-shared-enveloped-components/dist/formDisplayer"; import type { EnvelopeBusMessage } from "@kie-tools-core/envelope-bus/dist/api"; import { ContainerType } from "@kie-tools-core/envelope/dist/api"; -init({ +FormDisplayerEnvelope.init({ container: document.getElementById("displayer-app")!, config: { containerType: ContainerType.IFRAME }, bus: { diff --git a/packages/runtime-tools-management-console-webapp/src/index.tsx b/packages/runtime-tools-management-console-webapp/src/index.tsx index 8055969e432..805bebf0d3b 100644 --- a/packages/runtime-tools-management-console-webapp/src/index.tsx +++ b/packages/runtime-tools-management-console-webapp/src/index.tsx @@ -16,91 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import * as React from "react"; -import * as ReactDOM from "react-dom"; -import ApolloClient from "apollo-client"; import "@patternfly/patternfly/patternfly.css"; import "@patternfly/patternfly/patternfly-addons.css"; import "@patternfly/react-core/dist/styles/base.css"; -import { HttpLink } from "apollo-link-http"; -import { setContext } from "apollo-link-context"; -import { onError } from "apollo-link-error"; -import { InMemoryCache, NormalizedCacheObject } from "apollo-cache-inmemory"; -import ManagementConsole from "./components/console/ManagementConsole/ManagementConsole"; -import ManagementConsoleRoutes from "./components/console/ManagementConsoleRoutes/ManagementConsoleRoutes"; -import { KeycloakUnavailablePage } from "@kie-tools/runtime-tools-components/src/common/components/KeycloakUnavailablePage"; -import { ServerUnavailablePage } from "@kie-tools/runtime-tools-shared-webapp-components/dist/ServerUnavailablePage"; -import { UserContext } from "@kie-tools/runtime-tools-components/dist/contexts/KogitoAppContext"; -import { - isAuthEnabled, - updateKeycloakToken, - getToken, - appRenderWithAxiosInterceptorConfig, -} from "@kie-tools/runtime-tools-components/dist/utils/KeycloakClient"; -import { initEnv } from "./env/Env"; -import { ENV_PREFIX } from "./env/EnvConstants"; - -const onLoadFailure = (): void => { - ReactDOM.render(, document.getElementById("root")); -}; - -const appRender = async (ctx: UserContext) => { - const httpLink = new HttpLink({ - uri: window["DATA_INDEX_ENDPOINT"], - }); - const fallbackUI = onError(({ networkError }: any) => { - if (networkError && networkError.stack === "TypeError: Failed to fetch") { - // eslint-disable-next-line react/no-render-return-value - return ReactDOM.render( - - window.location.reload()} /> - , - document.getElementById("root") - ); - } - }); - - const setGQLContext = setContext((_, { headers }) => { - if (!isAuthEnabled()) { - return { - headers, - }; - } - return new Promise((resolve, reject) => { - updateKeycloakToken() - .then(() => { - const token = getToken(); - resolve({ - headers: { - ...headers, - authorization: token ? `Bearer ${token}` : "", - }, - }); - }) - .catch(() => { - reject(); - }); - }); - }); - - const cache = new InMemoryCache(); - const client: ApolloClient = new ApolloClient({ - cache, - link: setGQLContext.concat(fallbackUI.concat(httpLink)), - }); - ReactDOM.render( - - - , - document.getElementById("root") - ); -}; +import * as React from "react"; +import * as ReactDOM from "react-dom"; +import { App } from "./managementConsole/ManagementConsole"; +import "./styles.css"; -initEnv().then((env) => { - if (env) { - Object.keys(env).forEach((key) => { - window[key.replace(`${ENV_PREFIX}_`, "")] = env[key]; - }); - } - appRenderWithAxiosInterceptorConfig((ctx: UserContext) => appRender(ctx), onLoadFailure); -}); +ReactDOM.render(, document.getElementById("root")); diff --git a/packages/runtime-tools-management-console-webapp/src/jobs/Jobs.tsx b/packages/runtime-tools-management-console-webapp/src/jobs/Jobs.tsx new file mode 100644 index 00000000000..1e3a0c8d16b --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/jobs/Jobs.tsx @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useMemo, useEffect } from "react"; +import { EmbeddedJobsManagement } from "@kie-tools/runtime-tools-process-enveloped-components/dist/jobsManagement"; +import { + JobsManagementGatewayApi, + useJobsManagementGatewayApi, +} from "@kie-tools/runtime-tools-process-webapp-components/dist/JobsManagement"; +import { useHistory } from "react-router"; +import { useQueryParam, useQueryParams } from "../navigation/queryParams/QueryParamsContext"; +import { RuntimePathSearchParamsRoutes, useRuntimeDispatch } from "../runtime/RuntimeContext"; +import { QueryParams } from "../navigation/Routes"; +import { JobsManagementState, JobStatus } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; +import { OrderBy } from "@kie-tools/runtime-tools-shared-gateway-api/dist/types"; + +const defaultStatus = [JobStatus.Scheduled]; + +const defaultOrderBy = { + lastUpdate: OrderBy.DESC, +}; + +export const Jobs: React.FC = () => { + const gatewayApi: JobsManagementGatewayApi = useJobsManagementGatewayApi(); + const history = useHistory(); + const filters = useQueryParam(QueryParams.FILTERS); + const orderBy = useQueryParam(QueryParams.ORDER_BY); + const queryParams = useQueryParams(); + const { setRuntimePathSearchParams } = useRuntimeDispatch(); + + const initialState: JobsManagementState = useMemo(() => { + return { + filters: filters ? (JSON.parse(filters) as JobsManagementState["filters"]) : defaultStatus, + orderBy: orderBy ? (JSON.parse(orderBy) as JobsManagementState["orderBy"]) : defaultOrderBy, + }; + }, [filters, orderBy]); + + useEffect(() => { + const newSearchParams = { + [QueryParams.FILTERS]: JSON.stringify(initialState.filters), + [QueryParams.ORDER_BY]: JSON.stringify(initialState.orderBy), + }; + setRuntimePathSearchParams((currentRuntimePathSearchParams) => { + return currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.JOBS, newSearchParams); + }); + }, [initialState, setRuntimePathSearchParams]); + + useEffect(() => { + const unsubscriber = gatewayApi.onUpdateJobsManagementState({ + onUpdate(jobsManagementState: JobsManagementState) { + const newSearchParams = { + [QueryParams.FILTERS]: JSON.stringify(jobsManagementState.filters), + [QueryParams.ORDER_BY]: JSON.stringify(jobsManagementState.orderBy), + }; + setRuntimePathSearchParams((currentRuntimePathSearchParams) => { + return currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.JOBS, newSearchParams); + }); + const newQueryParams = queryParams + .with(QueryParams.FILTERS, newSearchParams[QueryParams.FILTERS]) + .with(QueryParams.ORDER_BY, newSearchParams[QueryParams.ORDER_BY]); + history.replace({ pathname: history.location.pathname, search: newQueryParams.toString() }); + }, + }); + + return () => { + unsubscriber.unSubscribe(); + }; + }, [gatewayApi, history, queryParams, setRuntimePathSearchParams]); + + return gatewayApi && initialState ? ( + + ) : ( + <> + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/jobs/JobsPage.tsx b/packages/runtime-tools-management-console-webapp/src/jobs/JobsPage.tsx new file mode 100644 index 00000000000..5f44aca24e8 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/jobs/JobsPage.tsx @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useEffect } from "react"; +import { Card } from "@patternfly/react-core/dist/js/components/Card"; +import { Jobs } from "./Jobs"; +import { AuthSession, useAuthSessionsDispatch } from "../authSessions"; +import { useHistory } from "react-router"; +import { useRuntimeInfo, useRuntimeSpecificRoutes } from "../runtime/RuntimeContext"; +import { useEnv } from "../env/hooks/EnvContext"; +import { useRuntimePageLayoutDispatch } from "../runtime/RuntimePageLayoutContext"; +import { useRoutes } from "../navigation/Hooks"; + +export const JobsPage: React.FC = () => { + const history = useHistory(); + const runtimeRoutes = useRuntimeSpecificRoutes(); + const routes = useRoutes(); + const { runtimeDisplayInfo } = useRuntimeInfo(); + const { setOnSelectAuthSession } = useAuthSessionsDispatch(); + const { setCurrentPageTitle, setBreadcrumbText, setBreadcrumbPath } = useRuntimePageLayoutDispatch(); + const { env } = useEnv(); + + useEffect(() => { + setOnSelectAuthSession(() => (authSession: AuthSession) => { + history.push(runtimeRoutes.jobs(authSession)); + }); + return () => { + setOnSelectAuthSession(undefined); + }; + }, [history, runtimeRoutes, setOnSelectAuthSession]); + + useEffect(() => { + setCurrentPageTitle("Jobs"); + setBreadcrumbText(["Home", runtimeDisplayInfo?.fullDisplayName ?? "Runtime", "Jobs"]); + setBreadcrumbPath([routes.home.path({}), runtimeRoutes.processes(), runtimeRoutes.jobs()]); + + return () => { + setCurrentPageTitle(""); + setBreadcrumbText([]); + setBreadcrumbPath([]); + }; + }, [ + routes.home, + runtimeDisplayInfo?.fullDisplayName, + runtimeRoutes, + setBreadcrumbPath, + setBreadcrumbText, + setCurrentPageTitle, + ]); + + useEffect(() => { + document.title = `${env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME} :: Jobs`; + }, [env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME]); + + return ( + + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/dev/server/app.js b/packages/runtime-tools-management-console-webapp/src/jobs/index.ts similarity index 91% rename from packages/runtime-tools-management-console-webapp/dev/server/app.js rename to packages/runtime-tools-management-console-webapp/src/jobs/index.ts index e515d2b03d7..2b5aee2cc94 100644 --- a/packages/runtime-tools-management-console-webapp/dev/server/app.js +++ b/packages/runtime-tools-management-console-webapp/src/jobs/index.ts @@ -16,8 +16,5 @@ * specific language governing permissions and limitations * under the License. */ -const server = require("./server"); - -server.listen(); - -module.exports = server; +export * from "./Jobs"; +export * from "./JobsPage"; diff --git a/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsole.tsx b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsole.tsx new file mode 100644 index 00000000000..6d98f068091 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsole.tsx @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { BrowserRouter } from "react-router-dom"; +import { AuthSessionsContextProvider } from "../authSessions/AuthSessionsContext"; +import { ManagementConsoleRoutes } from "./ManagementConsoleRoutes"; +import { EnvContextProvider } from "../env/hooks/EnvContextProvider"; +import { NavigationContextProvider } from "../navigation/NavigationContextProvider"; + +export const App: React.FC = () => { + return ( + ENV VAR FOR BASE PATH */> + + + ); +}; + +export const ManagementConsole: React.FC = () => { + return ( + + + + + + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleHome.tsx b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleHome.tsx new file mode 100644 index 00000000000..8d36eaeb54a --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleHome.tsx @@ -0,0 +1,121 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback, useEffect, useLayoutEffect } from "react"; +import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button"; +import { useAuthSessions, useAuthSessionsDispatch } from "../authSessions/AuthSessionsContext"; +import { PageSection } from "@patternfly/react-core/dist/js/components/Page"; +import { + EmptyState, + EmptyStateBody, + EmptyStateIcon, + EmptyStateVariant, + EmptyStateSecondaryActions, +} from "@patternfly/react-core/dist/js/components/EmptyState"; +import { Title } from "@patternfly/react-core/dist/js/components/Title"; +import { CubesIcon } from "@patternfly/react-icons/dist/js/icons/cubes-icon"; +import { PlusIcon } from "@patternfly/react-icons/dist/js/icons/plus-icon"; +import { useEnv } from "../env/hooks/EnvContext"; +import { AuthSession, AuthSessionsList, isOpenIdConnectAuthSession } from "../authSessions"; +import { useHistory } from "react-router"; +import { useRoutes } from "../navigation/Hooks"; +import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex"; +import { Divider } from "@patternfly/react-core/dist/js/components/Divider"; +import { ManagementConsolePageLayout } from "./ManagementConsolePageLayout"; + +export const ManagementConsoleHome = () => { + const { env } = useEnv(); + const { setIsNewAuthSessionModalOpen, setOnSelectAuthSession, setCurrentAuthSession } = useAuthSessionsDispatch(); + const { authSessions } = useAuthSessions(); + const history = useHistory(); + const routes = useRoutes(); + + useEffect(() => { + setOnSelectAuthSession(undefined); + setCurrentAuthSession(undefined); + }, [setCurrentAuthSession, setOnSelectAuthSession]); + + const onSelectAuthSession = useCallback( + (authSession: AuthSession) => { + const user = isOpenIdConnectAuthSession(authSession) ? authSession.username : undefined; + const encodedRuntimeUrl = encodeURIComponent(authSession.runtimeUrl); + const path = routes.runtime.processes.path({ + runtimeUrl: encodedRuntimeUrl, + }); + history.push({ + pathname: path, + search: user ? `?user=${encodeURIComponent(user)}` : "", + }); + }, + [history, routes.runtime.processes] + ); + + useEffect(() => { + document.title = `${env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME} :: Welcome`; + }, [env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME]); + + return ( + + + {authSessions.size <= 0 ? ( + +
+
+ + + {`Welcome to ${env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME}`} + + + Start by connecting to a runtime to manage Process Instances, Tasks, and Jobs. + + + + +
+ ) : ( + + + + + + Select connected runtime + + + +
+ +
+
+ +
+
+
+ )} +
+
+ ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsolePageLayout.tsx b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsolePageLayout.tsx new file mode 100644 index 00000000000..c27e9efdd57 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsolePageLayout.tsx @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { + Page, + PageHeader, + PageHeaderTools, + PageSection, + PageSidebar, +} from "@patternfly/react-core/dist/js/components/Page"; +import React, { useState, useMemo, useCallback, useEffect } from "react"; +import { Brand } from "@patternfly/react-core/dist/js/components/Brand"; +import { useEnv } from "../env/hooks/EnvContext"; +import { useRoutes } from "../navigation/Hooks"; +import { useHistory } from "react-router"; +import { ManagementConsoleToolbar } from "./ManagementConsoleToolbar"; +import { AboutButton } from "../aboutModal/AboutButton"; +import { PageSectionHeader } from "@kie-tools/runtime-tools-components/dist/components/PageSectionHeader"; +import { BreadcrumbPathType } from "../runtime/RuntimePageLayoutContext"; + +type Props = { + children: React.ReactNode; + disabledHeader?: boolean; + currentPageTile?: string; + breadcrumbText?: string[]; + breadcrumbPath?: BreadcrumbPathType; + nav?: React.ReactNode; +}; + +export const ManagementConsolePageLayout: React.FC = ({ + children, + disabledHeader = true, + currentPageTile, + breadcrumbText, + breadcrumbPath, + nav, +}) => { + const { env } = useEnv(); + const routes = useRoutes(); + const history = useHistory(); + const [isNavOpen, setIsNavOpen] = useState(true); + + const onNavToggle = useCallback(() => { + setIsNavOpen((currentValue) => !currentValue); + }, []); + + const onClickBrand = useCallback(() => { + history.push(routes.home.path({})); + }, [history, routes.home]); + + const Header = useMemo(() => { + return ( + + + + + } + headerTools={ + !disabledHeader && ( + <> + + + + + ) + } + showNavToggle + isNavOpen={isNavOpen} + onNavToggle={onNavToggle} + /> + ); + }, [ + routes.static.images.appLogoReverse, + env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME, + onClickBrand, + disabledHeader, + isNavOpen, + onNavToggle, + ]); + + const Sidebar = useMemo( + () => nav && , + [isNavOpen, nav] + ); + + return ( + + + {!disabledHeader && ( + + )} + {children} + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleRoutes.tsx b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleRoutes.tsx new file mode 100644 index 00000000000..f8658ad2495 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleRoutes.tsx @@ -0,0 +1,123 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { FC, useCallback } from "react"; +import { Route } from "react-router-dom"; +import { ProcessListPage } from "../process"; +import { Switch, useHistory } from "react-router"; +import { ManagementConsoleHome } from "./ManagementConsoleHome"; +import { NewAuthSessionLoginSuccessPage, NewAuthSessionModal } from "../authSessions/components"; +import { useRoutes } from "../navigation/Hooks"; +import { RuntimeContextProvider } from "../runtime/RuntimeContext"; +import { AuthSession, isOpenIdConnectAuthSession } from "../authSessions"; +import { ProcessDetailsPage } from "../process/details/ProcessDetailsPage"; +import { JobsPage } from "../jobs"; +import { TaskDetailsPage, TasksPage } from "../tasks"; +import { RuntimePageLayoutContextProvider } from "../runtime/RuntimePageLayoutContext"; + +export const ManagementConsoleRoutes: FC = () => { + const routes = useRoutes(); + const history = useHistory(); + + const onAddAuthSession = useCallback( + (authSession: AuthSession) => { + history.push({ + pathname: routes.runtime.processes.path({ + runtimeUrl: encodeURIComponent(authSession.runtimeUrl), + }), + search: isOpenIdConnectAuthSession(authSession) ? `?user=${authSession.username}` : "", + }); + }, + [history, routes.runtime.processes] + ); + + return ( + <> + + + + + + + {({ match }) => { + return ( + + + + + + + + {({ match }) => { + return ; + }} + + + + + + + + + {({ match }) => { + return ; + }} + + + + + ); + }} + + + + + + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleToolbar.tsx b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleToolbar.tsx new file mode 100644 index 00000000000..9ded6d37f6f --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/managementConsole/ManagementConsoleToolbar.tsx @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { Toolbar, ToolbarGroup, ToolbarItem } from "@patternfly/react-core/dist/js/components/Toolbar"; +import accessibleStyles from "@patternfly/react-styles/css/utilities/Accessibility/accessibility"; +import { css } from "@patternfly/react-styles"; +import { SelectPosition } from "@patternfly/react-core/dist/js/components/Select"; +import { AuthSessionSelect } from "../authSessions/components/AuthSessionSelect"; + +export const ManagementConsoleToolbar: React.FunctionComponent = () => { + return ( + + + + + + + + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/navigation/Hooks.tsx b/packages/runtime-tools-management-console-webapp/src/navigation/Hooks.tsx new file mode 100644 index 00000000000..c33ca78802f --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/navigation/Hooks.tsx @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 * as React from "react"; +import { useContext, useEffect, useMemo } from "react"; +import { BlockerDelegate, NavigationBlockerContext, NavigationStatusContext } from "./NavigationContextProvider"; +import { routes } from "./Routes"; + +function useNavigationBlockerContext() { + return useContext(NavigationBlockerContext); +} + +export function useNavigationStatus() { + return useContext(NavigationStatusContext); +} + +export function useNavigationBlockersBypass() { + const { bypass } = useNavigationBlockerContext(); + return useMemo(() => ({ execute: bypass }), [bypass]); +} + +export function useNavigationStatusToggle() { + const { unblock } = useNavigationBlockerContext(); + return useMemo(() => ({ unblock }), [unblock]); +} + +export function useNavigationBlocker(key: string, blocker: BlockerDelegate) { + const { addBlocker, removeBlocker } = useNavigationBlockerContext(); + + useEffect(() => { + addBlocker(key, blocker); + return () => removeBlocker(key); + }, [addBlocker, removeBlocker, key, blocker]); +} + +export function useRoutes() { + return useMemo(() => routes, []); +} diff --git a/packages/runtime-tools-management-console-webapp/src/navigation/NavigationContextProvider.tsx b/packages/runtime-tools-management-console-webapp/src/navigation/NavigationContextProvider.tsx new file mode 100644 index 00000000000..ba9705ac30f --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/navigation/NavigationContextProvider.tsx @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 * as React from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { useHistory } from "react-router"; +import { Location, LocationDescriptorObject } from "history"; + +export type BlockerDelegate = (args: { location: Location }) => boolean; + +export interface NavigationBlockerContextType { + addBlocker: (name: string, blocker: BlockerDelegate) => void; + removeBlocker: (name: string) => void; + block: (location: Location) => void; + unblock: () => void; + bypass: (callback: () => void) => void; +} + +export interface NavigationStatus { + blockers: Map; + lastBlockedLocation: Location | undefined; + bypassBlockers: boolean; +} + +export interface NavigationStatusHelpers { + shouldBlockNavigationTo: (location: LocationDescriptorObject) => boolean; +} + +export const NavigationBlockerContext = React.createContext({} as any); +export const NavigationStatusContext = React.createContext({} as any); + +export function NavigationContextProvider(props: { children: React.ReactNode }) { + const history = useHistory(); + + const [status, setStatus] = useState({ + blockers: new Map(), + lastBlockedLocation: undefined, + bypassBlockers: false, + }); + + const blockerCtx: NavigationBlockerContextType = useMemo( + () => ({ + block: (location) => setStatus((prev) => ({ ...prev, lastBlockedLocation: location })), + unblock: () => setStatus((prev) => ({ ...prev, lastBlockedLocation: undefined })), + bypass: (callback: () => void) => { + setStatus((prev) => ({ ...prev, bypassBlockers: true })); + setTimeout(() => { + callback(); + setStatus((prev) => ({ ...prev, bypassBlockers: false, lastBlockedLocation: undefined })); + }, 0); + }, + addBlocker: (name, blocker) => + setStatus((prev) => { + if (prev.blockers.get(name) === blocker) { + return prev; + } + const newBlockers = new Map(prev.blockers); + newBlockers.set(name, blocker); + return { ...prev, blockers: newBlockers }; + }), + removeBlocker: (name) => + setStatus((prev) => { + if (!prev.blockers.has(name)) { + return prev; + } + + const newBlockers = new Map(prev.blockers); + newBlockers.delete(name); + return { ...prev, blockers: newBlockers }; + }), + }), + [] + ); + + const shouldBlockNavigationTo = useCallback( + (location: Location) => { + return [...status.blockers.values()].reduce((acc, blockerDelegate) => { + return acc || blockerDelegate({ location }); + }, false); + }, + [status.blockers] + ); + + useEffect(() => { + const cleanup = history.block((location, action) => { + // history.replace is usually necessary for plumbing, so no reason to block. + if (action === "REPLACE") { + return; + } + + blockerCtx.unblock(); + + if (status.bypassBlockers) { + return; + } + + if (!shouldBlockNavigationTo(location)) { + return; + } + + blockerCtx.block(location); + return false; + }); + + return () => { + cleanup(); + }; + }, [blockerCtx, history, shouldBlockNavigationTo, status.bypassBlockers]); + + const statusCtx = useMemo( + () => ({ + ...status, + shouldBlockNavigationTo, + }), + [status, shouldBlockNavigationTo] + ); + + return ( + + + <>{props.children} + + + ); +} diff --git a/packages/runtime-tools-management-console-webapp/src/navigation/Routes.ts b/packages/runtime-tools-management-console-webapp/src/navigation/Routes.ts new file mode 100644 index 00000000000..797e7951ba2 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/navigation/Routes.ts @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { LocationDescriptor } from "history"; + +declare global { + interface Window { + BASE_PATH: string; + } +} + +const IS_HASH_ROUTER = false; + +export enum QueryParams { + USER = "user", + FILTERS = "filters", + SORT_BY = "sort", + ORDER_BY = "order", + IMPERSONATION_USER = "impersonationUsername", + IMPERSONATION_GROUP = "impersonationGroup", +} + +export enum PathParams { + RUNTIME_URL = "runtimeUrl", + PROCESS_INSTANCE_ID = "processInstanceId", + TASK_ID = "taskId", +} + +export class Route< + T extends { + pathParams?: any; + queryParams?: any; + }, +> { + constructor(private readonly pathDelegate: (pathParams: { [k in T["pathParams"]]: string }) => string) {} + + public url(args: { + base?: string; + static?: boolean; + pathParams: { [k in T["pathParams"]]: string }; + queryParams?: Partial<{ [k in T["queryParams"]]: string }>; + }) { + const path = this.pathDelegate(args.pathParams); + const SEP = args.base?.endsWith("/") || path.startsWith("/") ? "" : "/"; + const HASH = !args.static && IS_HASH_ROUTER ? "#" : ""; + const queryParams = args.queryParams ?? {}; + + if (!args.base && Object.keys(queryParams).length <= 0) { + return `${HASH}${path}`; + } + + if (!args.base) { + return `${HASH}${path}?${this.queryString(queryParams)}`; + } + + if (Object.keys(queryParams).length <= 0) { + return `${args.base}${SEP}${HASH}${path}`; + } + + return `${args.base}${SEP}${HASH}${path}?${this.queryString(queryParams)}`; + } + + public queryString(queryParams: Partial<{ [k in T["queryParams"]]: string }>) { + return decodeURIComponent(new URLSearchParams(queryParams as Record).toString()); + } + + public queryArgs(queryString: QueryParamsImpl): QueryParamsImpl { + return queryString; + } + + public path(pathParams: { [k in T["pathParams"]]: string }) { + return this.pathDelegate(pathParams); + } +} + +export interface QueryParamsImpl { + has(name: Q): boolean; + get(name: Q): string | undefined; + with(name: Q, value: string | undefined): QueryParamsImpl; + without(name: Q): QueryParamsImpl; + toString(): string; +} + +export function newQueryParamsImpl(queryString: string): QueryParamsImpl { + return { + has: (name) => new URLSearchParams(queryString).has(name), + get: (name) => { + const val = new URLSearchParams(queryString).get(name); + return !val ? undefined : decodeURIComponent(val); + }, + with: (name, value) => { + const urlSearchParams = new URLSearchParams(queryString); + if (value === undefined) { + urlSearchParams.delete(name); + } else { + urlSearchParams.set(name, value); + } + return newQueryParamsImpl(decodeURIComponent(urlSearchParams.toString())); + }, + without: (name) => { + const urlSearchParams = new URLSearchParams(queryString); + urlSearchParams.delete(name); + return newQueryParamsImpl(decodeURIComponent(urlSearchParams.toString())); + }, + toString: () => { + return decodeURIComponent(new URLSearchParams(queryString).toString()); + }, + }; +} + +export const routes = { + home: new Route<{}>(() => "/"), + + runtime: { + context: new Route<{ + pathParams: PathParams.RUNTIME_URL; + queryParams: QueryParams.USER; + }>(({ runtimeUrl }) => `/${runtimeUrl}`), + + processes: new Route<{ + pathParams: PathParams.RUNTIME_URL; + queryParams: QueryParams.USER | QueryParams.FILTERS | QueryParams.SORT_BY; + }>(({ runtimeUrl }) => `/${runtimeUrl}/processes`), + + processDetails: new Route<{ + pathParams: PathParams.RUNTIME_URL | PathParams.PROCESS_INSTANCE_ID; + queryParams: QueryParams.USER; + }>(({ runtimeUrl, processInstanceId }) => `/${runtimeUrl}/process/${processInstanceId}`), + + jobs: new Route<{ + pathParams: PathParams.RUNTIME_URL; + queryParams: QueryParams.USER | QueryParams.FILTERS | QueryParams.ORDER_BY; + }>(({ runtimeUrl }) => `/${runtimeUrl}/jobs`), + + tasks: new Route<{ + pathParams: PathParams.RUNTIME_URL; + queryParams: + | QueryParams.USER + | QueryParams.FILTERS + | QueryParams.SORT_BY + | QueryParams.IMPERSONATION_USER + | QueryParams.IMPERSONATION_GROUP; + }>(({ runtimeUrl }) => `/${runtimeUrl}/tasks`), + + taskDetails: new Route<{ + pathParams: PathParams.RUNTIME_URL | PathParams.TASK_ID; + queryParams: QueryParams.USER | QueryParams.IMPERSONATION_USER | QueryParams.IMPERSONATION_GROUP; + }>(({ runtimeUrl, taskId }) => `/${runtimeUrl}/task/${taskId}`), + }, + + login: new Route<{}>(() => `/login`), + + static: { + images: { + appLogoDefault: new Route<{}>(() => `/images/app_logo_rgb_fullcolor_default.svg`), + appLogoReverse: new Route<{}>(() => `/images/app_logo_rgb_fullcolor_reverse.svg`), + }, + }, +} as const; + +export function buildRouteUrl< + T extends { + pathParams: any; + queryParams: any; + }, +>( + route: Route, + pathParams?: { [k in T["pathParams"]]: string }, + queryParams?: Partial<{ [k in T["queryParams"]]: string }>, + extraQueryParams?: Record +) { + const encodedPathParams = {} as T["pathParams"]; + if (pathParams) { + for (const [key, value] of Object.entries(pathParams)) { + encodedPathParams[key] = encodeURIComponent(value as string); + } + } + const pathname = route.path(encodedPathParams); + + const searchParams: string[] = []; + if (queryParams || extraQueryParams) { + for (const [key, value] of Object.entries({ ...(queryParams ?? {}), ...(extraQueryParams ?? {}) })) { + if (value) { + searchParams.push(`${key}=${encodeURIComponent(value as string)}`); + } + } + } + const search = searchParams.length > 0 ? `?${searchParams.join("&")}` : ""; + + return { + pathname, + search, + }; +} diff --git a/packages/runtime-tools-management-console-webapp/src/navigation/queryParams/QueryParamsContext.ts b/packages/runtime-tools-management-console-webapp/src/navigation/queryParams/QueryParamsContext.ts new file mode 100644 index 00000000000..bfcce8c5d15 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/navigation/queryParams/QueryParamsContext.ts @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { useLocation } from "react-router"; +import { useMemo } from "react"; +import { newQueryParamsImpl, QueryParamsImpl } from "../Routes"; + +export function useQueryParams(): QueryParamsImpl { + const location = useLocation(); + return useMemo(() => newQueryParamsImpl(location.search), [location.search]); +} + +export function useQueryParam(name: string) { + const queryParams = useQueryParams(); + return useMemo(() => queryParams.get(name), [queryParams, name]); +} diff --git a/packages/runtime-tools-management-console-webapp/src/process/details/ProcessDetails.tsx b/packages/runtime-tools-management-console-webapp/src/process/details/ProcessDetails.tsx new file mode 100644 index 00000000000..c971bdf3519 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/process/details/ProcessDetails.tsx @@ -0,0 +1,141 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 * as React from "react"; +import { useState, useEffect, useCallback, useMemo } from "react"; +import { Card } from "@patternfly/react-core/dist/js/components/Card"; +import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye"; +import { ProcessInstance } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; +import { ServerErrors } from "@kie-tools/runtime-tools-components/dist/components/ServerErrors"; +import { KogitoSpinner } from "@kie-tools/runtime-tools-components/dist/components/KogitoSpinner"; +import { + useProcessDetailsGatewayApi, + ProcessDetailsGatewayApi, +} from "@kie-tools/runtime-tools-process-webapp-components/dist/ProcessDetails"; +import { + EmptyState, + EmptyStateBody, + EmptyStateIcon, + EmptyStateVariant, +} from "@patternfly/react-core/dist/js/components/EmptyState"; +import { SearchIcon } from "@patternfly/react-icons/dist/js/icons/search-icon"; +import { Title } from "@patternfly/react-core/dist/js/components/Title"; +import { Button } from "@patternfly/react-core/dist/js/components/Button"; +import { useCancelableEffect } from "@kie-tools-core/react-hooks/dist/useCancelableEffect"; +import { EmbeddedProcessDetails } from "@kie-tools/runtime-tools-process-enveloped-components/dist/processDetails"; +import { useRuntimeSpecificRoutes } from "../../runtime/RuntimeContext"; +import { useHistory } from "react-router"; + +interface Props { + processInstanceId: string; + onReturnToProcessList: () => void; +} + +export const ProcessDetails: React.FC = ({ processInstanceId, onReturnToProcessList }) => { + const gatewayApi: ProcessDetailsGatewayApi = useProcessDetailsGatewayApi(); + const runtimeRoutes = useRuntimeSpecificRoutes(); + const history = useHistory(); + const [processInstance, setProcessInstance] = useState(); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(); + + useCancelableEffect( + useCallback( + ({ canceled }) => { + if (canceled.get()) { + return; + } + setIsLoading(true); + gatewayApi + .processDetailsQuery(processInstanceId) + .then((response) => { + if (canceled.get()) { + return; + } + setProcessInstance(response); + }) + .catch((error) => { + console.log("DEU ERROR!"); + setError(error); + }) + .finally(() => { + setIsLoading(false); + }); + }, + [gatewayApi, processInstanceId] + ) + ); + + useEffect(() => { + const unSubscribeHandler = gatewayApi.onOpenProcessInstanceDetailsListener({ + onOpen(id: string) { + history.push(runtimeRoutes.processDetails(id)); + }, + }); + + return () => { + unSubscribeHandler.unSubscribe(); + }; + }, [gatewayApi, history, runtimeRoutes]); + + // Loading State + if (isLoading) { + return ( + + + + ); + } + + // Error State + if (error) { + return ( + + + + ); + } + + // Process Instance Details + if (processInstance) { + return ( + + ); + } + + return ( + + + + + Process instance not found + + {`Process instance with the id ${processInstanceId} not found`} + + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/process/details/ProcessDetailsPage.tsx b/packages/runtime-tools-management-console-webapp/src/process/details/ProcessDetailsPage.tsx new file mode 100644 index 00000000000..80ca204fa41 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/process/details/ProcessDetailsPage.tsx @@ -0,0 +1,104 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback, useEffect } from "react"; +import { ProcessDetails } from "./ProcessDetails"; +import { useRuntimeInfo, useRuntimeSpecificRoutes } from "../../runtime/RuntimeContext"; +import { AuthSession, useAuthSessionsDispatch } from "../../authSessions"; +import { useHistory } from "react-router"; +import { KogitoSpinner } from "@kie-tools/runtime-tools-components/dist/components/KogitoSpinner"; +import { useEnv } from "../../env/hooks/EnvContext"; +import { useRoutes } from "../../navigation/Hooks"; +import { useRuntimePageLayoutDispatch } from "../../runtime/RuntimePageLayoutContext"; + +export const ProcessDetailsPage: React.FC<{ processInstanceId?: string }> = ({ processInstanceId }) => { + const history = useHistory(); + const runtimeRoutes = useRuntimeSpecificRoutes(); + const routes = useRoutes(); + const { runtimeDisplayInfo } = useRuntimeInfo(); + const { setOnSelectAuthSession } = useAuthSessionsDispatch(); + const { setCurrentPageTitle, setBreadcrumbPath, setBreadcrumbText } = useRuntimePageLayoutDispatch(); + const { env } = useEnv(); + + const onNavigateToProcessDetails = useCallback( + (authSession?: AuthSession) => { + if (processInstanceId) { + history.push(runtimeRoutes.processDetails(processInstanceId, authSession)); + } else { + history.push(runtimeRoutes.processes(authSession)); + } + }, + [history, processInstanceId, runtimeRoutes] + ); + + const onNavigateToProcessesList = useCallback(() => { + history.push(runtimeRoutes.processes()); + }, [runtimeRoutes, history]); + + useEffect(() => { + setOnSelectAuthSession(() => onNavigateToProcessDetails); + + return () => { + setOnSelectAuthSession(undefined); + }; + }, [onNavigateToProcessDetails, setOnSelectAuthSession]); + + useEffect(() => { + setCurrentPageTitle("Process Instance"); + setBreadcrumbText([ + "Home", + runtimeDisplayInfo?.fullDisplayName ?? "Runtime", + "Process Instances", + processInstanceId ?? "", + ]); + setBreadcrumbPath([ + routes.home.path({}), + runtimeRoutes.processes(), + runtimeRoutes.processes(), + processInstanceId ? runtimeRoutes.processDetails(processInstanceId) : runtimeRoutes.processes(), + ]); + + return () => { + setCurrentPageTitle(""); + setBreadcrumbText([]); + setBreadcrumbPath([]); + }; + }, [ + processInstanceId, + routes.home, + runtimeDisplayInfo?.fullDisplayName, + runtimeRoutes, + setBreadcrumbPath, + setBreadcrumbText, + setCurrentPageTitle, + ]); + + useEffect(() => { + document.title = `${env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME} :: Process Instance :: ${processInstanceId}`; + }, [env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME, processInstanceId]); + + return ( + <> + {processInstanceId ? ( + + ) : ( + + )} + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/dev/server/config/index.js b/packages/runtime-tools-management-console-webapp/src/process/index.ts similarity index 80% rename from packages/runtime-tools-management-console-webapp/dev/server/config/index.js rename to packages/runtime-tools-management-console-webapp/src/process/index.ts index d6ec683bf1a..aa731b59cb3 100644 --- a/packages/runtime-tools-management-console-webapp/dev/server/config/index.js +++ b/packages/runtime-tools-management-console-webapp/src/process/index.ts @@ -16,10 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -const commonConfig = { - env: process.env.NODE_ENV || "development", - port: parseInt(process.env.PORT, 10) || 4000, - corsDomain: process.env.CORS_DOMAIN || "*", -}; - -module.exports = commonConfig; +export * from "./details/ProcessDetails"; +export * from "./details/ProcessDetailsPage"; +export * from "./list/ProcessList"; +export * from "./list/ProcessListPage"; diff --git a/packages/runtime-tools-management-console-webapp/src/process/list/ProcessList.tsx b/packages/runtime-tools-management-console-webapp/src/process/list/ProcessList.tsx new file mode 100644 index 00000000000..ebb4643a2ab --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/process/list/ProcessList.tsx @@ -0,0 +1,119 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useEffect, useMemo } from "react"; +import { + ProcessListState, + ProcessInstance, + ProcessInstanceState, + ProcessInstanceFilter, + ProcessListSortBy, +} from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; +import { + ProcessListGatewayApi, + useProcessListGatewayApi, +} from "@kie-tools/runtime-tools-process-webapp-components/dist/ProcessList"; +import { EmbeddedProcessList } from "@kie-tools/runtime-tools-process-enveloped-components/dist/processList"; +import { useHistory } from "react-router"; +import { OrderBy } from "@kie-tools/runtime-tools-shared-gateway-api/dist/types"; +import { useQueryParam, useQueryParams } from "../../navigation/queryParams/QueryParamsContext"; +import { QueryParams } from "../../navigation/Routes"; +import { RuntimePathSearchParamsRoutes, useRuntimeDispatch } from "../../runtime/RuntimeContext"; + +const defaultFilters = { + status: [ProcessInstanceState.Active], + businessKey: [], +}; + +const defaultSortBy = { + lastUpdate: OrderBy.DESC, +}; + +interface Props { + onNavigateToProcessDetails: (processInstanceId: string) => void; +} + +export const ProcessList: React.FC = ({ onNavigateToProcessDetails }) => { + const gatewayApi: ProcessListGatewayApi = useProcessListGatewayApi(); + const history = useHistory(); + const filters = useQueryParam(QueryParams.FILTERS); + const sortBy = useQueryParam(QueryParams.SORT_BY); + const queryParams = useQueryParams(); + const { setRuntimePathSearchParams } = useRuntimeDispatch(); + + const initialState: ProcessListState = useMemo(() => { + return { + filters: filters ? (JSON.parse(filters) as ProcessInstanceFilter) : defaultFilters, + sortBy: sortBy ? (JSON.parse(sortBy) as ProcessListSortBy) : defaultSortBy, + }; + }, [filters, sortBy]); + + useEffect(() => { + const newSearchParams = { + [QueryParams.FILTERS]: JSON.stringify(initialState.filters), + [QueryParams.SORT_BY]: JSON.stringify(initialState.sortBy), + }; + setRuntimePathSearchParams((currentRuntimePathSearchParams) => { + return currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.PROCESSES, newSearchParams); + }); + }, [initialState, setRuntimePathSearchParams]); + + useEffect(() => { + const unsubscriber = gatewayApi.onOpenProcessListen({ + onOpen(process: ProcessInstance) { + onNavigateToProcessDetails(process.id); + }, + }); + + return () => { + unsubscriber.unSubscribe(); + }; + }, [gatewayApi, onNavigateToProcessDetails]); + + useEffect(() => { + const unsubscriber = gatewayApi.onUpdateProcessListState({ + onUpdate(processListState: ProcessListState) { + const newSearchParams = { + [QueryParams.FILTERS]: JSON.stringify(processListState.filters), + [QueryParams.SORT_BY]: JSON.stringify(processListState.sortBy), + }; + setRuntimePathSearchParams((currentRuntimePathSearchParams) => { + return currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.PROCESSES, newSearchParams); + }); + const newQueryParams = queryParams + .with(QueryParams.FILTERS, newSearchParams[QueryParams.FILTERS]) + .with(QueryParams.SORT_BY, newSearchParams[QueryParams.SORT_BY]); + history.replace({ pathname: history.location.pathname, search: newQueryParams.toString() }); + }, + }); + + return () => { + unsubscriber.unSubscribe(); + }; + }, [gatewayApi, history, queryParams, setRuntimePathSearchParams]); + + return ( + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/process/list/ProcessListPage.tsx b/packages/runtime-tools-management-console-webapp/src/process/list/ProcessListPage.tsx new file mode 100644 index 00000000000..65399a20194 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/process/list/ProcessListPage.tsx @@ -0,0 +1,83 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback, useEffect } from "react"; +import { Card } from "@patternfly/react-core/dist/js/components/Card"; +import { ProcessList } from "./ProcessList"; +import { useRuntimeInfo, useRuntimeSpecificRoutes } from "../../runtime/RuntimeContext"; +import { AuthSession, useAuthSessionsDispatch } from "../../authSessions"; +import { useHistory } from "react-router"; +import { useRoutes } from "../../navigation/Hooks"; +import { useEnv } from "../../env/hooks/EnvContext"; +import { useRuntimePageLayoutDispatch } from "../../runtime/RuntimePageLayoutContext"; + +export const ProcessListPage: React.FC = () => { + const { env } = useEnv(); + const history = useHistory(); + const runtimeRoutes = useRuntimeSpecificRoutes(); + const routes = useRoutes(); + const { runtimeDisplayInfo } = useRuntimeInfo(); + const { setOnSelectAuthSession } = useAuthSessionsDispatch(); + const { setCurrentPageTitle, setBreadcrumbText, setBreadcrumbPath } = useRuntimePageLayoutDispatch(); + + useEffect(() => { + setOnSelectAuthSession(() => (authSession: AuthSession) => { + history.push(runtimeRoutes.processes(authSession)); + }); + + return () => { + setOnSelectAuthSession(undefined); + }; + }, [history, runtimeRoutes, setOnSelectAuthSession]); + + useEffect(() => { + setCurrentPageTitle("Process Instances"); + setBreadcrumbText(["Home", runtimeDisplayInfo?.fullDisplayName ?? "Runtime", "Process Instances"]); + setBreadcrumbPath([routes.home.path({}), runtimeRoutes.processes(), runtimeRoutes.processes()]); + + return () => { + setCurrentPageTitle(""); + setBreadcrumbText([]); + setBreadcrumbPath([]); + }; + }, [ + routes.home, + runtimeDisplayInfo?.fullDisplayName, + runtimeRoutes, + setBreadcrumbPath, + setBreadcrumbText, + setCurrentPageTitle, + ]); + + const onNavigateToProcessDetails = useCallback( + (processInstanceId: string) => { + history.push(runtimeRoutes.processDetails(processInstanceId)); + }, + [history, runtimeRoutes] + ); + + useEffect(() => { + document.title = `${env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME} :: Process Instances`; + }, [env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME]); + + return ( + + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeContext.tsx b/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeContext.tsx new file mode 100644 index 00000000000..d91cacd59cf --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeContext.tsx @@ -0,0 +1,499 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { createContext, ReactElement, useCallback, useContext, useEffect, useMemo, useState } from "react"; +import { useQueryParam, useQueryParams } from "../navigation/queryParams/QueryParamsContext"; +import { buildRouteUrl, QueryParams } from "../navigation/Routes"; +import { useAuthSessions, useAuthSessionsDispatch } from "../authSessions/AuthSessionsContext"; +import { + AuthSession, + AuthSessionStatus, + getAuthSessionDisplayInfo, + isOpenIdConnectAuthSession, + isUnauthenticatedAuthSession, + OpenIDConnectAuthSession, +} from "../authSessions/AuthSessionApi"; +import { useHistory } from "react-router"; +import { useRoutes } from "../navigation/Hooks"; +import ApolloClient from "apollo-client"; +import { InMemoryCache, NormalizedCacheObject } from "apollo-cache-inmemory"; +import { HttpLink } from "apollo-link-http"; +import { from } from "apollo-link"; +import { onError, ErrorResponse } from "apollo-link-error"; +import { + KogitoAppContextProvider, + UserContext, +} from "@kie-tools/runtime-tools-components/dist/contexts/KogitoAppContext"; +import { ApolloProvider } from "react-apollo"; +import { AuthSessionsService } from "../authSessions"; +import { useEnv } from "../env/hooks/EnvContext"; +import { ProcessListContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/ProcessList"; +import { JobsManagementContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/JobsManagement"; +import { ProcessDetailsContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/ProcessDetails"; +import { TaskInboxContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/TaskInbox"; +import { TaskFormContextProvider } from "@kie-tools/runtime-tools-process-webapp-components/dist/TaskForms"; + +export type RuntimePathSearchParams = Partial>; +export enum RuntimePathSearchParamsRoutes { + PROCESSES = "processes", + JOBS = "jobs", + TASKS = "tasks", + TASK_DETAILS = "taskDetails", +} + +export type RuntimeContextType = { + apolloClient?: ApolloClient; + userContext?: UserContext; + runtimeUrl?: string; + username?: string; + isRefreshingToken: boolean; + runtimePathSearchParams: Map; + impersonationUsername?: string; + impersonationGroup?: string; +}; + +export const RuntimeContext = createContext({} as RuntimeContextType); + +export type RuntimeDispatchContextType = { + refreshToken: (authSession: OpenIDConnectAuthSession) => Promise; + setRuntimePathSearchParams: React.Dispatch< + React.SetStateAction> + >; + setImpersonationUsername: React.Dispatch>; + setImpersonationGroup: React.Dispatch>; +}; + +export const RuntimeDispatchContext = createContext({} as RuntimeDispatchContextType); + +export function useRuntime() { + return useContext(RuntimeContext); +} + +export function useRuntimeDispatch() { + return useContext(RuntimeDispatchContext); +} + +export interface RuntimeContextProviderProps { + children: ReactElement; + runtimeUrl?: string; + fullPath?: string; +} + +export const RuntimeContextProvider: React.FC = (props) => { + const { env } = useEnv(); + const { authSessions } = useAuthSessions(); + const history = useHistory(); + const routes = useRoutes(); + const user = useQueryParam(QueryParams.USER); + const impersonationUsernameQueryParam = useQueryParam(QueryParams.IMPERSONATION_USER); + const impersonationGroupQueryParam = useQueryParam(QueryParams.IMPERSONATION_GROUP); + const queryParams = useQueryParams(); + const [runtimeUrl, setRuntimeUrl] = useState(); + const [username, setUsername] = useState(); + const [impersonationUsername, setImpersonationUsername] = useState( + impersonationUsernameQueryParam + ); + const [impersonationGroup, setImpersonationGroup] = useState(impersonationGroupQueryParam); + const [accessToken, setAccessToken] = useState(); + const [apolloClient, setApolloClient] = useState>(); + const [userContext, setUserContext] = useState(); + const [isRefreshingToken, setIsRefreshingToken] = useState(false); + const [runtimePathSearchParams, setRuntimePathSearchParams] = useState< + Map + >(new Map([])); + const { add: updateAuthSession, setCurrentAuthSession } = useAuthSessionsDispatch(); + const { currentAuthSession } = useAuthSessions(); + + useEffect(() => { + if (isRefreshingToken) { + return; + } + + if (!props.runtimeUrl) { + // TODO: No runtimeUrl set, show some warning. + // runtimeUrl not set, going home + history.push(routes.home.path({})); + setCurrentAuthSession(undefined); + return; + } + + const validRuntimeAuthSessions = [...authSessions] + .map(([_, session]) => session) + .filter((session) => { + return session.runtimeUrl === props.runtimeUrl && session.status === AuthSessionStatus.VALID; + }); + + // Compatible AuthSession not found + if (!validRuntimeAuthSessions.length) { + // TODO: Navigate to page to add the runtime as an AuthSession + // Going home for now. + history.push(routes.home.path({})); + setCurrentAuthSession(undefined); + return; + } + + // User not specified via queryParam. + if (!user) { + // Compatible AuthSession found but it's authenticated. Redirect to the same route with the first matched AuthSession's user. + if (isOpenIdConnectAuthSession(validRuntimeAuthSessions[0])) { + const updatedQueryParams = queryParams.with("user", validRuntimeAuthSessions[0].username); + history.push({ pathname: history.location.pathname, search: updatedQueryParams.toString() }); + return; + } + // First matched AuthSession is not authenticated, use it. + setCurrentAuthSession(validRuntimeAuthSessions[0]); + return; + } + + // User is specified, look for it in the matched AuthSessions. + const currentUserAuthSession = validRuntimeAuthSessions.find( + (session) => isOpenIdConnectAuthSession(session) && session.username === user + ); + + // Perfect match! Stay on the page. + if (currentUserAuthSession) { + setCurrentAuthSession(currentUserAuthSession); + return; + } else { + // Look for authenticated AuthSession for the same runtimeUrl but with another user + const possibleAuthenticatedAuthSession = validRuntimeAuthSessions.find((session) => + isOpenIdConnectAuthSession(session) + ); + // Compatible AuthSession found (with different user) + // Redirecting to it. + if (possibleAuthenticatedAuthSession) { + const updatedQueryParams = queryParams.with("user", possibleAuthenticatedAuthSession.username); + history.push({ + pathname: history.location.pathname, + search: updatedQueryParams.toString(), + }); + return; + } + } + + // Couldn't find an AuthSession with the same user. + // Look for unauthenticated AuthSession for the same runtime + const unauthenticatedAuthSession = validRuntimeAuthSessions.find((session) => + isUnauthenticatedAuthSession(session) + ); + if (unauthenticatedAuthSession) { + // Compatible AuthSession found but it's unauthenticated. Redirect to the same route without specifying user. + const updatedQueryParams = queryParams.without("user"); + history.push({ pathname: history.location.pathname, search: updatedQueryParams.toString() }); + setCurrentAuthSession(undefined); + return; + } + + // Compatible AuthSession not found + // TODO: Navigate to page to add the runtime as an AuthSession + // Going home for now. + history.push(routes.home.path({})); + setCurrentAuthSession(undefined); + }, [ + authSessions, + history, + props.runtimeUrl, + user, + isRefreshingToken, + routes.home, + queryParams, + setCurrentAuthSession, + ]); + + const refreshToken = useCallback( + async (authSession: OpenIDConnectAuthSession) => { + try { + setIsRefreshingToken(true); + const reauthResponse = await AuthSessionsService.reauthenticate({ + authSession, + clientId: env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_OIDC_CLIENT_CLIENT_ID, + }); + const updatedAuthSession: AuthSession = { + ...authSession, + ...reauthResponse, + }; + + await updateAuthSession(updatedAuthSession); + + return updatedAuthSession; + } catch (e) { + console.log("Failed to get new tokens: ", e); + await updateAuthSession({ + ...authSession, + status: AuthSessionStatus.INVALID, + }); + history.push(routes.home.path({})); + } finally { + setIsRefreshingToken(false); + } + }, + [env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_OIDC_CLIENT_CLIENT_ID, updateAuthSession, history, routes.home] + ); + + const onUnauthorized = useCallback( + async (networkError: ErrorResponse["networkError"]) => { + if (isOpenIdConnectAuthSession(currentAuthSession)) { + await refreshToken(currentAuthSession); + } else { + throw new Error(`Got unauthorized response for unauthenticated runtime! ${networkError}`); + } + }, + [currentAuthSession, refreshToken] + ); + + const createApolloClient = useCallback( + (runtimeUrl: string, token?: string) => { + if (!runtimeUrl) { + return; + } + const httpLink = new HttpLink({ + uri: `${runtimeUrl}/graphql`, + ...(token + ? { + headers: { + authorization: token ? `Bearer ${token}` : "", + }, + } + : {}), + }); + + const apolloNetworkErrorLink = onError(({ graphQLErrors, networkError, response, operation, forward }) => { + if (networkError && (networkError as any).statusCode === 401) { + onUnauthorized(networkError); + // forward(operation); + } + }); + + const cache = new InMemoryCache(); + const client: ApolloClient = new ApolloClient({ + cache, + link: from([apolloNetworkErrorLink, httpLink]), + }); + + return client; + }, + [onUnauthorized] + ); + + const createUserContext = useCallback( + (username?: string, impersonationUsername?: string, impersonationGroup?: string): UserContext => { + return { + getCurrentUser: () => ({ + id: impersonationUsername ?? (impersonationGroup ? "" : username) ?? "", + groups: impersonationGroup ? [impersonationGroup] : [], + }), + }; + }, + [] + ); + + useEffect(() => { + if (isOpenIdConnectAuthSession(currentAuthSession)) { + setUsername(currentAuthSession.username); + setAccessToken(currentAuthSession.tokens.access_token); + setRuntimeUrl(currentAuthSession.runtimeUrl); + return; + } + + if (isUnauthenticatedAuthSession(currentAuthSession)) { + setUsername(undefined); + setAccessToken(undefined); + setRuntimeUrl(currentAuthSession.runtimeUrl); + return; + } + + setUsername(undefined); + setAccessToken(undefined); + setRuntimeUrl(undefined); + }, [currentAuthSession]); + + useEffect(() => { + setApolloClient(runtimeUrl ? createApolloClient(runtimeUrl, accessToken) : undefined); + }, [createApolloClient, runtimeUrl, accessToken]); + + useEffect(() => { + setUserContext(createUserContext(username, impersonationUsername, impersonationGroup)); + }, [createUserContext, username, impersonationUsername, impersonationGroup]); + + const value = useMemo( + () => ({ + apolloClient, + userContext, + runtimeUrl, + username, + isRefreshingToken, + runtimePathSearchParams, + impersonationUsername, + impersonationGroup, + }), + [ + apolloClient, + userContext, + runtimeUrl, + username, + isRefreshingToken, + runtimePathSearchParams, + impersonationUsername, + impersonationGroup, + ] + ); + + const dispatch = useMemo( + () => ({ refreshToken, setRuntimePathSearchParams, setImpersonationUsername, setImpersonationGroup }), + [refreshToken, setRuntimePathSearchParams] + ); + + return ( + + + {apolloClient && userContext && !isRefreshingToken ? ( + + + + + + + {props.children} + + + + + + + ) : ( +
Loading...
+ )} +
+
+ ); +}; + +export function useRuntimeApolloClient() { + const { apolloClient } = useContext(RuntimeContext); + return useMemo(() => apolloClient, [apolloClient]); +} + +export function useRuntimeUser() { + const { userContext } = useContext(RuntimeContext); + return useMemo(() => userContext, [userContext]); +} + +export function useRuntimeInfo() { + const { runtimeUrl, username, isRefreshingToken } = useRuntime(); + const { currentAuthSession } = useAuthSessions(); + + const runtimeDisplayInfo = useMemo(() => { + if (!currentAuthSession) { + return undefined; + } + return getAuthSessionDisplayInfo(currentAuthSession); + }, [currentAuthSession]); + + const accessToken = useMemo(() => { + if (!currentAuthSession || isUnauthenticatedAuthSession(currentAuthSession)) { + return undefined; + } + return currentAuthSession.tokens.access_token; + }, [currentAuthSession]); + + const canImpersonate = useMemo(() => currentAuthSession?.impersonator, [currentAuthSession?.impersonator]); + + return useMemo( + () => ({ runtimeUrl, username, accessToken, runtimeDisplayInfo, isRefreshingToken, canImpersonate }), + [runtimeUrl, username, runtimeDisplayInfo, accessToken, isRefreshingToken, canImpersonate] + ); +} + +export function useRuntimeSpecificRoutes() { + const { runtimePathSearchParams, runtimeUrl, username } = useRuntime(); + const routes = useRoutes(); + + return useMemo( + () => ({ + processes: (authSession?: AuthSession) => { + const pathRuntimeUrl = authSession ? authSession.runtimeUrl : runtimeUrl; + const pathUsername = authSession && isOpenIdConnectAuthSession(authSession) ? authSession.username : username; + if (pathRuntimeUrl) { + return buildRouteUrl( + routes.runtime.processes, + { runtimeUrl: pathRuntimeUrl }, + { user: pathUsername }, + runtimePathSearchParams.get(RuntimePathSearchParamsRoutes.PROCESSES) + ); + } + // Should never come to this... + return buildRouteUrl(routes.home); + }, + processDetails: (processInstanceId: string, authSession?: AuthSession) => { + const pathRuntimeUrl = authSession ? authSession.runtimeUrl : runtimeUrl; + const pathUsername = authSession && isOpenIdConnectAuthSession(authSession) ? authSession.username : username; + if (pathRuntimeUrl) { + return buildRouteUrl( + routes.runtime.processDetails, + { runtimeUrl: pathRuntimeUrl, processInstanceId }, + { user: pathUsername } + ); + } + // Should never come to this... + return buildRouteUrl(routes.home); + }, + jobs: (authSession?: AuthSession) => { + const pathRuntimeUrl = authSession ? authSession.runtimeUrl : runtimeUrl; + const pathUsername = authSession && isOpenIdConnectAuthSession(authSession) ? authSession.username : username; + if (pathRuntimeUrl) { + return buildRouteUrl( + routes.runtime.jobs, + { runtimeUrl: pathRuntimeUrl }, + { user: pathUsername }, + runtimePathSearchParams.get(RuntimePathSearchParamsRoutes.JOBS) + ); + } + // Should never come to this... + return buildRouteUrl(routes.home); + }, + tasks: (authSession?: AuthSession) => { + const pathRuntimeUrl = authSession ? authSession.runtimeUrl : runtimeUrl; + const pathUsername = authSession && isOpenIdConnectAuthSession(authSession) ? authSession.username : username; + if (pathRuntimeUrl) { + return buildRouteUrl( + routes.runtime.tasks, + { runtimeUrl: pathRuntimeUrl }, + { user: pathUsername }, + runtimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASKS) + ); + } + // Should never come to this... + return buildRouteUrl(routes.home); + }, + taskDetails: (taskId: string, authSession?: AuthSession) => { + const pathRuntimeUrl = authSession ? authSession.runtimeUrl : runtimeUrl; + const pathUsername = authSession && isOpenIdConnectAuthSession(authSession) ? authSession.username : username; + if (pathRuntimeUrl) { + return buildRouteUrl( + routes.runtime.taskDetails, + { runtimeUrl: pathRuntimeUrl, taskId }, + { user: pathUsername } + ); + } + // Should never come to this... + return buildRouteUrl(routes.home); + }, + }), + [runtimeUrl, username, routes, runtimePathSearchParams] + ); +} diff --git a/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeNav.tsx b/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeNav.tsx new file mode 100644 index 00000000000..125663d9a1e --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeNav.tsx @@ -0,0 +1,60 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useMemo } from "react"; +import { Nav, NavItem, NavList } from "@patternfly/react-core/dist/js/components/Nav"; +import { Link, useHistory } from "react-router-dom"; +import { useRuntimeSpecificRoutes } from "./RuntimeContext"; + +export const RuntimeNav: React.FC = () => { + const runtimeRoutes = useRuntimeSpecificRoutes(); + const history = useHistory(); + + return ( + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/runtime/RuntimePageLayoutContext.tsx b/packages/runtime-tools-management-console-webapp/src/runtime/RuntimePageLayoutContext.tsx new file mode 100644 index 00000000000..4b03e4570cb --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/runtime/RuntimePageLayoutContext.tsx @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { createContext, PropsWithChildren, useContext, useMemo, useState } from "react"; +import { Location, LocationDescriptor } from "history"; +import { ManagementConsolePageLayout } from "../managementConsole/ManagementConsolePageLayout"; +import { RuntimeNav } from "./RuntimeNav"; + +export type BreadcrumbPathType = Array | LocationDescriptor>; + +export type RuntimePageLayoutContextType = { + currentPageTitle: string; + breadcrumbText: string[]; + breadcrumbPath: BreadcrumbPathType; +}; + +export type RuntimePageLayoutDispatchContextType = { + setCurrentPageTitle: React.Dispatch>; + setBreadcrumbText: React.Dispatch>; + setBreadcrumbPath: React.Dispatch>; +}; + +const RuntimePageLayoutContext = createContext({} as RuntimePageLayoutContextType); +const RuntimePageLayoutDispatchContext = createContext( + {} as RuntimePageLayoutDispatchContextType +); + +export function useRuntimePageLayout() { + return useContext(RuntimePageLayoutContext); +} + +export function useRuntimePageLayoutDispatch() { + return useContext(RuntimePageLayoutDispatchContext); +} + +export function RuntimePageLayoutContextProvider(props: PropsWithChildren<{}>) { + const [currentPageTitle, setCurrentPageTitle] = useState(""); + const [breadcrumbText, setBreadcrumbText] = useState([]); + const [breadcrumbPath, setBreadcrumbPath] = useState([]); + + const value = useMemo( + () => ({ currentPageTitle, breadcrumbText, breadcrumbPath }), + [breadcrumbPath, breadcrumbText, currentPageTitle] + ); + const dispatch = useMemo(() => ({ setCurrentPageTitle, setBreadcrumbText, setBreadcrumbPath }), []); + + return ( + + + } + > + {props.children} + + + + ); +} diff --git a/packages/runtime-tools-management-console-webapp/src/static/managementConsoleLogo.svg b/packages/runtime-tools-management-console-webapp/src/static/managementConsoleLogo.svg deleted file mode 100644 index eedd5dfda42..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/static/managementConsoleLogo.svg +++ /dev/null @@ -1,262 +0,0 @@ - - - - - - - Management_Console_Logo2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/runtime-tools-management-console-webapp/src/styles.css b/packages/runtime-tools-management-console-webapp/src/styles.css new file mode 100644 index 00000000000..d81a1e4df80 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/styles.css @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +.kie-tools--masthead-hoverable, +.kie-tools--masthead-hoverable > .pf-c-select__toggle { + border-radius: 8px; +} +.kie-tools--masthead-hoverable:hover, +.kie-tools--masthead-hoverable > .pf-c-select__toggle:hover { + background-color: rgb(235, 235, 235); +} + +.kie-tools--masthead-hoverable-dark, +.kie-tools--masthead-hoverable-dark > .pf-c-select__toggle { + color: white; + font-weight: bold; + background-color: var(--pf-c-page__header--BackgroundColor); + border-radius: 8px; +} +.kie-tools--masthead-hoverable-dark .pf-c-select__toggle-arrow { + color: lightgray; +} +.kie-tools--masthead-hoverable-dark:hover, +.kie-tools--masthead-hoverable-dark > .pf-c-select__toggle:hover { + background-color: rgba(255, 255, 255, 0.08); +} + +.kogito-management-console__auth-session-select .pf-c-select__menu { + right: 0; +} + +.kogito-management-console__auth-session-select-disabled { + opacity: 0.6; +} + +.kogito-management-console__card-size { + height: 100%; + position: relative; +} + +.kogito-management-console__full-size { + height: 100%; +} + +.kogito-management-console__task-details-page { + margin-top: 21px; +} + +.kogito-components-common__load-more { + margin-bottom: var(--pf-global--spacer--lg) !important; + text-align: center; +} + +.pf-c-spinner .pf-m-md .kogito-components-common__load-more-spinner { + overflow: hidden; + margin-left: 5px; +} + +.kogito-components-common__form-footer-padding-top { + padding-top: 20px; +} + +.kogito-request-data-editor-container { + border: #d2d2d2 solid 1px; + height: 350px; + padding: 5px; +} +.kogito-consoles-common--aboutModalBox .pf-c-about-modal-box__hero { + background-attachment: unset; +} + +.kogito-consoles-common--PageLayout .pf-c-page__header-brand-link .pf-c-brand { + --pf-c-page__header-brand-link--c-brand--MaxHeight: 42px; +} diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetails.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetails.tsx new file mode 100644 index 00000000000..5c356eddbd9 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetails.tsx @@ -0,0 +1,302 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback, useMemo, useState } from "react"; +import { useHistory } from "react-router-dom"; +import { + Drawer, + DrawerActions, + DrawerCloseButton, + DrawerContent, + DrawerContentBody, + DrawerHead, + DrawerPanelBody, + DrawerPanelContent, +} from "@patternfly/react-core/dist/js/components/Drawer"; +import { Card, CardBody } from "@patternfly/react-core/dist/js/components/Card"; +import { Button } from "@patternfly/react-core/dist/js/components/Button"; +import { Title } from "@patternfly/react-core/dist/js/components/Title"; +import { PageSection } from "@patternfly/react-core/dist/js/components/Page"; +import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye"; +import { Grid, GridItem } from "@patternfly/react-core/dist/js/layouts/Grid"; +import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex"; +import { + TaskInboxGatewayApi, + useTaskInboxGatewayApi, +} from "@kie-tools/runtime-tools-process-webapp-components/dist/TaskInbox"; +import { KogitoSpinner } from "@kie-tools/runtime-tools-components/dist/components/KogitoSpinner"; +import { ServerErrors } from "@kie-tools/runtime-tools-components/dist/components/ServerErrors"; +import { + KogitoEmptyState, + KogitoEmptyStateType, +} from "@kie-tools/runtime-tools-components/dist/components/KogitoEmptyState"; +import { PageTitle } from "@kie-tools/runtime-tools-components/dist/components/PageTitle"; +import { EmbeddedTaskDetails } from "@kie-tools/runtime-tools-process-enveloped-components/dist/taskDetails"; +import { UserTaskInstance } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; +import { TaskState } from "@kie-tools/runtime-tools-process-enveloped-components/dist/taskDetails"; +import { TaskForm } from "./TaskForm"; +import { FormNotification, Notification } from "./components"; +import { useRuntimeDispatch, useRuntimeInfo, useRuntimeSpecificRoutes } from "../runtime/RuntimeContext"; +import { useCancelableEffect } from "@kie-tools-core/react-hooks/dist/useCancelableEffect"; +import { isOpenIdConnectAuthSession, useAuthSessions } from "../authSessions"; +import { Divider } from "@patternfly/react-core/dist/js/components/Divider"; + +interface Props { + taskId?: string; +} + +export const TaskDetails: React.FC = ({ taskId }) => { + const taskInboxGatewayApi: TaskInboxGatewayApi = useTaskInboxGatewayApi(); + const history = useHistory(); + const runtimeRoutes = useRuntimeSpecificRoutes(); + const { username, accessToken } = useRuntimeInfo(); + const { currentAuthSession } = useAuthSessions(); + const { refreshToken } = useRuntimeDispatch(); + const [isLoading, setIsLoading] = useState(true); + const [userTask, setUserTask] = useState(); + const [notification, setNotification] = useState(); + const [error, setError] = useState(); + const [isDetailsExpanded, setIsDetailsExpanded] = useState(false); + + useCancelableEffect( + useCallback( + ({ canceled }) => { + if (!taskId) { + return; + } + setIsLoading(true); + setIsDetailsExpanded(false); + taskInboxGatewayApi + .getTaskById(taskId) + .then((taskData) => { + if (canceled.get()) { + return; + } + setUserTask(taskData); + if (username && !taskData?.potentialUsers?.includes(username)) { + setIsDetailsExpanded(true); + } + }) + .catch((e) => { + setError(e); + setIsDetailsExpanded(true); + }) + .finally(() => { + setIsLoading(false); + }); + }, + [taskId, taskInboxGatewayApi, username] + ) + ); + + const goToTasks = useCallback(() => { + taskInboxGatewayApi.clearOpenTask(); + history.push(runtimeRoutes.tasks()); + }, [history, runtimeRoutes, taskInboxGatewayApi]); + + const showNotification = useCallback( + (notificationType: "error" | "success", submitMessage: string, notificationDetails?: string) => { + setNotification({ + type: notificationType, + message: submitMessage, + details: notificationDetails, + customAction: { + label: "Go to Tasks", + onClick: () => { + setNotification(undefined); + goToTasks(); + }, + }, + close: () => { + setNotification(undefined); + }, + }); + }, + [goToTasks] + ); + + const onSubmitSuccess = useCallback( + (phase: string) => { + const message = `Task '${userTask!.referenceName}' successfully transitioned to phase '${phase}'.`; + + showNotification("success", message); + }, + [showNotification, userTask] + ); + + const onSubmitError = useCallback( + (phase: any, details?: string) => { + const message = `Task '${userTask!.referenceName}' couldn't transition to phase '${phase}'.`; + + showNotification("error", message, details); + }, + [showNotification, userTask] + ); + + const onUnauthorized = useCallback( + async (e: any) => { + if (isOpenIdConnectAuthSession(currentAuthSession)) { + await refreshToken(currentAuthSession); + } else { + throw new Error(`Got unauthorized response for unauthenticated runtime! ${e}`); + } + }, + [currentAuthSession, refreshToken] + ); + + const onViewDetailsClick = useCallback(() => { + setIsDetailsExpanded((prev) => !prev); + }, []); + + const onDetailsCloseClick = useCallback(() => { + setIsDetailsExpanded(false); + }, []); + + const content = useMemo(() => { + if (isLoading) { + return ( + + + + + + + + + + ); + } + + if (error) { + return ( + + + + + + + + + + ); + } + + if (!userTask) { + return ( + + + + + + + + ); + } + + const taskDetailsPanel = ( + + + + + Details + + + + + + + + + + + ); + + return ( + + + + + + + + + + + + + + + + ); + }, [ + accessToken, + error, + goToTasks, + isDetailsExpanded, + isLoading, + onDetailsCloseClick, + onSubmitError, + onSubmitSuccess, + onUnauthorized, + taskId, + userTask, + username, + ]); + + return ( + <> + {userTask && ( + + + } /> + + + + + + )} + {notification && ( +
+ +
+ )} + + {content} + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetailsPage.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetailsPage.tsx new file mode 100644 index 00000000000..0bede2391fb --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetailsPage.tsx @@ -0,0 +1,96 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback, useEffect } from "react"; +import { useHistory } from "react-router-dom"; +import { useRuntimeInfo, useRuntimeSpecificRoutes } from "../runtime/RuntimeContext"; +import { AuthSession, useAuthSessionsDispatch } from "../authSessions"; +import { useEnv } from "../env/hooks/EnvContext"; +import { useRoutes } from "../navigation/Hooks"; +import { TaskDetails } from "./TaskDetails"; +import { useRuntimePageLayoutDispatch } from "../runtime/RuntimePageLayoutContext"; +import { ImpersonationForm } from "./components/ImpersonationForm"; + +interface Props { + taskId?: string; +} + +export const TaskDetailsPage: React.FC = ({ taskId }) => { + const history = useHistory(); + const runtimeRoutes = useRuntimeSpecificRoutes(); + const { runtimeDisplayInfo } = useRuntimeInfo(); + const { env } = useEnv(); + const routes = useRoutes(); + const { setOnSelectAuthSession } = useAuthSessionsDispatch(); + const { setCurrentPageTitle, setBreadcrumbText, setBreadcrumbPath } = useRuntimePageLayoutDispatch(); + + useEffect(() => { + document.title = `${env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME} :: Task :: ${taskId}`; + }, [env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME, taskId]); + + const onNavigateToTaskDetails = useCallback( + (authSession?: AuthSession) => { + if (taskId) { + history.push(runtimeRoutes.taskDetails(taskId, authSession)); + } else { + history.push(runtimeRoutes.tasks(authSession)); + } + }, + [history, taskId, runtimeRoutes] + ); + + useEffect(() => { + setOnSelectAuthSession(() => onNavigateToTaskDetails); + + return () => { + setOnSelectAuthSession(undefined); + }; + }, [history, onNavigateToTaskDetails, setOnSelectAuthSession]); + + useEffect(() => { + setCurrentPageTitle("Task"); + setBreadcrumbText(["Home", runtimeDisplayInfo?.fullDisplayName ?? "Runtime", "Tasks", taskId ?? ""]); + setBreadcrumbPath([ + routes.home.path({}), + runtimeRoutes.processes(), + runtimeRoutes.tasks(), + taskId ? runtimeRoutes.taskDetails(taskId) : runtimeRoutes.tasks(), + ]); + + return () => { + setCurrentPageTitle(""); + setBreadcrumbText([]); + setBreadcrumbPath([]); + }; + }, [ + routes.home, + runtimeDisplayInfo?.fullDisplayName, + runtimeRoutes, + setBreadcrumbPath, + setBreadcrumbText, + setCurrentPageTitle, + taskId, + ]); + + return ( + <> + + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/components/containers/TaskFormContainer/TaskFormContainer.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/TaskForm.tsx similarity index 60% rename from packages/runtime-tools-management-console-webapp/src/components/containers/TaskFormContainer/TaskFormContainer.tsx rename to packages/runtime-tools-management-console-webapp/src/tasks/TaskForm.tsx index 8e74e503305..caa23e0584c 100644 --- a/packages/runtime-tools-management-console-webapp/src/components/containers/TaskFormContainer/TaskFormContainer.tsx +++ b/packages/runtime-tools-management-console-webapp/src/tasks/TaskForm.tsx @@ -16,9 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React from "react"; -import { OUIAProps, componentOuiaProps } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; -import { useKogitoAppContext } from "@kie-tools/runtime-tools-components/dist/contexts/KogitoAppContext"; +import React, { useMemo } from "react"; import { Form } from "@kie-tools/runtime-tools-shared-gateway-api/dist/types"; import { EmbeddedTaskForm } from "@kie-tools/runtime-tools-process-enveloped-components/dist/taskForm"; import { UserTaskInstance } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; @@ -26,39 +24,59 @@ import { useTaskFormGatewayApi } from "@kie-tools/runtime-tools-process-webapp-c interface Props { userTask: UserTaskInstance; - onSubmitSuccess: (message: string) => void; - onSubmitError: (message: string, details?: string) => void; + onSubmitFormSuccess: (message: string) => void; + onSubmitFormError: (message: string, details?: string) => void; + onUnauthorized: (error: any) => void; + accessToken?: string; + username?: string; } -const TaskFormContainer: React.FC = ({ +export const TaskForm: React.FC = ({ userTask, - onSubmitSuccess, - onSubmitError, - ouiaId, - ouiaSafe, + onSubmitFormSuccess, + onSubmitFormError, + onUnauthorized, + accessToken, + username, }) => { const gatewayApi = useTaskFormGatewayApi(); - const kogitoAppContext = useKogitoAppContext(); + const requestHeaders = useMemo( + () => + accessToken + ? { + Authorization: `Bearer ${accessToken}`, + } + : undefined, + [accessToken] + ); return ( { return gatewayApi - .doSubmitAsAnonymous(userTask, phase, payload) - .then((result) => onSubmitSuccess(phase)) - .catch((error) => { + .doSubmit(userTask, phase ?? "", payload, requestHeaders) + .then((result) => onSubmitFormSuccess(phase ?? "")) + .catch(async (error) => { + if (error?.response?.status === 401) { + await onUnauthorized(error); + } const message = error.response ? error.response.data : error.message; - onSubmitError(phase, message); + onSubmitFormError(phase ?? "", message); }); }, getTaskFormSchema(): Promise> { - return gatewayApi.getTaskFormSchemaAsAnonymous(userTask); + return gatewayApi.getTaskFormSchema(userTask, requestHeaders).catch(async (error) => { + if (error?.response?.status === 401) { + await onUnauthorized(error); + } + return error; + }); }, getCustomForm(): Promise
{ + // No-op return gatewayApi.getCustomForm(userTask); }, }} @@ -66,5 +84,3 @@ const TaskFormContainer: React.FC = ({ /> ); }; - -export default TaskFormContainer; diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/Tasks.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/Tasks.tsx new file mode 100644 index 00000000000..cbd512f6ebb --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/tasks/Tasks.tsx @@ -0,0 +1,123 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useEffect, useMemo } from "react"; +import { useHistory } from "react-router-dom"; +import { + TaskInboxGatewayApi, + useTaskInboxGatewayApi, +} from "@kie-tools/runtime-tools-process-webapp-components/dist/TaskInbox"; +import { EmbeddedTaskInbox } from "@kie-tools/runtime-tools-process-enveloped-components/dist/taskInbox"; +import { getActiveTaskStates, getAllTaskStates } from "@kie-tools/runtime-tools-process-webapp-components/dist/utils"; +import { UserTaskInstance } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; +import { + QueryFilter, + TaskInboxState, + SortBy, +} from "@kie-tools/runtime-tools-process-enveloped-components/src/taskInbox"; +import { RuntimePathSearchParamsRoutes, useRuntimeDispatch } from "../runtime/RuntimeContext"; +import { useQueryParam, useQueryParams } from "../navigation/queryParams/QueryParamsContext"; +import { QueryParams } from "../navigation/Routes"; + +interface Props { + onNavigateToTaskDetails: (taskId: string) => void; +} + +const defaultFilter: QueryFilter = { + taskNames: [], + taskStates: getActiveTaskStates(), +}; + +const defaultOrderBy: SortBy = { + property: "lastUpdate", + direction: "desc", +}; + +export const Tasks: React.FC = ({ onNavigateToTaskDetails }) => { + const gatewayApi: TaskInboxGatewayApi = useTaskInboxGatewayApi(); + const history = useHistory(); + const filters = useQueryParam(QueryParams.FILTERS); + const sortBy = useQueryParam(QueryParams.SORT_BY); + const queryParams = useQueryParams(); + const { setRuntimePathSearchParams } = useRuntimeDispatch(); + + const initialState: TaskInboxState = useMemo(() => { + return { + filters: filters ? (JSON.parse(filters) as TaskInboxState["filters"]) : defaultFilter, + sortBy: sortBy ? (JSON.parse(sortBy) as TaskInboxState["sortBy"]) : defaultOrderBy, + currentPage: { + offset: 0, + limit: 10, + }, + }; + }, [filters, sortBy]); + + useEffect(() => { + const newSearchParams = { + [QueryParams.FILTERS]: JSON.stringify(initialState.filters), + [QueryParams.SORT_BY]: JSON.stringify(initialState.sortBy), + }; + setRuntimePathSearchParams((currentRuntimePathSearchParams) => { + return currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASKS, newSearchParams); + }); + }, [initialState, setRuntimePathSearchParams]); + + useEffect(() => { + const unsubscriber = gatewayApi.onUpdateTaskListState({ + onUpdate(taskListState: TaskInboxState) { + const newSearchParams = { + [QueryParams.FILTERS]: JSON.stringify(taskListState.filters), + [QueryParams.ORDER_BY]: JSON.stringify(taskListState.sortBy), + }; + setRuntimePathSearchParams((currentRuntimePathSearchParams) => { + return currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASKS, newSearchParams); + }); + const newQueryParams = queryParams + .with(QueryParams.FILTERS, newSearchParams[QueryParams.FILTERS]) + .with(QueryParams.ORDER_BY, newSearchParams[QueryParams.ORDER_BY]); + history.replace({ pathname: history.location.pathname, search: newQueryParams.toString() }); + }, + }); + + return () => { + unsubscriber.unSubscribe(); + }; + }, [gatewayApi, history, queryParams, setRuntimePathSearchParams]); + + useEffect(() => { + const unsubscriber = gatewayApi.onOpenTaskListen({ + onOpen(task: UserTaskInstance) { + onNavigateToTaskDetails(task.id); + }, + }); + + return () => { + unsubscriber.unSubscribe(); + }; + }, [gatewayApi, onNavigateToTaskDetails]); + + return ( + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/TasksPage.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/TasksPage.tsx new file mode 100644 index 00000000000..494215b8a34 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/tasks/TasksPage.tsx @@ -0,0 +1,85 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback, useEffect } from "react"; +import { Card } from "@patternfly/react-core/dist/js/components/Card"; +import { Tasks } from "./Tasks"; +import { useEnv } from "../env/hooks/EnvContext"; +import { useRuntimeInfo, useRuntimeSpecificRoutes } from "../runtime/RuntimeContext"; +import { useHistory } from "react-router"; +import { useRoutes } from "../navigation/Hooks"; +import { AuthSession, useAuthSessionsDispatch } from "../authSessions"; +import { useRuntimePageLayoutDispatch } from "../runtime/RuntimePageLayoutContext"; +import { ImpersonationForm } from "./components/ImpersonationForm"; + +export const TasksPage: React.FC = (ouiaId, ouiaSafe) => { + const { env } = useEnv(); + const history = useHistory(); + const runtimeRoutes = useRuntimeSpecificRoutes(); + const routes = useRoutes(); + const { runtimeDisplayInfo } = useRuntimeInfo(); + const { setOnSelectAuthSession } = useAuthSessionsDispatch(); + const { setCurrentPageTitle, setBreadcrumbText, setBreadcrumbPath } = useRuntimePageLayoutDispatch(); + + useEffect(() => { + document.title = `${env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME} :: Tasks`; + }, [env.RUNTIME_TOOLS_MANAGEMENT_CONSOLE_APP_NAME]); + + useEffect(() => { + setOnSelectAuthSession(() => (authSession: AuthSession) => { + history.push(runtimeRoutes.tasks(authSession)); + }); + + return () => { + setOnSelectAuthSession(undefined); + }; + }, [history, runtimeRoutes, setOnSelectAuthSession]); + + useEffect(() => { + setCurrentPageTitle("Tasks"); + setBreadcrumbText(["Home", runtimeDisplayInfo?.fullDisplayName ?? "Runtime", "Tasks"]); + setBreadcrumbPath([routes.home.path({}), runtimeRoutes.processes(), runtimeRoutes.tasks()]); + + return () => { + setCurrentPageTitle(""); + setBreadcrumbText([]); + setBreadcrumbPath([]); + }; + }, [ + routes.home, + runtimeDisplayInfo?.fullDisplayName, + runtimeRoutes, + setBreadcrumbPath, + setBreadcrumbText, + setCurrentPageTitle, + ]); + + const onNavigateToTaskDetails = useCallback( + (taskId: string) => { + history.push(runtimeRoutes.taskDetails(taskId)); + }, + [history, runtimeRoutes] + ); + + return ( + + + + + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/components/pages/TaskDetailsPage/components/FormNotification/FormNotification.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/components/FormNotification.tsx similarity index 82% rename from packages/runtime-tools-management-console-webapp/src/components/pages/TaskDetailsPage/components/FormNotification/FormNotification.tsx rename to packages/runtime-tools-management-console-webapp/src/tasks/components/FormNotification.tsx index 1c539b9a460..cec3595b384 100644 --- a/packages/runtime-tools-management-console-webapp/src/components/pages/TaskDetailsPage/components/FormNotification/FormNotification.tsx +++ b/packages/runtime-tools-management-console-webapp/src/tasks/components/FormNotification.tsx @@ -18,7 +18,6 @@ */ import React, { useState } from "react"; import { Alert, AlertActionCloseButton, AlertActionLink } from "@patternfly/react-core/dist/js/components/Alert"; -import { OUIAProps, componentOuiaProps } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; export interface Notification { type: "success" | "error"; @@ -33,20 +32,18 @@ export interface Action { onClick: () => void; } -interface IOwnProps { +interface Props { notification: Notification; } -const FormNotification: React.FC = ({ notification, ouiaId, ouiaSafe }) => { - const variant = notification.type === "error" ? "danger" : "success"; - +export const FormNotification: React.FC = ({ notification }) => { const [showDetails, setShowDetails] = useState(false); return ( {notification.details && ( @@ -60,11 +57,8 @@ const FormNotification: React.FC = ({ notification, ouiaI } actionClose={} - {...componentOuiaProps(ouiaId, "form-notification-alert", ouiaSafe)} > {showDetails && notification.details &&

{notification.details}

}
); }; - -export default FormNotification; diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationForm.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationForm.tsx new file mode 100644 index 00000000000..01798fa84f2 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationForm.tsx @@ -0,0 +1,171 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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, { useCallback, useEffect, useState } from "react"; +import { FormGroup } from "@patternfly/react-core/dist/js/components/Form"; +import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput"; +import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button"; +import { + RuntimePathSearchParamsRoutes, + useRuntime, + useRuntimeDispatch, + useRuntimeInfo, +} from "../../runtime/RuntimeContext"; +import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex"; +import { QueryParams } from "../../navigation/Routes"; +import { useQueryParams } from "../../navigation/queryParams/QueryParamsContext"; +import { useHistory } from "react-router"; + +export const ImpersonationForm: React.FC = () => { + const { impersonationUsername, impersonationGroup } = useRuntime(); + const { canImpersonate } = useRuntimeInfo(); + const queryParams = useQueryParams(); + const history = useHistory(); + const { setImpersonationUsername, setImpersonationGroup, setRuntimePathSearchParams } = useRuntimeDispatch(); + const [username, setUsername] = useState(); + const [group, setGroup] = useState(); + + useEffect(() => { + setUsername(impersonationUsername); + setGroup(impersonationGroup); + }, [impersonationGroup, impersonationUsername]); + + const onClear = useCallback(() => { + setUsername(undefined); + setGroup(undefined); + setImpersonationUsername(undefined); + setImpersonationGroup(undefined); + const newQueryParams = { + [QueryParams.IMPERSONATION_USER]: undefined, + [QueryParams.IMPERSONATION_GROUP]: undefined, + }; + + setRuntimePathSearchParams((currentRuntimePathSearchParams) => { + const tasksNewSearchParams = { + ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASKS), + ...newQueryParams, + }; + const taskDetailsNewSearchParams = { + ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASK_DETAILS), + ...newQueryParams, + }; + currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASKS, tasksNewSearchParams); + currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASK_DETAILS, taskDetailsNewSearchParams); + + return new Map(currentRuntimePathSearchParams); + }); + history.replace({ + pathname: history.location.pathname, + search: queryParams + .with(QueryParams.IMPERSONATION_USER, newQueryParams[QueryParams.IMPERSONATION_USER]) + .with(QueryParams.IMPERSONATION_GROUP, newQueryParams[QueryParams.IMPERSONATION_GROUP]) + .toString(), + }); + }, [history, queryParams, setImpersonationGroup, setImpersonationUsername, setRuntimePathSearchParams]); + + const onApply = useCallback(() => { + setImpersonationUsername(username); + setImpersonationGroup(group); + const newQueryParams = { + [QueryParams.IMPERSONATION_USER]: username, + [QueryParams.IMPERSONATION_GROUP]: group, + }; + + setRuntimePathSearchParams((currentRuntimePathSearchParams) => { + const tasksNewSearchParams = { + ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASKS), + ...newQueryParams, + }; + const taskDetailsNewSearchParams = { + ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASK_DETAILS), + ...newQueryParams, + }; + currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASKS, tasksNewSearchParams); + currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASK_DETAILS, taskDetailsNewSearchParams); + + return new Map(currentRuntimePathSearchParams); + }); + history.replace({ + pathname: history.location.pathname, + search: queryParams + .with(QueryParams.IMPERSONATION_USER, newQueryParams[QueryParams.IMPERSONATION_USER]) + .with(QueryParams.IMPERSONATION_GROUP, newQueryParams[QueryParams.IMPERSONATION_GROUP]) + .toString(), + }); + }, [ + group, + history, + queryParams, + setImpersonationGroup, + setImpersonationUsername, + setRuntimePathSearchParams, + username, + ]); + + useEffect(() => { + if (!canImpersonate) { + onClear(); + } + }, [canImpersonate, onClear]); + + return canImpersonate ? ( + + +
Impersonation:
+
+ + + + + + + + + + + + + + + + + +
+ ) : ( + <> + ); +}; diff --git a/packages/runtime-tools-management-console-webapp/src/components/styles.css b/packages/runtime-tools-management-console-webapp/src/tasks/components/index.ts similarity index 79% rename from packages/runtime-tools-management-console-webapp/src/components/styles.css rename to packages/runtime-tools-management-console-webapp/src/tasks/components/index.ts index 21c64bbe322..fb43cd55938 100644 --- a/packages/runtime-tools-management-console-webapp/src/components/styles.css +++ b/packages/runtime-tools-management-console-webapp/src/tasks/components/index.ts @@ -16,15 +16,4 @@ * specific language governing permissions and limitations * under the License. */ -.kogito-management-console__card-size { - height: 100%; - position: relative; -} - -.kogito-management-console__full-size { - height: 100%; -} - -.kogito-management-console__task-details-page { - margin-top: 21px; -} +export * from "./FormNotification"; diff --git a/packages/runtime-tools-management-console-webapp/src/components/console/index.ts b/packages/runtime-tools-management-console-webapp/src/tasks/index.ts similarity index 73% rename from packages/runtime-tools-management-console-webapp/src/components/console/index.ts rename to packages/runtime-tools-management-console-webapp/src/tasks/index.ts index 0d170461365..0d62d4208f5 100644 --- a/packages/runtime-tools-management-console-webapp/src/components/console/index.ts +++ b/packages/runtime-tools-management-console-webapp/src/tasks/index.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -export { default as ManagementConsole } from "./ManagementConsole/ManagementConsole"; -export { default as ManagementConsoleNav } from "./ManagementConsoleNav/ManagementConsoleNav"; -export { default as ManagementConsoleRoutes } from "./ManagementConsoleRoutes/ManagementConsoleRoutes"; +export * from "./TaskDetailsPage"; +export * from "./TaskForm"; +export * from "./Tasks"; +export * from "./TasksPage"; diff --git a/packages/runtime-tools-management-console-webapp/src/static/env.json b/packages/runtime-tools-management-console-webapp/static/env.json similarity index 100% rename from packages/runtime-tools-management-console-webapp/src/static/env.json rename to packages/runtime-tools-management-console-webapp/static/env.json diff --git a/packages/runtime-tools-management-console-webapp/static/favicon.svg b/packages/runtime-tools-management-console-webapp/static/favicon.svg new file mode 100644 index 00000000000..8806924e382 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/static/favicon.svg @@ -0,0 +1,44 @@ + + + + + + + kie_icon_rgb_fullcolor_default + + + + + + + + + diff --git a/packages/runtime-tools-management-console-webapp/static/images/app_logo_rgb_fullcolor_default.svg b/packages/runtime-tools-management-console-webapp/static/images/app_logo_rgb_fullcolor_default.svg new file mode 100644 index 00000000000..aaee397ebdf --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/static/images/app_logo_rgb_fullcolor_default.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/runtime-tools-management-console-webapp/static/images/app_logo_rgb_fullcolor_reverse.svg b/packages/runtime-tools-management-console-webapp/static/images/app_logo_rgb_fullcolor_reverse.svg new file mode 100644 index 00000000000..0844d45ccf1 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/static/images/app_logo_rgb_fullcolor_reverse.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/runtime-tools-management-console-webapp/src/index.html b/packages/runtime-tools-management-console-webapp/static/index.html similarity index 79% rename from packages/runtime-tools-management-console-webapp/src/index.html rename to packages/runtime-tools-management-console-webapp/static/index.html index 7a053d68c33..45c1f55e75a 100644 --- a/packages/runtime-tools-management-console-webapp/src/index.html +++ b/packages/runtime-tools-management-console-webapp/static/index.html @@ -15,19 +15,20 @@ ~ KIND, either express or implied. See the License for the ~ specific language governing permissions and limitations ~ under the License. - --> +--> + - + - - Kogito - Management Console - + - + + + -
+
diff --git a/packages/runtime-tools-management-console-webapp/resources/form-displayer.html b/packages/runtime-tools-management-console-webapp/static/resources/form-displayer.html similarity index 96% rename from packages/runtime-tools-management-console-webapp/resources/form-displayer.html rename to packages/runtime-tools-management-console-webapp/static/resources/form-displayer.html index cd9a0eddbe7..3d03001a2ab 100644 --- a/packages/runtime-tools-management-console-webapp/resources/form-displayer.html +++ b/packages/runtime-tools-management-console-webapp/static/resources/form-displayer.html @@ -43,6 +43,6 @@ - + diff --git a/packages/runtime-tools-management-console-webapp/tsconfig.json b/packages/runtime-tools-management-console-webapp/tsconfig.json index 8b2ac28d6f9..09268aca3ee 100644 --- a/packages/runtime-tools-management-console-webapp/tsconfig.json +++ b/packages/runtime-tools-management-console-webapp/tsconfig.json @@ -1,12 +1,10 @@ { "extends": "@kie-tools/tsconfig/tsconfig.esm.json", "compilerOptions": { + "esModuleInterop": true, "declaration": false, "declarationMap": false, - "esModuleInterop": true, - "jsx": "react-jsx", - "noImplicitAny": false, - "strictNullChecks": false + "jsx": "react-jsx" }, "preserveSymlinks": true } diff --git a/packages/runtime-tools-management-console-webapp/webpack.config.js b/packages/runtime-tools-management-console-webapp/webpack.config.js index 1fb55b0502d..29f928cbeed 100644 --- a/packages/runtime-tools-management-console-webapp/webpack.config.js +++ b/packages/runtime-tools-management-console-webapp/webpack.config.js @@ -19,55 +19,51 @@ const path = require("path"); const { merge } = require("webpack-merge"); +const { EnvironmentPlugin } = require("webpack"); const common = require("@kie-tools-core/webpack-base/webpack.common.config"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const CopyPlugin = require("copy-webpack-plugin"); -const { env } = require("./env"); +const childProcess = require("child_process"); const { defaultEnvJson } = require("./build/defaultEnvJson"); +const { env } = require("./env"); +const buildEnv = env; + const BG_IMAGES_DIRNAME = "bgimages"; module.exports = async (webpackEnv) => { + const buildInfo = getBuildInfo(); + let lastCommitSha = ""; + try { + lastCommitSha = childProcess.execSync("git rev-parse --short HEAD").toString().trim(); + JSON.stringify(lastCommitSha); + } catch (e) { + lastCommitSha = "unavailable"; + } + return merge(common(webpackEnv), { entry: { - index: path.resolve(__dirname, "src", "index.tsx"), - "resources/form-displayer": "./src/resources/form-displayer.ts", - }, - devServer: { - static: { - directory: "./dist", - }, - host: env.runtimeToolsManagementConsoleWebapp.host, - port: env.runtimeToolsManagementConsoleWebapp.port, - compress: true, - historyApiFallback: true, - hot: true, - client: { - overlay: { - warnings: false, - errors: true, - runtimeErrors: false, - }, - progress: true, - }, - proxy: { - "/svg": { - target: "http://localhost:4000", - secure: false, - changeOrigin: true, - }, - }, + index: "./src/index.tsx", + "resources/form-displayer-envelope": "./src/forms/form-displayer-envelope.ts", }, plugins: [ + new EnvironmentPlugin({ + WEBPACK_REPLACE__commitHash: lastCommitSha, + WEBPACK_REPLACE__buildInfo: buildInfo, + WEBPACK_REPLACE__kogitoVersion: buildEnv.versions.kogito, + }), new HtmlWebpackPlugin({ - template: "./src/index.html", + template: "./static/index.html", inject: false, minify: false, }), new CopyPlugin({ patterns: [ + { from: "./static/resources", to: "./resources" }, + { from: "./static/images", to: "./images" }, + { from: "./static/favicon.svg", to: "./favicon.svg" }, { - from: "./src/static/env.json", + from: "./static/env.json", to: "./env.json", transform: () => JSON.stringify(defaultEnvJson, null, 2), }, @@ -136,5 +132,24 @@ module.exports = async (webpackEnv) => { }, }, ignoreWarnings: [/Failed to parse source map/], + devServer: { + server: "http", + host: buildEnv.runtimeToolsManagementConsoleWebapp.dev.host, + port: buildEnv.runtimeToolsManagementConsoleWebapp.dev.port, + historyApiFallback: true, // FIXME: Tiago --> This is making the router work. + static: [{ directory: path.join(__dirname, "./dist") }, { directory: path.join(__dirname, "./static") }], + compress: true, + client: { + overlay: false, + progress: true, + }, + allowedHosts: "all", + }, }); }; + +function getBuildInfo() { + const buildInfo = buildEnv.runtimeToolsManagementConsoleWebapp.buildInfo; + console.info(`Management Console Webapp :: Build info: ${buildInfo}`); + return buildInfo; +} diff --git a/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/ProcessFormPage/ProcessFormPage.tsx b/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/ProcessFormPage/ProcessFormPage.tsx index ab68c515a7f..65fa280fc83 100644 --- a/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/ProcessFormPage/ProcessFormPage.tsx +++ b/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/ProcessFormPage/ProcessFormPage.tsx @@ -62,7 +62,7 @@ const ProcessFormPage: React.FC = ({ ouiaId, ouiaSafe }) => { details: notificationDetails, customActions: [ { - label: "Go to process list", + label: "Go to Processes", onClick: () => { setNotification(null); goToProcessDefinition(); diff --git a/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx b/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx index 7be81daef6e..0eadc482a88 100644 --- a/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx +++ b/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx @@ -81,6 +81,9 @@ const TaskDetailsPage: React.FC & OUIAProps> = ({ oui try { const task = await taskInboxGatewayApi.getTaskById(taskId); setUserTask(task); + if (appContext.getCurrentUser()?.id && !task?.potentialUsers?.includes(appContext.getCurrentUser()?.id)) { + setIsDetailsExpanded(true); + } } catch (err) { setError(err); } finally { @@ -118,7 +121,7 @@ const TaskDetailsPage: React.FC & OUIAProps> = ({ oui const goToInbox = () => { taskInboxGatewayApi.clearOpenTask(); - props.history.push("/TaskInbox"); + props.history.push("/Tasks"); }; const onSubmitSuccess = (phase: string) => { diff --git a/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskInboxPage/TaskInboxPage.tsx b/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskInboxPage/TaskInboxPage.tsx index 0aa9b2c3de1..ec72a7e095f 100644 --- a/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskInboxPage/TaskInboxPage.tsx +++ b/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskInboxPage/TaskInboxPage.tsx @@ -30,6 +30,7 @@ import { ouiaPageTypeAndObjectId, } from "@kie-tools/runtime-tools-components/dist/ouiaTools"; import { PageTitle } from "@kie-tools/runtime-tools-components/dist/components/PageTitle"; +import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex"; const TaskInboxPage: React.FC = (ouiaId, ouiaSafe) => { const appContext = useDevUIAppContext(); @@ -48,12 +49,10 @@ const TaskInboxPage: React.FC = (ouiaId, ouiaSafe) => { variant="light" {...componentOuiaProps("header" + (ouiaId ? "-" + ouiaId : ""), "tasks-page", ouiaSafe)} > - - - - - {user.length > 0 && } - + + + {user.length > 0 && } + {renderTaskInbox()} diff --git a/packages/runtime-tools-process-dev-ui-webapp/src/components/styles.css b/packages/runtime-tools-process-dev-ui-webapp/src/components/styles.css index fe5bb1b9776..b6fc41c5627 100644 --- a/packages/runtime-tools-process-dev-ui-webapp/src/components/styles.css +++ b/packages/runtime-tools-process-dev-ui-webapp/src/components/styles.css @@ -22,5 +22,5 @@ } .DevUI-switchUser-dropdown-styling { - margin-left: 5em !important; + padding-top: 8px; } diff --git a/packages/runtime-tools-process-enveloped-components/package.json b/packages/runtime-tools-process-enveloped-components/package.json index fe0b96976a6..58db5304395 100644 --- a/packages/runtime-tools-process-enveloped-components/package.json +++ b/packages/runtime-tools-process-enveloped-components/package.json @@ -34,6 +34,7 @@ "@kie-tools-core/notifications": "workspace:*", "@kie-tools-core/operating-system": "workspace:*", "@kie-tools-core/patternfly-base": "workspace:*", + "@kie-tools-core/react-hooks": "workspace:*", "@kie-tools/i18n-common-dictionary": "workspace:*", "@kie-tools/runtime-tools-components": "workspace:*", "@kie-tools/runtime-tools-process-gateway-api": "workspace:*", diff --git a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/api/JobsManagementEnvelopeApi.ts b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/api/JobsManagementEnvelopeApi.ts index 9a7361121da..4d88aa523b6 100644 --- a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/api/JobsManagementEnvelopeApi.ts +++ b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/api/JobsManagementEnvelopeApi.ts @@ -1,3 +1,5 @@ +import { JobsManagementState } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; + /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -17,7 +19,7 @@ * under the License. */ export interface JobsManagementEnvelopeApi { - jobsManagement__init(association: Association): Promise; + jobsManagement__init(association: Association, initArgs: JobsManagementInitArgs): Promise; } export interface Association { origin: string; @@ -28,3 +30,7 @@ export interface QueryPage { offset: number; limit: number; } + +export interface JobsManagementInitArgs { + initialState?: JobsManagementState; +} diff --git a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/embedded/EmbeddedJobsManagement.tsx b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/embedded/EmbeddedJobsManagement.tsx index 83e1368c62c..5518e8b8fde 100644 --- a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/embedded/EmbeddedJobsManagement.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/embedded/EmbeddedJobsManagement.tsx @@ -16,17 +16,19 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useCallback } from "react"; +import React, { useCallback, useMemo } from "react"; import { EnvelopeServer } from "@kie-tools-core/envelope-bus/dist/channel"; import { EmbeddedEnvelopeProps, RefForwardingEmbeddedEnvelope } from "@kie-tools-core/envelope/dist/embedded"; import { ContainerType } from "@kie-tools-core/envelope/dist/api"; import { init } from "../envelope"; import { JobsManagementApi, JobsManagementChannelApi, JobsManagementEnvelopeApi, JobsManagementDriver } from "../api"; import { JobsManagementChannelApiImpl } from "./JobsManagementChannelApiImpl"; +import { JobsManagementState } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; export interface Props { targetOrigin: string; driver: JobsManagementDriver; + initialState?: JobsManagementState; } export const EmbeddedJobsManagement = React.forwardRef((props: Props, forwardedRef: React.Ref) => { @@ -35,11 +37,11 @@ export const EmbeddedJobsManagement = React.forwardRef((props: Props, forwardedR [] ); const pollInit = useCallback( - ( + async ( envelopeServer: EnvelopeServer, container: () => HTMLDivElement ) => { - init({ + await init({ config: { containerType: ContainerType.DIV, envelopeId: envelopeServer.id, @@ -52,18 +54,26 @@ export const EmbeddedJobsManagement = React.forwardRef((props: Props, forwardedR }, }); - return envelopeServer.envelopeApi.requests.jobsManagement__init({ - origin: envelopeServer.origin, - envelopeServerId: envelopeServer.id, - }); + return await envelopeServer.envelopeApi.requests.jobsManagement__init( + { + origin: envelopeServer.origin, + envelopeServerId: envelopeServer.id, + }, + props.initialState + ? { + initialState: props.initialState, + } + : {} + ); }, - [] + [props.initialState] ); + const apiImpl = useMemo(() => new JobsManagementChannelApiImpl(props.driver), [props.driver]); return ( => { + jobsManagement__init = async (association: Association, initArgs: JobsManagementInitArgs): Promise => { this.args.envelopeClient.associate(association.origin, association.envelopeServerId); if (this.hasCapturedInitRequestYet()) { @@ -50,6 +50,6 @@ export class JobsManagementEnvelopeApiImpl implements JobsManagementEnvelopeApi this.ackCapturedInitRequest(); this.view = await this.args.viewDelegate(); - this.view().initialize(); + this.view().initialize(initArgs); }; } diff --git a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/JobsManagementEnvelopeContext.ts b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/JobsManagementEnvelopeContext.ts index 7db7a55936b..19ddbe4b104 100644 --- a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/JobsManagementEnvelopeContext.ts +++ b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/JobsManagementEnvelopeContext.ts @@ -16,10 +16,9 @@ * specific language governing permissions and limitations * under the License. */ - /** * This is a convenience class that the Envelope view can use. - * Since the Jobs View is very simple, it's empty. + * Since the Jobs Management View is very simple, it's empty. */ // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/JobsManagementEnvelopeView.tsx b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/JobsManagementEnvelopeView.tsx index c4620d0b7e6..7c661830a0b 100644 --- a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/JobsManagementEnvelopeView.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/JobsManagementEnvelopeView.tsx @@ -16,28 +16,45 @@ * specific language governing permissions and limitations * under the License. */ -import * as React from "react"; +import React, { useMemo } from "react"; import { useImperativeHandle, useState } from "react"; import { MessageBusClientApi } from "@kie-tools-core/envelope-bus/dist/api"; -import { JobsManagementChannelApi } from "../api"; +import { JobsManagementChannelApi, JobsManagementInitArgs } from "../api"; import JobsManagement from "./components/JobsManagement/JobsManagement"; import JobsManagementEnvelopeViewDriver from "./JobsManagementEnvelopeViewDriver"; import "@patternfly/patternfly/patternfly.css"; +import { JobsManagementState, JobStatus } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; +import { OrderBy } from "@kie-tools/runtime-tools-shared-gateway-api/dist/types"; export interface JobsManagementEnvelopeViewApi { - initialize: () => void; + initialize: (initArgs?: JobsManagementInitArgs) => void; } interface Props { channelApi: MessageBusClientApi; } +const defaultStatus = [JobStatus.Scheduled]; + +const defaultOrderBy = { + lastUpdate: OrderBy.DESC, +}; + export const JobsManagementEnvelopeView = React.forwardRef( (props, forwardedRef) => { + const [jobsManagementInitArgs, setJobsManagementInitArgs] = useState({ + initialState: { + filters: defaultStatus, + orderBy: defaultOrderBy, + } as JobsManagementState, + }); const [isEnvelopeConnectedToChannel, setEnvelopeConnectedToChannel] = useState(false); + const driver = useMemo(() => new JobsManagementEnvelopeViewDriver(props.channelApi), [props.channelApi]); useImperativeHandle( forwardedRef, () => ({ - initialize: () => { + initialize: (initArgs) => { + setEnvelopeConnectedToChannel(false); + setJobsManagementInitArgs(initArgs!); setEnvelopeConnectedToChannel(true); }, }), @@ -45,12 +62,13 @@ export const JobsManagementEnvelopeView = React.forwardRef + <> - + ); } ); diff --git a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/components/JobsManagement/JobsManagement.tsx b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/components/JobsManagement/JobsManagement.tsx index 9bea57e7c5d..4793924717f 100644 --- a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/components/JobsManagement/JobsManagement.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/components/JobsManagement/JobsManagement.tsx @@ -16,9 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { Button } from "@patternfly/react-core/dist/js/components/Button"; -import { CardTitle } from "@patternfly/react-core/dist/js/components/Card"; import { Divider } from "@patternfly/react-core/dist/js/components/Divider"; import { ISortBy } from "@patternfly/react-table/dist/js/components/Table"; import { LoadMore } from "@kie-tools/runtime-tools-components/dist/components/LoadMore"; @@ -28,7 +27,13 @@ import { KogitoEmptyStateType, } from "@kie-tools/runtime-tools-components/dist/components/KogitoEmptyState"; import { componentOuiaProps, OUIAProps } from "@kie-tools/runtime-tools-components/dist/ouiaTools/OuiaUtils"; -import { BulkCancel, Job, JobStatus, JobsSortBy } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; +import { + BulkCancel, + Job, + JobStatus, + JobsManagementState, + JobsSortBy, +} from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; import { BulkListItem, BulkListType, @@ -44,6 +49,7 @@ import { setTitle } from "@kie-tools/runtime-tools-components/dist/utils/Utils"; import { JobsDetailsModal } from "../JobsDetailsModal"; import { JobsRescheduleModal } from "../JobsRescheduleModal"; import { JobsCancelModal } from "../JobsCancelModal"; +import { useCancelableEffect } from "@kie-tools-core/react-hooks/dist/useCancelableEffect"; export const formatForBulkListJob = (jobsList: (Job & { errorMessage?: string })[]): BulkListItem[] => { const formattedItems: BulkListItem[] = []; @@ -62,22 +68,35 @@ export const formatForBulkListJob = (jobsList: (Job & { errorMessage?: string }) interface JobsManagementProps { isEnvelopeConnectedToChannel: boolean; driver: JobsManagementDriver; + initialState?: JobsManagementState; } +const defaultPageSize: number = 10; +const defaultSortBy: ISortBy = { index: 6, direction: "asc" }; + const JobsManagement: React.FC = ({ ouiaId, ouiaSafe, driver, isEnvelopeConnectedToChannel, + initialState, }) => { - const defaultPageSize: number = 10; - const defaultStatus: JobStatus[] = [JobStatus.Scheduled]; - const defaultChip: JobStatus[] = [JobStatus.Scheduled]; - const defaultSortBy: ISortBy = { index: 6, direction: "asc" }; - const defaultOrderBy: JobsSortBy = { - lastUpdate: OrderBy.ASC, - }; - const [chips, setChips] = useState(defaultChip); + const defaultStatus: JobStatus[] = useMemo( + () => (initialState && initialState.filters ? [...initialState.filters] : [JobStatus.Scheduled]), + [initialState] + ); + + const defaultOrderBy: JobsSortBy = useMemo( + () => + initialState && initialState.orderBy + ? initialState.orderBy + : { + lastUpdate: OrderBy.DESC, + }, + [initialState] + ); + + const [chips, setChips] = useState(defaultStatus); const [selectedStatus, setSelectedStatus] = useState(defaultStatus); const [selectedJobInstances, setSelectedJobInstances] = useState([]); const [jobs, setJobs] = useState([]); @@ -105,177 +124,237 @@ const JobsManagement: React.FC = ({ ignoredItems: [], }, }); + const [isInitialLoadDone, setIsInitialLoadDone] = useState(false); - const onRefresh = async (): Promise => { + const doQueryJobs = useCallback( + async (_offset: number, _limit: number) => { + try { + const jobsResponse: Job[] = await driver.query(_offset, _limit); + setLimit(jobsResponse.length); + setJobs((currentJobs) => { + if (_offset > 0 && currentJobs.length > 0) { + const tempData: Job[] = currentJobs.concat(jobsResponse); + return tempData; + } else { + return jobsResponse; + } + }); + } catch (err) { + setError(err); + } + }, + [driver] + ); + + const onRefresh = useCallback(async () => { setIsLoading(true); - await driver.initialLoad(selectedStatus, orderBy); - setSortBy(defaultSortBy); + await driver.applyFilter(selectedStatus); + await driver.sortBy(orderBy); setOffset(0); - doQueryJobs(0, 10); - }; + await doQueryJobs(0, 10); + setIsLoading(false); + }, [doQueryJobs, driver, orderBy, selectedStatus]); - const initLoad = async (): Promise => { - const defaultState: any = { - filters: ["SCHEDULED"], - sortBy: { lastUpdate: "ASC" }, - }; + const onApplyFilter = useCallback(async () => { setIsLoading(true); - await driver.initialLoad(defaultState.filters, defaultState.sortBy); - doQueryJobs(0, 10); - }; - - const doQueryJobs = async (_offset: number, _limit: number): Promise => { - try { - const jobsResponse: Job[] = await driver.query(_offset, _limit); - setIsLoading(false); - setLimit(jobsResponse.length); - if (_offset > 0 && jobs.length > 0) { - setIsLoadingMore(false); - const tempData: Job[] = jobs.concat(jobsResponse); - setJobs(tempData); - } else { - setJobs(jobsResponse); - } - } catch (err) { - setError(err); - } - }; + await driver.applyFilter(selectedStatus); + await driver.sortBy(orderBy); + setChips(selectedStatus); + setOffset(0); + await doQueryJobs(0, 10); + setIsLoading(false); + }, [doQueryJobs, driver, orderBy, selectedStatus]); - React.useEffect(() => { - if (isEnvelopeConnectedToChannel) { - initLoad(); + useEffect(() => { + if (!isEnvelopeConnectedToChannel) { + setIsInitialLoadDone(false); } }, [isEnvelopeConnectedToChannel]); - const handleCancelModalToggle = (): void => { + useCancelableEffect( + useCallback( + ({ canceled }) => { + if (isEnvelopeConnectedToChannel) { + setIsLoading(true); + setSelectedStatus(defaultStatus); + setChips(defaultStatus); + setOrderBy(defaultOrderBy); + if (canceled.get()) { + return; + } + driver + .initialLoad(defaultStatus, defaultOrderBy) + .then(() => { + if (canceled.get()) { + return; + } + return doQueryJobs(0, 10); + }) + .then(() => { + if (canceled.get()) { + return; + } + setIsLoading(false); + setIsInitialLoadDone(true); + }); + } + }, + [defaultOrderBy, defaultStatus, doQueryJobs, driver, isEnvelopeConnectedToChannel] + ) + ); + + const handleCancelModalToggle = useCallback((): void => { setIsCancelModalOpen(!isCancelModalOpen); - }; + }, [isCancelModalOpen]); - const handleCancelModalCloseToggle = (): void => { + const handleCancelModalCloseToggle = useCallback(async () => { setIsCancelModalOpen(!isCancelModalOpen); - doQueryJobs(0, 10); - }; + setIsLoading(true); + await doQueryJobs(0, 10); + setIsLoading(false); + }, [doQueryJobs, isCancelModalOpen]); - const handleDetailsToggle = (): void => { + const handleDetailsToggle = useCallback((): void => { setIsDetailsModalOpen(!isDetailsModalOpen); - }; + }, [isDetailsModalOpen]); - const handleRescheduleToggle = (): void => { + const handleRescheduleToggle = useCallback((): void => { setIsRescheduleModalOpen(!isRescheduleModalOpen); - }; + }, [isRescheduleModalOpen]); - const onGetMoreInstances = async (initVal: number, _pageSize: number): Promise => { - setIsLoadingMore(true); - setOffset(initVal); - setPageSize(_pageSize); - await driver.initialLoad(selectedStatus, orderBy); - doQueryJobs(initVal, _pageSize); - }; + const onGetMoreInstances = useCallback( + async (initVal: number, _pageSize: number): Promise => { + setIsLoadingMore(true); + setOffset(initVal); + setPageSize(_pageSize); + await driver.initialLoad(selectedStatus, orderBy); + await doQueryJobs(initVal, _pageSize); + setIsLoadingMore(false); + }, + [doQueryJobs, driver, orderBy, selectedStatus] + ); - const handleBulkCancel = (cancelResults: BulkCancel, ignoredJobs: Job[]): void => { - setIsActionPerformed(true); - setModalTitle(setTitle("success", "Job Cancel")); - setModalContent(""); - setJobOperationResults({ - ...jobOperationResults, - [OperationType.CANCEL]: { - ...jobOperationResults[OperationType.CANCEL], - successItems: formatForBulkListJob(cancelResults.successJobs), - failedItems: formatForBulkListJob(cancelResults.failedJobs), - ignoredItems: formatForBulkListJob(ignoredJobs), - }, - }); - handleCancelModalToggle(); - }; + const handleBulkCancel = useCallback( + (cancelResults: BulkCancel, ignoredJobs: Job[]): void => { + setIsActionPerformed(true); + setModalTitle(setTitle("success", "Job Cancel")); + setModalContent(""); + setJobOperationResults({ + ...jobOperationResults, + [OperationType.CANCEL]: { + ...jobOperationResults[OperationType.CANCEL], + successItems: formatForBulkListJob(cancelResults.successJobs), + failedItems: formatForBulkListJob(cancelResults.failedJobs), + ignoredItems: formatForBulkListJob(ignoredJobs), + }, + }); + handleCancelModalToggle(); + }, + [handleCancelModalToggle, jobOperationResults] + ); - const jobOperations: IOperations = { - CANCEL: { - type: BulkListType.JOB, - results: jobOperationResults[OperationType.CANCEL], - messages: { - successMessage: "Canceled jobs: ", - noItemsMessage: "No jobs were canceled", - warningMessage: - "Note: The job status has been updated. The list may appear inconsistent until you refresh any applied filters.", - ignoredMessage: "These jobs were ignored because they were already canceled or executed.", - }, - functions: { - perform: async () => { - const ignoredJobs: Job[] = []; - const remainingInstances = selectedJobInstances.filter((job) => { - if (job.status === JobStatus.Canceled || job.status === JobStatus.Executed) { - ignoredJobs.push(job); - } else { - return true; - } - }); - const cancelResults = await driver.bulkCancel(remainingInstances); - handleBulkCancel(cancelResults, ignoredJobs); + const jobOperations: IOperations = useMemo( + () => ({ + CANCEL: { + type: BulkListType.JOB, + results: jobOperationResults[OperationType.CANCEL], + messages: { + successMessage: "Canceled jobs: ", + noItemsMessage: "No jobs were canceled", + warningMessage: + "Note: The job status has been updated. The list may appear inconsistent until you refresh any applied filters.", + ignoredMessage: "These jobs were ignored because they were already canceled or executed.", + }, + functions: { + perform: async () => { + const ignoredJobs: Job[] = []; + const remainingInstances = selectedJobInstances.filter((job) => { + if (job.status === JobStatus.Canceled || job.status === JobStatus.Executed) { + ignoredJobs.push(job); + } else { + return true; + } + }); + const cancelResults = await driver.bulkCancel(remainingInstances); + handleBulkCancel(cancelResults, ignoredJobs); + }, }, }, - }, - }; + }), + [driver, handleBulkCancel, jobOperationResults, selectedJobInstances] + ); - const detailsAction: JSX.Element[] = [ - , - ]; + const detailsAction: JSX.Element[] = useMemo( + () => [ + , + ], + [handleDetailsToggle] + ); - const rescheduleActions: JSX.Element[] = [ - , - ]; + const rescheduleActions: JSX.Element[] = useMemo( + () => [ + , + ], + [handleRescheduleToggle] + ); - const onResetToDefault = (): void => { - setSelectedStatus(defaultStatus); - setChips(defaultChip); - setDisplayTable(true); - initLoad(); - }; + const onResetToDefault = useCallback(async () => { + const defaultState: any = { + filters: ["SCHEDULED"], + orderBy: { lastUpdate: "ASC" }, + }; + setSelectedStatus(defaultState.filters); + setChips(defaultState.filters); + setOrderBy(defaultState.orderBy), setDisplayTable(true); + setIsLoading(true); + await driver.initialLoad(defaultState.filters, defaultState.orderBy); + await doQueryJobs(0, 10); + setIsLoading(false); + }, [doQueryJobs, driver]); - const handleJobReschedule = async ( - job: Job, - repeatInterval: string | number, - repeatLimit: string | number, - scheduleDate: Date - ) => { - const response = await driver.rescheduleJob(job, repeatInterval, repeatLimit, scheduleDate); - if (response && response.modalTitle === "success") { - handleRescheduleToggle(); + const handleJobReschedule = useCallback( + async (job: Job, repeatInterval: string | number, repeatLimit: string | number, scheduleDate: Date) => { + const response = await driver.rescheduleJob(job, repeatInterval, repeatLimit, scheduleDate); setIsLoading(true); - doQueryJobs(0, 10); - } else if (response && response.modalTitle === "failure") { - handleRescheduleToggle(); - setRescheduleError(response.modalContent); - setIsLoading(true); - doQueryJobs(0, 10); - } - }; + if (response && response.modalTitle === "success") { + handleRescheduleToggle(); + await doQueryJobs(0, 10); + } else if (response && response.modalTitle === "failure") { + handleRescheduleToggle(); + setRescheduleError(response.modalContent); + await doQueryJobs(0, 10); + } + setIsLoading(false); + }, + [doQueryJobs, driver, handleRescheduleToggle] + ); + return (
{error.length === 0 ? ( <> - - - + - {isEnvelopeConnectedToChannel && displayTable ? ( + {isInitialLoadDone && displayTable ? ( = ({ )} )} - {isEnvelopeConnectedToChannel && (!isLoading || isLoadingMore) && (limit === pageSize || isLoadingMore) && ( + {isInitialLoadDone && (!isLoading || isLoadingMore) && (limit === pageSize || isLoadingMore) && ( void; setModalContent: (content: string) => void; - setSelectedJobInstances: (selectedJobInstances: Job[]) => void; + setSelectedJobInstances: React.Dispatch>; setSelectedJob: (job?: Job) => void; setSortBy: (sortObj: ISortBy) => void; setOrderBy: (orderBy: JobsSortBy) => void; sortBy: ISortBy; } +const editableJobStatus: string[] = ["SCHEDULED", "ERROR"]; + const JobsManagementTable: React.FC = ({ jobs, driver, @@ -97,28 +99,31 @@ const JobsManagementTable: React.FC = ({ ouiaSafe, }) => { const [rows, setRows] = useState([]); - const jobRow: IRow[] = []; - const editableJobStatus: string[] = ["SCHEDULED", "ERROR"]; - const columns = [ + + const checkNotEmpty = useCallback(() => { + return jobs && jobs.length > 0 && !isLoading; + }, [jobs, isLoading]); + + const [columns, setColumns] = useState>([ { title: "Id" }, { title: "Status" }, { title: "Expiration time" }, { title: "Retries" }, { title: "Execution counter" }, { title: "Last update" }, - ]; - - const checkNotEmpty = useCallback(() => { - return jobs && jobs.length > 0 && !isLoading; - }, [jobs, isLoading]); + ]); - columns.map((column) => { - column["props"] = { className: "pf-u-text-align-center" }; - checkNotEmpty() && column.title !== "Id" ? (column["transforms"] = [sortable]) : ""; - return column; - }); + useEffect(() => { + setColumns((currentColumns) => { + return [...currentColumns].map((column) => { + column["props"] = { className: "pf-u-text-align-center" }; + checkNotEmpty() && column.title !== "Id" ? (column["transforms"] = [sortable]) : ""; + return column; + }); + }); + }, [checkNotEmpty]); - const getValues = (job): RetrievedValueType => { + const getValues = useCallback((job): RetrievedValueType => { const tempRows: RowTitle[] = []; let jobType: string = ""; for (const item in job) { @@ -177,174 +182,206 @@ const JobsManagementTable: React.FC = ({ } } return { tempRows, jobType }; - }; + }, []); - const onSelect = (_event, isSelected, rowId, _rowData): void => { - if (!checkNotEmpty()) { - return; - } - setIsActionPerformed(false); - const copyOfRows = [...rows]; - if (rowId === -1) { - copyOfRows.forEach((row) => { - row.selected = isSelected; - return row; - }); - if (selectedJobInstances.length === jobs.length) { - setSelectedJobInstances([]); - } else if (selectedJobInstances.length < jobs.length) { - /* istanbul ignore else*/ - setSelectedJobInstances(_.cloneDeep(jobs)); + const onSelect = useCallback( + (_event, isSelected, rowId, _rowData): void => { + if (!checkNotEmpty()) { + return; } - } else { - if (copyOfRows[rowId]) { - copyOfRows[rowId].selected = isSelected; - const row = [...jobs].filter((job) => job.id === copyOfRows[rowId].rowKey); - const rowData = _.find(selectedJobInstances, ["id", copyOfRows[rowId].rowKey]); - if (rowData === undefined) { - setSelectedJobInstances([...selectedJobInstances, row[0]]); + setIsActionPerformed(false); + setRows((currentRows) => { + const copyOfRows = [...currentRows]; + if (rowId === -1) { + copyOfRows.forEach((row) => { + row.selected = isSelected; + return row; + }); + setSelectedJobInstances((currentSelectedJobInstances) => { + if (currentSelectedJobInstances.length === jobs.length) { + return []; + } else if (currentSelectedJobInstances.length < jobs.length) { + return _.cloneDeep(jobs); + } + return currentSelectedJobInstances; + }); } else { - const copyOfSelectedJobInstances = [...selectedJobInstances]; - _.remove(copyOfSelectedJobInstances, (job) => job.id === copyOfRows[rowId].rowKey); - setSelectedJobInstances(copyOfSelectedJobInstances); + if (copyOfRows[rowId]) { + copyOfRows[rowId].selected = isSelected; + const row = [...jobs].filter((job) => job.id === copyOfRows[rowId].rowKey); + setSelectedJobInstances((currentSelectedJobInstances) => { + const rowData = _.find(currentSelectedJobInstances, ["id", copyOfRows[rowId].rowKey]); + if (rowData === undefined) { + return [...currentSelectedJobInstances, row[0]]; + } else { + const copyOfSelectedJobInstances = [...currentSelectedJobInstances]; + _.remove(copyOfSelectedJobInstances, (job) => job.id === copyOfRows[rowId].rowKey); + return copyOfSelectedJobInstances; + } + }); + } } - } - } - setRows(copyOfRows); - }; + return copyOfRows; + }); + }, + [checkNotEmpty, jobs, setIsActionPerformed, setSelectedJobInstances] + ); - const tableContent = (jobs): void => { - !isLoading && - !_.isEmpty(jobs) && - jobs.map((job) => { - const retrievedValue = getValues( - _.pick(job, ["id", "status", "expirationTime", "retries", "executionCounter", "lastUpdate"]) - ); - jobRow.push({ - cells: retrievedValue.tempRows, - type: retrievedValue.jobType, - rowKey: job.id, - selected: false, + const tableContent = useCallback( + (jobs): void => { + const jobRow: IRow[] = []; + if (!isLoading && !_.isEmpty(jobs)) { + jobs.map((job) => { + const retrievedValue = getValues( + _.pick(job, ["id", "status", "expirationTime", "retries", "executionCounter", "lastUpdate"]) + ); + jobRow.push({ + cells: retrievedValue.tempRows, + type: retrievedValue.jobType, + rowKey: job.id, + selected: false, + }); }); - }); - if (isLoading) { - const tempRows = [ - { - rowKey: "1", - cells: [ - { - props: { colSpan: 8 }, - title: , - }, - ], - }, - ]; - setRows(tempRows); - } else { - if (jobRow.length === 0) { + } + if (isLoading) { const tempRows = [ { rowKey: "1", cells: [ { props: { colSpan: 8 }, - title: ( - - ), + title: , }, ], }, ]; setRows(tempRows); } else { - setRows((prev) => [...prev, ...jobRow]); + if (jobRow.length === 0) { + const tempRows = [ + { + rowKey: "1", + cells: [ + { + props: { colSpan: 8 }, + title: ( + + ), + }, + ], + }, + ]; + setRows(tempRows); + } else { + setRows((prev) => [...prev, ...jobRow]); + } } - } - }; + }, + [getValues, isLoading] + ); - const handleJobDetails = (id): void => { - const job = jobs.find((job) => job.id === id); - setSelectedJob(job); - handleDetailsToggle(); - }; + const handleJobDetails = useCallback( + (id): void => { + const job = jobs.find((job) => job.id === id); + setSelectedJob(job); + handleDetailsToggle(); + }, + [handleDetailsToggle, jobs, setSelectedJob] + ); - const handleJobReschedule = (id): void => { - const job = jobs.find((job) => job.id === id); - setSelectedJob(job); - handleRescheduleToggle(); - }; + const handleJobReschedule = useCallback( + (id): void => { + const job = jobs.find((job) => job.id === id); + setSelectedJob(job); + handleRescheduleToggle(); + }, + [handleRescheduleToggle, jobs, setSelectedJob] + ); - const handleCancelAction = async (id): Promise => { - const job: any = jobs.find((job) => job.id === id); - const cancelResponse = await driver.cancelJob(job); - const title: JSX.Element = setTitle(cancelResponse.modalTitle, "Job cancel"); - setModalTitle(title); - setModalContent(cancelResponse.modalContent); - handleCancelModalToggle(); - }; + const handleCancelAction = useCallback( + async (id): Promise => { + const job: any = jobs.find((job) => job.id === id); + const cancelResponse = await driver.cancelJob(job); + const title: JSX.Element = setTitle(cancelResponse.modalTitle, "Job cancel"); + setModalTitle(title); + setModalContent(cancelResponse.modalContent); + handleCancelModalToggle(); + }, + [driver, handleCancelModalToggle, jobs, setModalContent, setModalTitle] + ); - const dynamicActions = (rowData) => { - if (rowData.type === "Editable") { + const dynamicActions = useCallback( + (rowData) => { + if (rowData.type === "Editable") { + return [ + { + title: "Reschedule", + onClick: (_event, _rowId, rowData, _extra) => handleJobReschedule(rowData.rowKey), + }, + { + title: "Cancel", + onClick: (_event, _rowId, rowData, _extra) => handleCancelAction(rowData.rowKey), + }, + ]; + } else { + return []; + } + }, + [handleCancelAction, handleJobReschedule] + ); + + const actionResolver = useCallback( + (rowData): ActionsMeta[] => { + if (!checkNotEmpty()) { + return []; + } + const editActions = dynamicActions(rowData); return [ { - title: "Reschedule", - onClick: (_event, _rowId, rowData, _extra) => handleJobReschedule(rowData.rowKey), - }, - { - title: "Cancel", - onClick: (_event, _rowId, rowData, _extra) => handleCancelAction(rowData.rowKey), + title: "Details", + onClick: (event, rowId, rowData, extra) => handleJobDetails(rowData.rowKey), }, + ...editActions, ]; - } else { - return []; - } - }; - - const actionResolver = (rowData): ActionsMeta[] => { - if (!checkNotEmpty()) { - return []; - } - const editActions = dynamicActions(rowData); - return [ - { - title: "Details", - onClick: (event, rowId, rowData, extra) => handleJobDetails(rowData.rowKey), - }, - ...editActions, - ]; - }; + }, + [checkNotEmpty, dynamicActions, handleJobDetails] + ); - const onSort = async (event, index: number, direction: "asc" | "desc"): Promise => { - setSortBy({ index, direction }); - let sortingColumn: string = event.target.innerText; - sortingColumn = _.camelCase(sortingColumn); - const obj: JobsSortBy = {}; - constructObject(obj, sortingColumn, direction.toUpperCase()); - setOrderBy(obj); - await driver.sortBy(obj); - doQueryJobs(0, 10); - }; + const onSort = useCallback( + async (event, index: number, direction: "asc" | "desc"): Promise => { + setSortBy({ index, direction }); + let sortingColumn: string = event.target.innerText; + sortingColumn = _.camelCase(sortingColumn); + const obj: JobsSortBy = {}; + constructObject(obj, sortingColumn, direction.toUpperCase()); + setOrderBy(obj); + await driver.sortBy(obj); + await doQueryJobs(0, 10); + }, + [doQueryJobs, driver, setOrderBy, setSortBy] + ); useEffect(() => { - /* istanbul ignore else*/ if (isActionPerformed) { - const updatedRows = rows.filter((row) => { - row.selected = false; - return row; - }); setSelectedJobInstances([]); - setRows(updatedRows); + setRows((curentRows) => { + const updatedRows = curentRows.filter((row) => { + row.selected = false; + return row; + }); + return updatedRows; + }); } - }, [isActionPerformed]); + }, [isActionPerformed, setSelectedJobInstances]); useEffect(() => { setRows([]); tableContent(jobs); - }, [isLoading, jobs]); + }, [isLoading, jobs, tableContent]); return ( = ({ actionResolver={checkNotEmpty() ? actionResolver : undefined} sortBy={sortBy} onSort={onSort} - aria-label="Jobs table" + aria-label="Jobs management Table" className="kogito-jobs-management__table" {...componentOuiaProps(ouiaId, "jobs-management-table", ouiaSafe)} > diff --git a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/components/JobsManagementToolbar/JobsManagementToolbar.tsx b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/components/JobsManagementToolbar/JobsManagementToolbar.tsx index d9fcf6bb908..082fc6192fe 100644 --- a/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/components/JobsManagementToolbar/JobsManagementToolbar.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/jobsManagement/envelope/components/JobsManagementToolbar/JobsManagementToolbar.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useCallback, useMemo } from "react"; import { DropdownItem, Dropdown, KebabToggle } from "@patternfly/react-core/dist/js/components/Dropdown"; import { Button } from "@patternfly/react-core/dist/js/components/Button"; import { Select, SelectOption, SelectVariant } from "@patternfly/react-core/dist/js/components/Select"; @@ -56,6 +56,7 @@ interface JobsManagementToolbarProps { setChips: (chips: ((chip: JobStatus[]) => JobStatus[]) | JobStatus[]) => void; setDisplayTable: (displayTable: boolean) => void; setIsLoading: (isLoading: boolean) => void; + onApplyFilter: () => void; } const JobsManagementToolbar: React.FC = ({ chips, @@ -71,6 +72,7 @@ const JobsManagementToolbar: React.FC = setIsLoading, setSelectedStatus, setSelectedJobInstances, + onApplyFilter, ouiaId, ouiaSafe, }) => { @@ -86,60 +88,52 @@ const JobsManagementToolbar: React.FC = , ]; - const onStatusToggle = (): void => { - setIsExpanded(!isExpanded); - }; + const onStatusToggle = useCallback((): void => { + setIsExpanded((currentIsExpanded) => !currentIsExpanded); + }, []); - const filterData = async (): Promise => { - await driver.applyFilter(selectedStatus); - doQueryJobs(0, 10); - setChipRemoved(false); - }; - - const onApplyFilter = async (): Promise => { - setChips(selectedStatus); - setIsLoading(true); - filterData(); - }; - - const onDelete = (type: string, id: string): void => { - const chipsCopy = [...chips]; - const tempChips = chipsCopy.filter((item) => item !== id); - setSelectedJobInstances([]); - let selectedStatusCopy = [...selectedStatus]; - setChips(tempChips); - selectedStatusCopy = selectedStatusCopy.filter((item) => item !== id); - setSelectedStatus(selectedStatusCopy); - if (tempChips.length > 0) { - setIsLoading(true); - setChipRemoved(true); - } else { - setDisplayTable(false); - } - }; + const onDelete = useCallback( + (type: string, id: string): void => { + setChips((currentChips) => { + const chipsCopy = [...currentChips]; + const tempChips = chipsCopy.filter((item) => item !== id); + return tempChips; + }); + setSelectedJobInstances([]); + setSelectedStatus((currentSelectedStatus) => { + let selectedStatusCopy = [...currentSelectedStatus]; + selectedStatusCopy = selectedStatusCopy.filter((item) => item !== id); + return selectedStatusCopy; + }); + }, + [setChips, setSelectedJobInstances, setSelectedStatus] + ); - const onSelect = (event, selection: JobStatus): void => { - let selectionText = event.target.id; - selectionText = selectionText.split("pf-random-id-")[1].split("-")[1]; - let selectedStatusCopy = [...selectedStatus]; - if (selectedStatus.includes(selectionText)) { - selectedStatusCopy = selectedStatusCopy.filter((item) => item !== selectionText); - setSelectedStatus(selectedStatusCopy); - } else { - selectedStatusCopy = [...selectedStatusCopy, selectionText]; - setSelectedStatus(selectedStatusCopy); - } - }; + const onSelect = useCallback( + (event, selection: JobStatus): void => { + setSelectedStatus((currentSelectedStatus) => { + let selectionText = event.target.id; + selectionText = selectionText.split("pf-random-id-")[1].split("-")[1]; + const selectedStatusCopy = [...currentSelectedStatus]; + if (currentSelectedStatus.includes(selectionText)) { + return selectedStatusCopy.filter((item) => item !== selectionText); + } else { + return [...selectedStatusCopy, selectionText]; + } + }); + }, + [setSelectedStatus] + ); - const cancelJobsOptionSelect = (): void => { - setIsKebabOpen(!isKebabOpen); - }; + const cancelJobsOptionSelect = useCallback((): void => { + setIsKebabOpen((currentIsKebabOpen) => !currentIsKebabOpen); + }, []); - const cancelJobsKebabToggle = (isOpen): void => { + const cancelJobsKebabToggle = useCallback((isOpen): void => { setIsKebabOpen(isOpen); - }; + }, []); - const dropdownItemsCancelJobsButtons = (): JSX.Element[] => { + const dropdownItemsCancelJobsButtons = useCallback((): JSX.Element[] => { return [ = Cancel selected , ]; - }; + }, [jobOperations, selectedJobInstances.length]); - const cancelJobsOption: JSX.Element = ( - - - - - - - - } - isOpen={isKebabOpen} - isPlain - dropdownItems={dropdownItemsCancelJobsButtons()} - /> - - + const cancelJobsOption: JSX.Element = useMemo( + () => ( + + + + + + + + } + isOpen={isKebabOpen} + isPlain + dropdownItems={dropdownItemsCancelJobsButtons()} + /> + + + ), + [ + cancelJobsKebabToggle, + cancelJobsOptionSelect, + dropdownItemsCancelJobsButtons, + isKebabOpen, + jobOperations, + selectedJobInstances.length, + ] ); useEffect(() => { if (chipRemoved) { - filterData(); + onRefresh(); } - }, [chipRemoved]); + }, [chipRemoved, onRefresh]); return ( = ({ const [repeatLimit, setRepeatLimit] = React.useState(job.repeatLimit); const [errorModalOpen, setErrorModalOpen] = React.useState(false); - const handleIntervalChange = (value: number | string): void => { + const handleIntervalChange = useCallback((value: number | string): void => { setRepeatInterval(value); - }; + }, []); - const handleLimitChange = (value: number | string): void => { + const handleLimitChange = useCallback((value: number | string): void => { setRepeatLimit(value); - }; + }, []); - const handleDateChange = (value: Date): void => { + const handleDateChange = useCallback((value: Date): void => { setScheduleDate(value); - }; + }, []); - const handleTimeNow = (): void => { + const handleTimeNow = useCallback((): void => { setScheduleDate(new Date()); - }; + }, []); - const onApplyReschedule = (): void => { + const onApplyReschedule = useCallback((): void => { handleJobReschedule(job, repeatInterval, repeatLimit, scheduleDate); - }; + }, [handleJobReschedule, job, repeatInterval, repeatLimit, scheduleDate]); - const applyAction: JSX.Element[] = [ - , - ]; - const modalContent = (): JSX.Element => { - return ( - - - - {scheduleDate && scheduleDate !== undefined && ( - - )} - - - - - - - - - - - ); - }; - const handleErrorModal = (): void => { - setErrorModalOpen(!errorModalOpen); - }; + const applyAction: JSX.Element[] = useMemo( + () => [ + , + ], + [onApplyReschedule] + ); + + const handleErrorModal = useCallback((): void => { + setErrorModalOpen((currentErrorModalOpen) => !currentErrorModalOpen); + }, []); const errorModalAction: JSX.Element[] = [ + + + + + + + + + = ({ actions={errorModalAction} {...componentOuiaProps(ouiaId, "job-reschedule-error-modal", ouiaSafe)} > - {errorModalContent()} + ); diff --git a/packages/runtime-tools-process-enveloped-components/src/processList/embedded/EmbeddedProcessList.tsx b/packages/runtime-tools-process-enveloped-components/src/processList/embedded/EmbeddedProcessList.tsx index 6e5f04e87c4..fa78c6c6010 100644 --- a/packages/runtime-tools-process-enveloped-components/src/processList/embedded/EmbeddedProcessList.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/processList/embedded/EmbeddedProcessList.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useCallback } from "react"; +import React, { useCallback, useMemo } from "react"; import { EnvelopeServer } from "@kie-tools-core/envelope-bus/dist/channel"; import { EmbeddedEnvelopeProps, RefForwardingEmbeddedEnvelope } from "@kie-tools-core/envelope/dist/embedded"; import { ProcessListApi, ProcessListChannelApi, ProcessListEnvelopeApi, ProcessListDriver } from "../api"; @@ -39,11 +39,11 @@ export const EmbeddedProcessList = React.forwardRef((props: Props, forwardedRef: [] ); const pollInit = useCallback( - ( + async ( envelopeServer: EnvelopeServer, container: () => HTMLDivElement ) => { - init({ + await init({ config: { containerType: ContainerType.DIV, envelopeId: envelopeServer.id, @@ -51,7 +51,6 @@ export const EmbeddedProcessList = React.forwardRef((props: Props, forwardedRef: container: container(), bus: { postMessage(message, targetOrigin, transfer) { - /* istanbul ignore next */ window.postMessage(message, targetOrigin!, transfer); }, }, @@ -68,13 +67,17 @@ export const EmbeddedProcessList = React.forwardRef((props: Props, forwardedRef: } ); }, - [] + [props.initialState, props.pluralProcessLabel, props.singularProcessLabel] ); + const apiImpl = useMemo(() => { + return new ProcessListChannelApiImpl(props.driver); + }, [props.driver]); + return ( void; + initialize: (initArgs?: ProcessListInitArgs) => void; } interface Props { channelApi: MessageBusClientApi; } +const defaultFilters = { + status: [ProcessInstanceState.Active], + businessKey: [], +}; + +const defaultSortBy = { + lastUpdate: OrderBy.DESC, +}; + export const ProcessListEnvelopeView = React.forwardRef((props, forwardedRef) => { const [isEnvelopeConnectedToChannel, setEnvelopeConnectedToChannel] = useState(false); - const [processInitialState, setProcessInitialState] = useState({} as ProcessListInitArgs); + const [processInitialArgs, setProcessInitialArgs] = useState({ + initialState: { + filters: defaultFilters, + sortBy: defaultSortBy, + } as ProcessListState, + singularProcessLabel: "Process", + pluralProcessLabel: "Processes", + }); useImperativeHandle( forwardedRef, () => ({ - initialize: (initialState) => { + initialize: (initArgs) => { setEnvelopeConnectedToChannel(false); - setProcessInitialState(initialState!); + setProcessInitialArgs(initArgs!); setEnvelopeConnectedToChannel(true); }, }), @@ -51,9 +69,9 @@ export const ProcessListEnvelopeView = React.forwardRef ); diff --git a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessList/ProcessList.tsx b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessList/ProcessList.tsx index 3a3ac433d46..23f98cf83e5 100644 --- a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessList/ProcessList.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessList/ProcessList.tsx @@ -16,14 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState, useMemo } from "react"; import { ProcessListDriver } from "../../../api"; import ProcessListTable from "../ProcessListTable/ProcessListTable"; import ProcessListToolbar from "../ProcessListToolbar/ProcessListToolbar"; import { ISortBy } from "@patternfly/react-table/dist/js/components/Table"; import _ from "lodash"; import { alterOrderByObj, processListDefaultStatusFilter } from "../utils/ProcessListUtils"; - +import { useCancelableEffect } from "@kie-tools-core/react-hooks/dist/useCancelableEffect"; import "../styles.css"; import { ProcessInstance, @@ -57,21 +57,27 @@ const ProcessList: React.FC = ({ ouiaId, ouiaSafe, }) => { - const defaultStatusFilter = processListDefaultStatusFilter; + const defaultFilters: ProcessInstanceFilter = useMemo( + () => + initialState && initialState.filters + ? { ...initialState.filters } + : { + status: processListDefaultStatusFilter, + businessKey: [], + }, + [initialState] + ); + + const defaultOrderBy: any = useMemo( + () => + initialState && initialState.sortBy + ? initialState.sortBy + : { + lastUpdate: OrderBy.DESC, + }, + [initialState] + ); - const defaultFilters: ProcessInstanceFilter = - initialState && initialState.filters - ? { ...initialState.filters } - : { - status: defaultStatusFilter, - businessKey: [], - }; - const defaultOrderBy: any = - initialState && initialState.sortBy - ? initialState.sortBy - : { - lastUpdate: OrderBy.DESC, - }; const [defaultPageSize] = useState(10); const [isLoading, setIsLoading] = useState(false); const [isLoadingMore, setIsLoadingMore] = useState(false); @@ -81,21 +87,100 @@ const ProcessList: React.FC = ({ const [processInstances, setProcessInstances] = useState([]); const [error, setError] = useState(); const [filters, setFilters] = useState(defaultFilters); - const [processStates, setProcessStates] = useState(defaultStatusFilter); + const [processStates, setProcessStates] = useState(processListDefaultStatusFilter); const [expanded, setExpanded] = React.useState<{ [key: number]: boolean }>({}); const [sortBy, setSortBy] = useState(defaultOrderBy); const [selectedInstances, setSelectedInstances] = useState([]); const [selectableInstances, setSelectableInstances] = useState(0); const [isAllChecked, setIsAllChecked] = useState(false); + const [isInitialLoadDone, setIsInitialLoadDone] = useState(false); useEffect(() => { - if (isEnvelopeConnectedToChannel) { - initLoad(); + if (!isEnvelopeConnectedToChannel) { + setIsInitialLoadDone(false); } }, [isEnvelopeConnectedToChannel]); + const countExpandableRows = useCallback( + (instances: ProcessInstance[]): void => { + instances.forEach((processInstance, index) => { + expanded[index] = false; + processInstance.isSelected = false; + processInstance.isOpen = false; + processInstance.childProcessInstances = []; + if (processInstance.serviceUrl && processInstance.addons?.includes("process-management")) { + setSelectableInstances((prev) => prev + 1); + } + }); + }, + [expanded] + ); + + const doQuery = useCallback( + async ( + _offset: number, + _limit: number, + _resetProcesses: boolean, + _resetPagination: boolean = false, + _loadMore: boolean = false + ): Promise => { + setIsLoading(true); + setIsLoadingMore(_loadMore); + setSelectableInstances(0); + setSelectedInstances([]); + setError(undefined); + try { + const response: ProcessInstance[] = await driver.query(_offset, _limit); + setLimit(response.length); + if (_resetProcesses) { + countExpandableRows(response); + setProcessInstances(response); + } else { + setProcessInstances((currentProcessInstances) => { + const newData = currentProcessInstances.concat(response); + countExpandableRows(newData); + return newData; + }); + } + if (_resetPagination) { + setOffset(_offset); + } + } catch (err) { + setError(JSON.parse(JSON.parse(err.message).errorMessage)); + } finally { + setIsLoading(false); + setIsLoadingMore(false); + } + }, + [countExpandableRows, driver] + ); + + useCancelableEffect( + useCallback( + ({ canceled }) => { + if (isEnvelopeConnectedToChannel && !isInitialLoadDone) { + setFilters(defaultFilters); + driver + .initialLoad(defaultFilters, defaultOrderBy) + .then(() => { + if (canceled.get()) { + return; + } + return doQuery(0, 10, true); + }) + .then(() => { + if (canceled.get()) { + return; + } + setIsInitialLoadDone(true); + }); + } + }, + [defaultFilters, defaultOrderBy, doQuery, driver, isEnvelopeConnectedToChannel, isInitialLoadDone] + ) + ); + useEffect(() => { - setIsLoading(true); if (initialState && initialState.filters) { setFilters(initialState.filters); setProcessStates(initialState.filters.status); @@ -103,100 +188,51 @@ const ProcessList: React.FC = ({ } }, [initialState]); - const initLoad = async () => { - setIsLoading(true); - setFilters(defaultFilters); - await driver.initialLoad(defaultFilters, defaultOrderBy); - doQuery(0, 10, true); - }; - - const countExpandableRows = (instances: ProcessInstance[]): void => { - instances.forEach((processInstance, index) => { - expanded[index] = false; - processInstance.isSelected = false; - processInstance.isOpen = false; - processInstance.childProcessInstances = []; - if (processInstance.serviceUrl && processInstance.addons?.includes("process-management")) { - setSelectableInstances((prev) => prev + 1); - } - }); - }; - - const doQuery = async ( - _offset: number, - _limit: number, - _resetProcesses: boolean, - _resetPagination: boolean = false, - _loadMore: boolean = false - ): Promise => { - setIsLoadingMore(_loadMore); - setSelectableInstances(0); - setSelectedInstances([]); - try { - const response: ProcessInstance[] = await driver.query(_offset, _limit); - setLimit(response.length); - if (_resetProcesses) { - countExpandableRows(response); - setProcessInstances(response); - } else { - const newData = processInstances.concat(response); - countExpandableRows(newData); - setProcessInstances(newData); - } - if (_resetPagination) { - setOffset(_offset); - } - } catch (err) { - setError(err.errorMessage); - } finally { - setIsLoading(false); - setIsLoadingMore(false); - } - }; - useEffect(() => { if (selectedInstances.length === selectableInstances && selectableInstances !== 0) { setIsAllChecked(true); } else { setIsAllChecked(false); } - }, [processInstances]); + }, [processInstances, selectableInstances, selectedInstances.length]); - const applyFilter = async (filter: ProcessInstanceFilter): Promise => { - setIsLoading(true); - setProcessInstances([]); - await driver.applyFilter(filter); - doQuery(0, defaultPageSize, true, true); - }; + const applyFilter = useCallback( + async (filter: ProcessInstanceFilter): Promise => { + setProcessInstances([]); + await driver.applyFilter(filter); + await doQuery(0, defaultPageSize, true, true); + }, + [defaultPageSize, doQuery, driver] + ); - const applySorting = async (event, index: number, direction: "asc" | "desc") => { - setIsLoading(true); - setProcessInstances([]); - setSortBy({ index, direction }); - let sortingColumn: string = event.target.innerText; - sortingColumn = _.camelCase(sortingColumn); - let sortByObj = _.set({}, sortingColumn, direction.toUpperCase()); - sortByObj = alterOrderByObj(sortByObj); - await driver.applySorting(sortByObj); - doQuery(0, defaultPageSize, true, true); - }; + const applySorting = useCallback( + async (event, index: number, direction: "asc" | "desc") => { + setProcessInstances([]); + setSortBy({ index, direction }); + let sortingColumn: string = event.target.innerText; + sortingColumn = _.camelCase(sortingColumn); + let sortByObj = _.set({}, sortingColumn, direction.toUpperCase()); + sortByObj = alterOrderByObj(sortByObj); + await driver.applySorting(sortByObj); + await doQuery(0, defaultPageSize, true, true); + }, + [defaultPageSize, doQuery, driver] + ); - const doRefresh = async (): Promise => { - setIsLoading(true); + const doRefresh = useCallback(async (): Promise => { setProcessInstances([]); - doQuery(0, defaultPageSize, true, true); - }; + await doQuery(0, defaultPageSize, true, true); + }, [defaultPageSize, doQuery]); - const doResetFilters = (): void => { + const doResetFilters = useCallback(async () => { const resetFilter = { - status: defaultStatusFilter, + status: processListDefaultStatusFilter, businessKey: [], }; - setIsLoading(true); - setProcessStates(defaultStatusFilter); + setProcessStates(processListDefaultStatusFilter); setFilters(resetFilter); - applyFilter(resetFilter); - }; + await applyFilter(resetFilter); + }, [applyFilter]); const mustShowLoadMore = (!isLoading || isLoadingMore) && processInstances && limit === pageSize && filters.status.length > 0; @@ -221,7 +257,7 @@ const ProcessList: React.FC = ({ isAllChecked={isAllChecked} setIsAllChecked={setIsAllChecked} driver={driver} - defaultStatusFilter={defaultStatusFilter} + defaultStatusFilter={processListDefaultStatusFilter} singularProcessLabel={singularProcessLabel} pluralProcessLabel={pluralProcessLabel} /> diff --git a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListActionsKebab/ProcessListActionsKebab.tsx b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListActionsKebab/ProcessListActionsKebab.tsx index 4add686dfaa..d4f826ee250 100644 --- a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListActionsKebab/ProcessListActionsKebab.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListActionsKebab/ProcessListActionsKebab.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useMemo, useState } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import { Dropdown, DropdownItem, KebabToggle } from "@patternfly/react-core/dist/js/components/Dropdown"; import { checkProcessInstanceState } from "../utils/ProcessListUtils"; import { ProcessInstance, ProcessInstanceState } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; @@ -41,13 +41,13 @@ const ProcessListActionsKebab: React.FC { const [isKebabOpen, setIsKebabOpen] = useState(false); - const onSelect = (): void => { + const onSelect = useCallback((): void => { setIsKebabOpen(!isKebabOpen); - }; + }, [isKebabOpen]); - const onToggle = (isOpen: boolean): void => { + const onToggle = useCallback((isOpen: boolean): void => { setIsKebabOpen(isOpen); - }; + }, []); const dropDownList = useMemo(() => { const result: JSX.Element[] = []; diff --git a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListChildTable/ProcessListChildTable.tsx b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListChildTable/ProcessListChildTable.tsx index a321dc01071..5155e6e0b25 100644 --- a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListChildTable/ProcessListChildTable.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListChildTable/ProcessListChildTable.tsx @@ -18,7 +18,7 @@ */ import { ProcessListDriver } from "../../../api"; import { ICell, IRow, IRowCell, Table, TableBody, TableHeader } from "@patternfly/react-table/dist/js/components/Table"; -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { getProcessInstanceDescription, ProcessInstanceIconCreator } from "../utils/ProcessListUtils"; import { HistoryIcon } from "@patternfly/react-icons/dist/js/icons/history-icon"; import Moment from "react-moment"; @@ -39,6 +39,8 @@ import { } from "@kie-tools/runtime-tools-components/dist/components/KogitoEmptyState"; import _ from "lodash"; +const columnNames: string[] = ["__Select", "Id", "Status", "Created", "Last update", "__Actions"]; + export interface ProcessListChildTableProps { parentProcessId: string; processInstances: ProcessInstance[]; @@ -73,138 +75,146 @@ const ProcessListChildTable: React.FC = const [isLoading, setIsLoading] = useState(false); const [showNoDataEmptyState, setShowNoDataEmptyState] = useState(false); const [error, setError] = useState(); - const columnNames: string[] = ["__Select", "Id", "Status", "Created", "Last update", "__Actions"]; const columns: ICell[] = columnNames.map((it) => ({ title: it.startsWith("__") ? "" : it, })); - const handleClick = (childProcessInstance: ProcessInstance): void => { - driver.openProcess(childProcessInstance); - }; + const handleClick = useCallback( + (childProcessInstance: ProcessInstance): void => { + driver.openProcess(childProcessInstance); + }, + [driver] + ); - const checkBoxSelect = (processInstance: ProcessInstance): void => { - const clonedProcessInstances = [...processInstances]; - clonedProcessInstances.forEach((instance: ProcessInstance) => { - if (instance.id === parentProcessId) { - instance.childProcessInstances?.forEach((childInstance: ProcessInstance) => { - if (childInstance.id === processInstance.id) { - if (childInstance.isSelected) { - childInstance.isSelected = false; - setSelectedInstances( - selectedInstances.filter((selectedInstance) => selectedInstance.id !== childInstance.id) - ); - } else { - childInstance.isSelected = true; - setSelectedInstances([...selectedInstances, childInstance]); + const checkBoxSelect = useCallback( + (processInstance: ProcessInstance): void => { + const clonedProcessInstances = [...processInstances]; + clonedProcessInstances.forEach((instance: ProcessInstance) => { + if (instance.id === parentProcessId) { + instance.childProcessInstances?.forEach((childInstance: ProcessInstance) => { + if (childInstance.id === processInstance.id) { + if (childInstance.isSelected) { + childInstance.isSelected = false; + setSelectedInstances( + selectedInstances.filter((selectedInstance) => selectedInstance.id !== childInstance.id) + ); + } else { + childInstance.isSelected = true; + setSelectedInstances([...selectedInstances, childInstance]); + } } - } - }); - } - }); - setProcessInstances(clonedProcessInstances); - }; + }); + } + }); + setProcessInstances(clonedProcessInstances); + }, + [parentProcessId, processInstances, selectedInstances, setProcessInstances, setSelectedInstances] + ); - const createRows = (childProcessInstances: ProcessInstance[]): void => { - if (!_.isEmpty(childProcessInstances)) { - const tempRows: IRow[] = []; - childProcessInstances.forEach((child: ProcessInstance) => { - const cells: IRowCell[] = [ - { - title: ( - <> - {child.addons?.includes("process-management") && child.serviceUrl !== null ? ( - { - checkBoxSelect(child); - }} - aria-label="process-list-checkbox" - id={`checkbox-${child.id}`} - name={`checkbox-${child.id}`} - data-testid={`checkbox-${child.id}`} - /> + const createRows = useCallback( + (childProcessInstances: ProcessInstance[]): void => { + if (!_.isEmpty(childProcessInstances)) { + const tempRows: IRow[] = []; + childProcessInstances.forEach((child: ProcessInstance) => { + const cells: IRowCell[] = [ + { + title: ( + <> + {child.addons?.includes("process-management") && child.serviceUrl !== null ? ( + { + checkBoxSelect(child); + }} + aria-label="process-list-checkbox" + id={`checkbox-${child.id}`} + name={`checkbox-${child.id}`} + data-testid={`checkbox-${child.id}`} + /> + ) : ( + + } + /> + )} + + ), + }, + { + title: ( + <> + handleClick(child)} + {...componentOuiaProps(ouiaId, "process-description", ouiaSafe)} + > + + + + + + + ), + }, + { + title: + child.state === ProcessInstanceState.Error ? ( + ) : ( - - } - /> - )} - - ), - }, - { - title: ( - <> - handleClick(child)} - {...componentOuiaProps(ouiaId, "process-description", ouiaSafe)} - > - - - - - - - ), - }, - { - title: - child.state === ProcessInstanceState.Error ? ( - + ProcessInstanceIconCreator(child.state) + ), + }, + { + title: child.start ? {new Date(`${child.start}`)} : "", + }, + { + title: child.lastUpdate ? ( + + {" "} + Updated{" "} + {new Date(`${child.lastUpdate}`)} + ) : ( - ProcessInstanceIconCreator(child.state) + "" ), - }, - { - title: child.start ? {new Date(`${child.start}`)} : "", - }, - { - title: child.lastUpdate ? ( - - {" "} - Updated{" "} - {new Date(`${child.lastUpdate}`)} - - ) : ( - "" - ), - }, - { - title: ( - - ), - }, - ]; - cells.forEach((cellInRow, index) => { - cellInRow.props = componentOuiaProps(columnNames[index].toLowerCase(), "process-list-cell", true); - }); - tempRows.push({ - // props are not passed to the actual element (to set OUIA attributes). - // Seems that only solution is to use TableComposable instead. - cells: cells, + }, + { + title: ( + + ), + }, + ]; + cells.forEach((cellInRow, index) => { + cellInRow.props = componentOuiaProps(columnNames[index].toLowerCase(), "process-list-cell", true); + }); + tempRows.push({ + // props are not passed to the actual element (to set OUIA attributes). + // Seems that only solution is to use TableComposable instead. + cells: cells, + }); }); - }); - setRows(tempRows); - setShowNoDataEmptyState(false); - } else { - setShowNoDataEmptyState(true); - } - }; + setRows(tempRows); + setShowNoDataEmptyState(false); + } else { + setShowNoDataEmptyState(true); + } + }, + [checkBoxSelect, handleClick, onAbortClick, onRetryClick, onSkipClick, ouiaId, ouiaSafe] + ); - const getChildProcessInstances = async (): Promise => { + const getChildProcessInstances = useCallback(async (): Promise => { try { setIsLoading(true); const response: ProcessInstance[] = await driver.getChildProcessesQuery(parentProcessId); @@ -225,18 +235,18 @@ const ProcessListChildTable: React.FC = } finally { setIsLoading(false); } - }; + }, [createRows, driver, parentProcessId, processInstances, setSelectableInstances]); useEffect(() => { if (processInstances.length > 0) { const processInstance = processInstances.find((instance: ProcessInstance) => instance.id === parentProcessId); processInstance && createRows(processInstance.childProcessInstances!); } - }, [processInstances]); + }, [createRows, parentProcessId, processInstances]); useEffect(() => { getChildProcessInstances(); - }, []); + }, [getChildProcessInstances]); if (isLoading) { return ; diff --git a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListTable/ProcessListTable.tsx b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListTable/ProcessListTable.tsx index dd440425748..a37ff87ce7c 100644 --- a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListTable/ProcessListTable.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListTable/ProcessListTable.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useEffect, useMemo, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { ExpandableRowContent } from "@patternfly/react-table/dist/js/components/Table"; import { TableComposable, Thead, Tbody, Tr, Th, Td } from "@patternfly/react-table/dist/js/components/TableComposable"; import _ from "lodash"; @@ -55,7 +55,7 @@ export interface ProcessListTableProps { }> >; driver: ProcessListDriver; - onSort: (event: React.SyntheticEvent, index: number, direction: "desc" | "asc") => void; + onSort: (event: React.SyntheticEvent, index: number, direction: "desc" | "asc") => Promise; sortBy: any; setProcessInstances: React.Dispatch>; selectedInstances: ProcessInstance[]; @@ -96,95 +96,135 @@ const ProcessListTable: React.FC = ({ const [isModalOpen, setIsModalOpen] = useState(false); const [selectedProcessInstance, setSelectedProcessInstance] = useState(); - const handleModalToggle = (): void => { - setIsModalOpen(!isModalOpen); - }; - const onShowMessage = (title: string, content: string, type: TitleType, processInstance: ProcessInstance): void => { - setSelectedProcessInstance(processInstance); - setTitleType(type); - setModalTitle(title); - setModalContent(content); - handleModalToggle(); - }; + const handleModalToggle = useCallback((): void => { + setIsModalOpen((currentValue) => !currentValue); + }, []); - const onSkipClick = async (processInstance: ProcessInstance): Promise => { - try { - await driver.handleProcessSkip(processInstance); - onShowMessage( - "Skip operation", - `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} was successfully skipped.`, - TitleType.SUCCESS, - processInstance - ); - } catch (error) { - onShowMessage( - "Skip operation", - `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} failed to skip. Message: ${ - error.message - }`, - TitleType.FAILURE, - processInstance - ); - } finally { + const onShowMessage = useCallback( + (title: string, content: string, type: TitleType, processInstance: ProcessInstance): void => { + setSelectedProcessInstance(processInstance); + setTitleType(type); + setModalTitle(title); + setModalContent(content); handleModalToggle(); - } - }; + }, + [handleModalToggle] + ); - const onRetryClick = async (processInstance: ProcessInstance): Promise => { - try { - await driver.handleProcessRetry(processInstance); - onShowMessage( - "Retry operation", - `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} was successfully re-executed.`, - TitleType.SUCCESS, - processInstance - ); - } catch (error) { - onShowMessage( - "Retry operation", - `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} failed to re-execute. Message: ${ - error.message - }`, - TitleType.FAILURE, - processInstance - ); - } finally { - handleModalToggle(); - } - }; + const onSkipClick = useCallback( + async (processInstance: ProcessInstance): Promise => { + try { + await driver.handleProcessSkip(processInstance); + onShowMessage( + "Skip operation", + `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} was successfully skipped.`, + TitleType.SUCCESS, + processInstance + ); + } catch (error) { + onShowMessage( + "Skip operation", + `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} failed to skip. Message: ${ + error.message + }`, + TitleType.FAILURE, + processInstance + ); + } finally { + handleModalToggle(); + } + }, + [driver, handleModalToggle, onShowMessage, singularProcessLabel] + ); - const onAbortClick = async (processInstance: ProcessInstance): Promise => { - try { - await driver.handleProcessAbort(processInstance); - onShowMessage( - "Abort operation", - `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} was successfully aborted.`, - TitleType.SUCCESS, - processInstance - ); - processInstances.forEach((instance) => { - if (instance.id === processInstance.id) { - instance.state = ProcessInstanceState.Aborted; - } - }); - setProcessInstances([...processInstances]); - } catch (error) { - onShowMessage( - "Abort operation", - `Failed to abort ${singularProcessLabel?.toLowerCase()} ${processInstance.processName}. Message: ${ - error.message - }`, - TitleType.FAILURE, - processInstance - ); - } finally { - handleModalToggle(); - } - }; + const onRetryClick = useCallback( + async (processInstance: ProcessInstance): Promise => { + try { + await driver.handleProcessRetry(processInstance); + onShowMessage( + "Retry operation", + `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} was successfully re-executed.`, + TitleType.SUCCESS, + processInstance + ); + } catch (error) { + onShowMessage( + "Retry operation", + `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} failed to re-execute. Message: ${ + error.message + }`, + TitleType.FAILURE, + processInstance + ); + } finally { + handleModalToggle(); + } + }, + [driver, handleModalToggle, onShowMessage, singularProcessLabel] + ); - const handleClick = (processInstance: ProcessInstance): void => { - driver.openProcess(processInstance); - }; + const onAbortClick = useCallback( + async (processInstance: ProcessInstance): Promise => { + try { + await driver.handleProcessAbort(processInstance); + onShowMessage( + "Abort operation", + `The ${singularProcessLabel?.toLowerCase()} ${processInstance.processName} was successfully aborted.`, + TitleType.SUCCESS, + processInstance + ); + setProcessInstances((currentProcessInstances) => { + currentProcessInstances.forEach((instance) => { + if (instance.id === processInstance.id) { + instance.state = ProcessInstanceState.Aborted; + } + }); + + return [...currentProcessInstances]; + }); + } catch (error) { + onShowMessage( + "Abort operation", + `Failed to abort ${singularProcessLabel?.toLowerCase()} ${processInstance.processName}. Message: ${ + error.message + }`, + TitleType.FAILURE, + processInstance + ); + } finally { + handleModalToggle(); + } + }, + [driver, handleModalToggle, onShowMessage, setProcessInstances, singularProcessLabel] + ); + + const handleClick = useCallback( + (processInstance: ProcessInstance): void => { + driver.openProcess(processInstance); + }, + [driver] + ); + + const checkBoxSelect = useCallback( + (processInstance: ProcessInstance): void => { + setProcessInstances((currentProcessInstances) => { + const clonedProcessInstances = [...currentProcessInstances]; + clonedProcessInstances.forEach((instance: ProcessInstance) => { + if (processInstance.id === instance.id) { + if (instance.isSelected) { + instance.isSelected = false; + setSelectedInstances(selectedInstances.filter((selectedInstance) => selectedInstance.id !== instance.id)); + } else { + instance.isSelected = true; + setSelectedInstances([...selectedInstances, instance]); + } + } + }); + return clonedProcessInstances; + }); + }, + [selectedInstances, setProcessInstances, setSelectedInstances] + ); useEffect(() => { if (!_.isEmpty(processInstances)) { @@ -262,7 +302,7 @@ const ProcessListTable: React.FC = ({ } else { setRowPairs([]); } - }, [processInstances]); + }, [checkBoxSelect, handleClick, onAbortClick, onRetryClick, onSkipClick, ouiaId, ouiaSafe, processInstances]); const loadChild = (parentId: string, parentIndex: number): JSX.Element | null => { if (!expanded[parentIndex]) { @@ -288,22 +328,6 @@ const ProcessListTable: React.FC = ({ } }; - const checkBoxSelect = (processInstance: ProcessInstance): void => { - const clonedProcessInstances = [...processInstances]; - clonedProcessInstances.forEach((instance: ProcessInstance) => { - if (processInstance.id === instance.id) { - if (instance.isSelected) { - instance.isSelected = false; - setSelectedInstances(selectedInstances.filter((selectedInstance) => selectedInstance.id !== instance.id)); - } else { - instance.isSelected = true; - setSelectedInstances([...selectedInstances, instance]); - } - } - }); - setProcessInstances(clonedProcessInstances); - }; - const onToggle = (pairIndex: number, pair: any): void => { setExpanded({ ...expanded, diff --git a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListToolbar/ProcessListToolbar.tsx b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListToolbar/ProcessListToolbar.tsx index 661373bb969..b771a044e6b 100644 --- a/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListToolbar/ProcessListToolbar.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/processList/envelope/components/ProcessListToolbar/ProcessListToolbar.tsx @@ -79,8 +79,8 @@ enum BulkSelectionType { interface ProcessListToolbarProps { filters: ProcessInstanceFilter; setFilters: React.Dispatch>; - applyFilter: (filter: ProcessInstanceFilter) => void; - refresh: () => void; + applyFilter: (filter: ProcessInstanceFilter) => Promise; + refresh: () => Promise; processStates: ProcessInstanceState[]; setProcessStates: React.Dispatch>; selectedInstances: ProcessInstance[]; @@ -296,7 +296,7 @@ const ProcessListToolbar: React.FC = ({ } }; - const onDeleteChip = (categoryName: Category, value: string): void => { + const onDeleteChip = async (categoryName: Category, value: string) => { const clonedProcessStates = [...processStates]; const clonedBusinessKeyArray = [...(filters.businessKey ?? [])]; switch (categoryName) { @@ -314,13 +314,13 @@ const ProcessListToolbar: React.FC = ({ setFilters({ ...filters, businessKey: clonedBusinessKeyArray }); break; } - applyFilter({ + await applyFilter({ status: clonedProcessStates, businessKey: clonedBusinessKeyArray, }); }; - const onApplyFilter = (): void => { + const onApplyFilter = async () => { setBusinessKeyInput(""); const clonedBusinessKeyArray = [...(filters.businessKey ?? [])]; if (businessKeyInput && !clonedBusinessKeyArray.includes(businessKeyInput)) { @@ -331,16 +331,15 @@ const ProcessListToolbar: React.FC = ({ status: processStates, businessKey: clonedBusinessKeyArray, }); - applyFilter({ + await applyFilter({ status: processStates, businessKey: clonedBusinessKeyArray, }); }; - const onEnterClicked = (event: React.KeyboardEvent): void => { - /* istanbul ignore else */ + const onEnterClicked = async (event: React.KeyboardEvent) => { if (event.key === "Enter") { - businessKeyInput.length > 0 && onApplyFilter(); + businessKeyInput.length > 0 && (await onApplyFilter()); } }; diff --git a/packages/runtime-tools-process-enveloped-components/src/taskForm/embedded/EmbeddedTaskForm.tsx b/packages/runtime-tools-process-enveloped-components/src/taskForm/embedded/EmbeddedTaskForm.tsx index dc9ffb1c21f..a2526f80096 100644 --- a/packages/runtime-tools-process-enveloped-components/src/taskForm/embedded/EmbeddedTaskForm.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/taskForm/embedded/EmbeddedTaskForm.tsx @@ -61,7 +61,7 @@ export const EmbeddedTaskForm = React.forwardRef( { userTask: props.userTask, user: props.user } ); }, - [] + [props.targetOrigin, props.user, props.userTask] ); return ( diff --git a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/TaskFormEnvelopeView.tsx b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/TaskFormEnvelopeView.tsx index a3eaac4562c..f5bf7553e23 100644 --- a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/TaskFormEnvelopeView.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/TaskFormEnvelopeView.tsx @@ -33,6 +33,7 @@ import { KogitoEmptyState, KogitoEmptyStateType, } from "@kie-tools/runtime-tools-components/dist/components/KogitoEmptyState"; +import { useCancelableEffect } from "@kie-tools-core/react-hooks/dist/useCancelableEffect"; export interface TaskFormEnvelopeViewApi { initialize: (initArgs: TaskFormInitArgs) => void; @@ -66,41 +67,46 @@ export const TaskFormEnvelopeView = React.forwardRef { - if (isEnvelopeConnectedToChannel) { - loadForm(); - } - }, [isEnvelopeConnectedToChannel]); - - const loadForm = useCallback(async () => { - if (!isEnvelopeConnectedToChannel) { - setIsLoading(true); - } + useCancelableEffect( + useCallback( + ({ canceled }) => { + if (!isEnvelopeConnectedToChannel) { + setIsLoading(true); + } else { + const customFormPromise: Promise = new Promise((resolve) => { + driver + .getCustomForm() + .then((customForm) => { + if (canceled.get()) { + return; + } + setCustomForm(customForm); + resolve(); + }) + .catch((error) => resolve()); + }); - const customFormPromise: Promise = new Promise((resolve) => { - driver - .getCustomForm() - .then((customForm) => { - setCustomForm(customForm); - resolve(); - }) - .catch((error) => resolve()); - }); + const schemaPromise: Promise = new Promise((resolve) => { + driver + .getTaskFormSchema() + .then((schema) => { + if (canceled.get()) { + return; + } + setTaskFormSchema(schema); + resolve(); + }) + .catch((error) => resolve()); + }); - const schemaPromise: Promise = new Promise((resolve) => { - driver - .getTaskFormSchema() - .then((schema) => { - setTaskFormSchema(schema); - resolve(); - }) - .catch((error) => resolve()); - }); - - Promise.all([customFormPromise, schemaPromise]).then((values) => { - setIsLoading(false); - }); - }, [isEnvelopeConnectedToChannel]); + Promise.all([customFormPromise, schemaPromise]).then((values) => { + setIsLoading(false); + }); + } + }, + [driver, isEnvelopeConnectedToChannel] + ) + ); if (isLoading) { return ( diff --git a/packages/runtime-tools-process-enveloped-components/src/taskInbox/api/TaskInboxChannelApi.ts b/packages/runtime-tools-process-enveloped-components/src/taskInbox/api/TaskInboxChannelApi.ts index 39ac71eec06..075ccc341fa 100644 --- a/packages/runtime-tools-process-enveloped-components/src/taskInbox/api/TaskInboxChannelApi.ts +++ b/packages/runtime-tools-process-enveloped-components/src/taskInbox/api/TaskInboxChannelApi.ts @@ -20,7 +20,7 @@ import { UserTaskInstance } from "@kie-tools/runtime-tools-process-gateway-api/d import { QueryFilter, SortBy, TaskInboxState } from "./TaskInboxEnvelopeApi"; /** - * Channel Api for Tasks + * Channel Api for Task Inbox */ export interface TaskInboxChannelApi { /** diff --git a/packages/runtime-tools-process-enveloped-components/src/taskInbox/embedded/EmbeddedTaskInbox.tsx b/packages/runtime-tools-process-enveloped-components/src/taskInbox/embedded/EmbeddedTaskInbox.tsx index 0e2bfd4dad4..9e4ef4924a4 100644 --- a/packages/runtime-tools-process-enveloped-components/src/taskInbox/embedded/EmbeddedTaskInbox.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/taskInbox/embedded/EmbeddedTaskInbox.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useCallback } from "react"; +import React, { useCallback, useMemo } from "react"; import { EnvelopeServer } from "@kie-tools-core/envelope-bus/dist/channel"; import { EmbeddedEnvelopeProps, RefForwardingEmbeddedEnvelope } from "@kie-tools-core/envelope/dist/embedded"; import { TaskInboxApi, TaskInboxChannelApi, TaskInboxEnvelopeApi, TaskInboxDriver, TaskInboxState } from "../api"; @@ -40,8 +40,11 @@ export const EmbeddedTaskInbox = React.forwardRef((props: Props, forwardedRef: R [] ); const pollInit = useCallback( - (envelopeServer: EnvelopeServer, container: () => HTMLDivElement) => { - init({ + async ( + envelopeServer: EnvelopeServer, + container: () => HTMLDivElement + ) => { + await init({ config: { containerType: ContainerType.DIV, envelopeId: envelopeServer.id, @@ -53,7 +56,7 @@ export const EmbeddedTaskInbox = React.forwardRef((props: Props, forwardedRef: R }, }, }); - return envelopeServer.envelopeApi.requests.taskInbox__init( + return await envelopeServer.envelopeApi.requests.taskInbox__init( { origin: envelopeServer.origin, envelopeServerId: envelopeServer.id, @@ -65,13 +68,15 @@ export const EmbeddedTaskInbox = React.forwardRef((props: Props, forwardedRef: R } ); }, - [props.allTaskStates, props.activeTaskStates] + [props.initialState, props.allTaskStates, props.activeTaskStates] ); + const apiImpl = useMemo(() => new TaskInboxChannelApiImpl(props.driver), [props.driver]); + return ( new TaskInboxEnvelopeViewDriver(props.channelApi), [props.channelApi]); + return ( = ({ const [offset, setOffset] = useState(0); const [error, setError] = useState(undefined); const [showEmptyFiltersError, setShowEmptyFiltersError] = useState(false); - const [tasks, setTasks] = useState([]); - const [columns] = useState([ - getTaskDescriptionColumn((task: UserTaskInstance): void => driver.openTask(task)), - getDefaultColumn("processId", "Process", true), - getDefaultColumn("priority", "Priority", true), - getTaskStateColumn(), - getDateColumn("started", "Started"), - getDateColumn("lastUpdate", "Last update"), - ]); + const columns: DataTableColumn[] = useMemo( + () => [ + getTaskDescriptionColumn((task: UserTaskInstance): void => driver.openTask(task)), + getDefaultColumn("processId", "Process", true), + getDefaultColumn("priority", "Priority", true), + getTaskStateColumn(), + getDateColumn("started", "Started"), + getDateColumn("lastUpdate", "Last update"), + ], + [driver] + ); - const getTableSortBy = () => { + const getTableSortBy = useCallback(() => { return { index: columns.findIndex((column) => column.path === sortBy.property), direction: sortBy.direction, }; - }; + }, [columns, sortBy.direction, sortBy.property]); - const initDefault = async () => { - const defaultState: TaskInboxState = { - filters: { - taskStates: [...(activeTaskStates ?? [])], - taskNames: [], - }, - sortBy, - currentPage: { offset: 0, limit: 10 }, - }; - await driver.setInitialState(defaultState); - setQueryFilter(defaultState.filters); - setIsLoading(true); - setSortBy(defaultState.sortBy); - doQueryTasks(0, pageSize, true); - }; + const doQueryTasks = useCallback( + async ( + _offset: number, + _limit: number, + _resetTasks: boolean, + _resetPagination: boolean = false, + _loadMore: boolean = false + ) => { + setIsLoadingMore(_loadMore); + setIsLoading(true); + setError(null); - const initWithState = async (initialState: TaskInboxState) => { - setQueryFilter(initialState.filters); - setSortBy(initialState.sortBy); - setOffset(initialState.currentPage.offset); + try { + const response: UserTaskInstance[] = await driver.query(_offset, _limit); + if (_resetTasks) { + setTasks(response); + } else { + setTasks((currentTasks) => currentTasks.concat(response)); + } - setIsLoading(true); + if (_resetPagination) { + setOffset(_offset); + } + } catch (err) { + setError(err); + } finally { + setIsLoading(false); + setIsLoadingMore(false); + } + }, + [driver] + ); - const limit = initialState.currentPage.offset + pageSize; + const initDefault = useCallback( + (canceled: Holder) => { + const defaultState: TaskInboxState = { + filters: { + taskStates: [...(activeTaskStates ?? [])], + taskNames: [], + }, + sortBy, + currentPage: { offset: 0, limit: 10 }, + }; + return driver + .setInitialState(defaultState) + .then(() => { + if (canceled.get()) { + return; + } + setQueryFilter(defaultState.filters); + setSortBy(defaultState.sortBy); + return doQueryTasks(0, pageSize, true); + }) + .then(() => { + if (canceled.get()) { + return; + } + setIsLoading(false); + }); + }, + [activeTaskStates, doQueryTasks, driver, pageSize, sortBy] + ); - doQueryTasks(0, limit, true); - }; + const initWithState = useCallback( + (canceled: Holder, initialState: TaskInboxState) => { + setQueryFilter(initialState.filters); + setSortBy(initialState.sortBy); + setOffset(initialState.currentPage.offset); - const doQueryTasks = async ( - _offset: number, - _limit: number, - _resetTasks: boolean, - _resetPagination: boolean = false, - _loadMore: boolean = false - ) => { - setIsLoadingMore(_loadMore); - setError(null); + const limit = initialState.currentPage.offset + pageSize; - try { - const response: UserTaskInstance[] = await driver.query(_offset, _limit); - if (_resetTasks) { - setTasks(response); - } else { - setTasks(tasks.concat(response)); - } + return driver + .setInitialState(initialState) + .then(() => { + if (canceled.get()) { + return; + } + return doQueryTasks(0, limit, true); + }) + .then(() => { + if (canceled.get()) { + return; + } + setIsLoading(false); + }); + }, + [doQueryTasks, driver, pageSize] + ); - if (_resetPagination) { - setOffset(_offset); + const doApplyFilter = useCallback( + async (filter: QueryFilter) => { + setQueryFilter(filter); + if (!filter || (_.isEmpty(filter.taskStates) && _.isEmpty(filter.taskNames))) { + setShowEmptyFiltersError(true); + return; } - } catch (err) { - setError(err); - } finally { - setIsLoading(false); - setIsLoadingMore(false); - } - }; - - const doApplyFilter = async (filter: QueryFilter) => { - setQueryFilter(filter); - if (!filter || (_.isEmpty(filter.taskStates) && _.isEmpty(filter.taskNames))) { - setShowEmptyFiltersError(true); - return; - } - setShowEmptyFiltersError(false); - setIsLoading(true); - await driver.applyFilter(filter); - doQueryTasks(0, pageSize, true, true); - }; + setShowEmptyFiltersError(false); + setIsLoading(true); + await driver.applyFilter(filter); + doQueryTasks(0, pageSize, true, true); + }, + [doQueryTasks, driver, pageSize] + ); - const doRefresh = async () => { + const doRefresh = useCallback(async () => { setIsLoading(true); doQueryTasks(0, pageSize, true, true); - }; + }, [doQueryTasks, pageSize]); - const onSort = async (index: number, direction: SortByDirection) => { - const sortObj: SortBy = { - property: columns[index].path, - direction: direction.toLowerCase() as SortByDirection, - }; - await driver.applySorting(sortObj); - setSortBy(sortObj); - setIsLoading(true); - await doQueryTasks(0, pageSize, true, true); - }; - - useEffect(() => { - if (!isEnvelopeConnectedToChannel) { + const onSort = useCallback( + async (index: number, direction: SortByDirection) => { + const sortObj: SortBy = { + property: columns[index].path, + direction: direction.toLowerCase() as SortByDirection, + }; + await driver.applySorting(sortObj); + setSortBy(sortObj); setIsLoading(true); - return; - } - setAllStates(allTaskStates ?? []); - setActiveStates(activeTaskStates ?? []); - if (!initialState) { - initDefault(); - } else { - initWithState(initialState); - } - }, [isEnvelopeConnectedToChannel]); + await doQueryTasks(0, pageSize, true, true); + }, + [columns, doQueryTasks, driver, pageSize] + ); - useEffect(() => { - if (isEnvelopeConnectedToChannel && currentUser && currentUser.length > 0) { - initDefault(); - } - }, [isEnvelopeConnectedToChannel, currentUser]); + useCancelableEffect( + useCallback( + ({ canceled }) => { + if (isEnvelopeConnectedToChannel && currentUser && currentUser.length > 0) { + initDefault(canceled); + } + }, + [currentUser, initDefault, isEnvelopeConnectedToChannel] + ) + ); - if (error) { - return ; - } + useCancelableEffect( + useCallback( + ({ canceled }) => { + if (!isEnvelopeConnectedToChannel) { + setIsLoading(true); + return; + } else { + setAllStates(allTaskStates ?? []); + setActiveStates(activeTaskStates ?? []); + if (!initialState) { + initDefault(canceled); + } else { + initWithState(canceled, initialState); + } + } + }, + [activeTaskStates, allTaskStates, initDefault, initWithState, initialState, isEnvelopeConnectedToChannel] + ) + ); - const mustShowMore = (): boolean => { + const mustShowMore = useCallback((): boolean => { if (!isLoadingMore) { const limit = offset * pageSize + pageSize; return !isLoading && limit === tasks.length; } return true; - }; + }, [isLoading, isLoadingMore, offset, pageSize, tasks.length]); + + if (error) { + return ; + } return (
diff --git a/packages/runtime-tools-process-enveloped-components/src/taskInbox/envelope/components/TaskInboxToolbar/TaskInboxToolbar.tsx b/packages/runtime-tools-process-enveloped-components/src/taskInbox/envelope/components/TaskInboxToolbar/TaskInboxToolbar.tsx index 55cf641caa5..cdad8d3a515 100644 --- a/packages/runtime-tools-process-enveloped-components/src/taskInbox/envelope/components/TaskInboxToolbar/TaskInboxToolbar.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/taskInbox/envelope/components/TaskInboxToolbar/TaskInboxToolbar.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { ToolbarFilter, ToolbarGroup, @@ -47,7 +47,7 @@ interface TaskInboxToolbarProps { activeFilter: QueryFilter; allTaskStates: string[]; activeTaskStates: string[]; - applyFilter: (filter: QueryFilter) => void; + applyFilter: (filter: QueryFilter) => Promise; refresh: () => void; } @@ -84,61 +84,64 @@ const TaskInboxToolbar: React.FC = ({ setSelectedTaskStates(activeFilter.taskStates); setFilterTaskStates(activeFilter.taskStates); setFilterTaskNames(activeFilter.taskNames); - }, [activeFilter]); + }, [activeFilter, activeTaskStates, allTaskStates]); - const createStatusMenuItems = () => { + const createStatusMenuItems = useCallback(() => { return allStates.map((state) => ); - }; + }, [allStates]); - const doResetFilter = () => { - applyFilter({ + const doResetFilter = useCallback(async () => { + await applyFilter({ taskStates: activeStates, taskNames: [], }); - }; + }, [activeStates, applyFilter]); + + const onDeleteFilterGroup = useCallback( + async (categoryName: string | ToolbarChipGroup, value: string | ToolbarChip) => { + const newFilterTaskStates = [...filterTaskStates]; + const newFilterTaskNames = [...filterTaskNames]; + + switch (categoryName) { + case Category.STATUS: + _.remove(newFilterTaskStates, (status: string) => { + return status === value; + }); + setFilterTaskStates(newFilterTaskStates); + setSelectedTaskStates(newFilterTaskStates); + break; + case Category.TASK_NAME: + _.remove(newFilterTaskNames, (status: string) => { + return status === value; + }); + setFilterTaskNames(newFilterTaskNames); + break; + } + await applyFilter({ + taskNames: newFilterTaskNames, + taskStates: newFilterTaskStates, + }); + }, + [applyFilter, filterTaskNames, filterTaskStates] + ); - const onDeleteFilterGroup = (categoryName: string | ToolbarChipGroup, value: string | ToolbarChip): void => { - const newFilterTaskStates = [...filterTaskStates]; - const newFilterTaskNames = [...filterTaskNames]; + const onSelectTaskState = useCallback( + (event: React.MouseEvent | React.ChangeEvent, selection: string | SelectOptionObject): void => { + const filter: string[] = [...selectedTaskStates]; - switch (categoryName) { - case Category.STATUS: - _.remove(newFilterTaskStates, (status: string) => { - return status === value; + if (!filter.includes(selection.toString())) { + filter.push(selection.toString()); + } else { + _.remove(filter, (status: string) => { + return status === selection; }); - setFilterTaskStates(newFilterTaskStates); - setSelectedTaskStates(newFilterTaskStates); - break; - case Category.TASK_NAME: - _.remove(newFilterTaskNames, (status: string) => { - return status === value; - }); - setFilterTaskNames(newFilterTaskNames); - break; - } - applyFilter({ - taskNames: newFilterTaskNames, - taskStates: newFilterTaskStates, - }); - }; - - const onSelectTaskState = ( - event: React.MouseEvent | React.ChangeEvent, - selection: string | SelectOptionObject - ): void => { - const filter: string[] = [...selectedTaskStates]; - - if (!filter.includes(selection.toString())) { - filter.push(selection.toString()); - } else { - _.remove(filter, (status: string) => { - return status === selection; - }); - } - setSelectedTaskStates(filter); - }; + } + setSelectedTaskStates(filter); + }, + [selectedTaskStates] + ); - const doApplyFilter = () => { + const doApplyFilter = useCallback(async () => { const newTaskNames = [...filterTaskNames]; if (taskNameInput && !newTaskNames.includes(taskNameInput)) { newTaskNames.push(taskNameInput); @@ -150,66 +153,82 @@ const TaskInboxToolbar: React.FC = ({ taskStates: [...selectedTaskStates], taskNames: newTaskNames, }); - }; - - const toggleGroupItems = ( - - - - - - - - - - - - - - - + }, [applyFilter, filterTaskNames, selectedTaskStates, taskNameInput]); + + const toggleGroupItems = useMemo( + () => ( + + + + + + + + + + + + + + + + ), + [ + createStatusMenuItems, + doApplyFilter, + filterTaskNames, + filterTaskStates, + isStatusExpanded, + onDeleteFilterGroup, + onSelectTaskState, + selectedTaskStates, + taskNameInput, + ] ); - const toolbarItems = ( - - } breakpoint="xl"> - {toggleGroupItems} - - - - - - - - - + const toolbarItems = useMemo( + () => ( + + } breakpoint="xl"> + {toggleGroupItems} + + + + + + + + + + ), + [refresh, toggleGroupItems] ); return ( diff --git a/packages/runtime-tools-process-gateway-api/src/types.ts b/packages/runtime-tools-process-gateway-api/src/types.ts index ec6c175bc55..ac2c551bc2c 100644 --- a/packages/runtime-tools-process-gateway-api/src/types.ts +++ b/packages/runtime-tools-process-gateway-api/src/types.ts @@ -72,6 +72,11 @@ export interface JobsSortBy { executionCounter?: OrderBy; } +export interface JobsManagementState { + filters: JobStatus[]; + orderBy: JobsSortBy; +} + export interface BulkProcessInstanceActionResponse { successProcessInstances: ProcessInstance[]; failedProcessInstances: ProcessInstance[]; diff --git a/packages/runtime-tools-process-webapp-components/src/JobsManagement/JobsManagementContextProvider.tsx b/packages/runtime-tools-process-webapp-components/src/JobsManagement/JobsManagementContextProvider.tsx index 4f4981a2e9e..57728b6a816 100644 --- a/packages/runtime-tools-process-webapp-components/src/JobsManagement/JobsManagementContextProvider.tsx +++ b/packages/runtime-tools-process-webapp-components/src/JobsManagement/JobsManagementContextProvider.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import * as React from "react"; +import React, { useMemo } from "react"; import { ApolloClient } from "apollo-client"; import JobsManagementContext from "./JobsManagementContext"; import { JobsManagementGatewayApiImpl } from "./JobsManagementGatewayApi"; @@ -28,13 +28,11 @@ interface IOwnProps { } export const JobsManagementContextProvider: React.FC = ({ apolloClient, children }) => { - return ( - - {children} - + const gatewayApi = useMemo( + () => new JobsManagementGatewayApiImpl(new GraphQLJobsManagementQueries(apolloClient)), + [apolloClient] ); + return {children}; }; export default JobsManagementContextProvider; diff --git a/packages/runtime-tools-process-webapp-components/src/JobsManagement/JobsManagementGatewayApi.ts b/packages/runtime-tools-process-webapp-components/src/JobsManagement/JobsManagementGatewayApi.ts index f51b54c1b51..3c75c2f4347 100644 --- a/packages/runtime-tools-process-webapp-components/src/JobsManagement/JobsManagementGatewayApi.ts +++ b/packages/runtime-tools-process-webapp-components/src/JobsManagement/JobsManagementGatewayApi.ts @@ -23,6 +23,7 @@ import { BulkCancel, JobOperationResult, JobsSortBy, + JobsManagementState, } from "@kie-tools/runtime-tools-process-gateway-api/dist/types"; import { JobsManagementQueries } from "./JobsManagementQueries"; @@ -40,15 +41,20 @@ export interface JobsManagementGatewayApi { ) => Promise<{ modalTitle: string; modalContent: string }>; sortBy: (orderBy: JobsSortBy) => Promise; query(offset: number, limit: number): Promise; + onUpdateJobsManagementState: (listener: OnUpdateJobsManagementStateListener) => UnSubscribeHandler; } -export interface JobsManagementState { - filters: JobStatus[]; - orderBy: JobsSortBy | any; +export interface OnUpdateJobsManagementStateListener { + onUpdate: (jobsManagementState: JobsManagementState) => void; +} + +export interface UnSubscribeHandler { + unSubscribe: () => void; } export class JobsManagementGatewayApiImpl implements JobsManagementGatewayApi { private readonly queries: JobsManagementQueries; + private readonly onUpdateJobsManagementStateListeners: OnUpdateJobsManagementStateListener[] = []; private _JobsManagementState: JobsManagementState; constructor(queries: JobsManagementQueries) { @@ -68,6 +74,7 @@ export class JobsManagementGatewayApiImpl implements JobsManagementGatewayApi { applyFilter = (filter: JobStatus[]): Promise => { this._JobsManagementState.filters = filter; + this.onUpdateJobsManagementStateListeners.forEach((listener) => listener.onUpdate(this._JobsManagementState)); return Promise.resolve(); }; @@ -92,9 +99,25 @@ export class JobsManagementGatewayApiImpl implements JobsManagementGatewayApi { sortBy = (orderBy: JobsSortBy): Promise => { this._JobsManagementState.orderBy = orderBy; + this.onUpdateJobsManagementStateListeners.forEach((listener) => listener.onUpdate(this._JobsManagementState)); return Promise.resolve(); }; + onUpdateJobsManagementState(listener: OnUpdateJobsManagementStateListener): UnSubscribeHandler { + this.onUpdateJobsManagementStateListeners.push(listener); + + const unSubscribe = () => { + const index = this.onUpdateJobsManagementStateListeners.indexOf(listener); + if (index > -1) { + this.onUpdateJobsManagementStateListeners.splice(index, 1); + } + }; + + return { + unSubscribe, + }; + } + query(offset: number, limit: number): Promise { return new Promise((resolve, reject) => { this.queries diff --git a/packages/runtime-tools-process-webapp-components/src/ProcessList/ProcessListContextProvider.tsx b/packages/runtime-tools-process-webapp-components/src/ProcessList/ProcessListContextProvider.tsx index fa61b4bdc32..598edec4b89 100644 --- a/packages/runtime-tools-process-webapp-components/src/ProcessList/ProcessListContextProvider.tsx +++ b/packages/runtime-tools-process-webapp-components/src/ProcessList/ProcessListContextProvider.tsx @@ -35,7 +35,7 @@ export const ProcessListContextProvider: FC = ( }) => { const gatewayApiImpl = useMemo(() => { return new ProcessListGatewayApiImpl(new GraphQLProcessListQueries(apolloClient, options)); - }, []); + }, [apolloClient, options]); return {children}; }; diff --git a/packages/runtime-tools-process-webapp-components/src/ProcessList/ProcessListGatewayApi.ts b/packages/runtime-tools-process-webapp-components/src/ProcessList/ProcessListGatewayApi.ts index 5382e2901d9..6af3a8c30be 100644 --- a/packages/runtime-tools-process-webapp-components/src/ProcessList/ProcessListGatewayApi.ts +++ b/packages/runtime-tools-process-webapp-components/src/ProcessList/ProcessListGatewayApi.ts @@ -41,6 +41,7 @@ export interface ProcessListGatewayApi { query(offset: number, limit: number): Promise; getChildProcessesQuery(rootProcessInstanceId: string): Promise; onOpenProcessListen: (listener: OnOpenProcessListener) => UnSubscribeHandler; + onUpdateProcessListState: (listener: OnUpdateProcessListStateListener) => UnSubscribeHandler; openTriggerCloudEvent(processInstance?: ProcessInstance): void; } @@ -53,11 +54,16 @@ export interface OnOpenProcessListener { onOpen: (process: ProcessInstance) => void; } +export interface OnUpdateProcessListStateListener { + onUpdate: (processListState: ProcessListState) => void; +} + export interface UnSubscribeHandler { unSubscribe: () => void; } export class ProcessListGatewayApiImpl implements ProcessListGatewayApi { - private readonly listeners: OnOpenProcessListener[] = []; + private readonly onOpenProcessListeners: OnOpenProcessListener[] = []; + private readonly onUpdateProcessListStateListeners: OnUpdateProcessListStateListener[] = []; private readonly queries: ProcessListQueries; private _ProcessListState: ProcessListState; @@ -77,7 +83,7 @@ export class ProcessListGatewayApiImpl implements ProcessListGatewayApi { } openProcess = (process: ProcessInstance): Promise => { - this.listeners.forEach((listener) => listener.onOpen(process)); + this.onOpenProcessListeners.forEach((listener) => listener.onOpen(process)); return Promise.resolve(); }; @@ -89,11 +95,13 @@ export class ProcessListGatewayApiImpl implements ProcessListGatewayApi { applyFilter = (filter: ProcessInstanceFilter): Promise => { this.processListState.filters = filter; + this.onUpdateProcessListStateListeners.forEach((listener) => listener.onUpdate(this.processListState)); return Promise.resolve(); }; applySorting = (sortBy: ProcessListSortBy) => { this._ProcessListState.sortBy = sortBy; + this.onUpdateProcessListStateListeners.forEach((listener) => listener.onUpdate(this.processListState)); return Promise.resolve(); }; @@ -142,12 +150,27 @@ export class ProcessListGatewayApiImpl implements ProcessListGatewayApi { } onOpenProcessListen(listener: OnOpenProcessListener): UnSubscribeHandler { - this.listeners.push(listener); + this.onOpenProcessListeners.push(listener); + + const unSubscribe = () => { + const index = this.onOpenProcessListeners.indexOf(listener); + if (index > -1) { + this.onOpenProcessListeners.splice(index, 1); + } + }; + + return { + unSubscribe, + }; + } + + onUpdateProcessListState(listener: OnUpdateProcessListStateListener): UnSubscribeHandler { + this.onUpdateProcessListStateListeners.push(listener); const unSubscribe = () => { - const index = this.listeners.indexOf(listener); + const index = this.onUpdateProcessListStateListeners.indexOf(listener); if (index > -1) { - this.listeners.splice(index, 1); + this.onUpdateProcessListStateListeners.splice(index, 1); } }; diff --git a/packages/runtime-tools-process-webapp-components/src/TaskForms/TaskFormGatewayApi.ts b/packages/runtime-tools-process-webapp-components/src/TaskForms/TaskFormGatewayApi.ts index c53a505c133..4def9f9ea60 100644 --- a/packages/runtime-tools-process-webapp-components/src/TaskForms/TaskFormGatewayApi.ts +++ b/packages/runtime-tools-process-webapp-components/src/TaskForms/TaskFormGatewayApi.ts @@ -22,27 +22,24 @@ import { ANONYMOUS_USER, User } from "@kie-tools/runtime-tools-components/dist/c import { Form } from "@kie-tools/runtime-tools-shared-gateway-api/dist/types"; export interface TaskFormGatewayApi { - getTaskFormSchema(userTask: UserTaskInstance): Promise>; - - getTaskFormSchemaAsAnonymous(userTask: UserTaskInstance): Promise>; + getTaskFormSchema(userTask: UserTaskInstance, headers?: any): Promise>; getCustomForm(userTask: UserTaskInstance): Promise
; - doSubmit(userTask: UserTaskInstance, phase: string, payload: any): Promise; - - doSubmitAsAnonymous(userTask: UserTaskInstance, phase: string, payload: any): Promise; + doSubmit(userTask: UserTaskInstance, phase: string, payload: any, headers?: any): Promise; } export class TaskFormGatewayApiImpl implements TaskFormGatewayApi { constructor(private readonly getCurrentUser: () => User) {} - submitTaskForm(endpoint: string, payload: any) { + submitTaskForm(endpoint: string, payload: any, headers?: any) { return new Promise((resolve, reject) => { axios .post(endpoint, payload, { headers: { "Content-Type": "application/json", Accept: "application/json", + ...headers, }, }) .then((response) => { @@ -56,13 +53,14 @@ export class TaskFormGatewayApiImpl implements TaskFormGatewayApi { }); } - fetchTaskFormSchema(endpoint: string) { + fetchTaskFormSchema(endpoint: string, headers?: any) { return new Promise>((resolve, reject) => { axios .get(endpoint, { headers: { "Content-Type": "application/json", Accept: "application/json", + ...headers, }, }) .then((response) => { @@ -76,24 +74,14 @@ export class TaskFormGatewayApiImpl implements TaskFormGatewayApi { }); } - doSubmit(userTask: UserTaskInstance, phase: string, payload: any): Promise { + doSubmit(userTask: UserTaskInstance, phase: string, payload: any, headers?: any): Promise { const endpoint = `${userTask.endpoint}?phase=${phase}&${getTaskEndpointSecurityParams(userTask, this.getCurrentUser())}`; - return this.submitTaskForm(endpoint, payload); + return this.submitTaskForm(endpoint, payload, headers); } - getTaskFormSchema(userTask: UserTaskInstance): Promise> { + getTaskFormSchema(userTask: UserTaskInstance, headers?: any): Promise> { const endpoint = getTaskSchemaEndPoint(userTask, this.getCurrentUser()); - return this.fetchTaskFormSchema(endpoint); - } - - doSubmitAsAnonymous(userTask: UserTaskInstance, phase: string, payload: any): Promise { - const endpoint = `${userTask.endpoint}?phase=${phase}&${getTaskEndpointSecurityParams(userTask)}`; - return this.submitTaskForm(endpoint, payload); - } - - getTaskFormSchemaAsAnonymous(userTask: UserTaskInstance): Promise> { - const endpoint = getTaskSchemaEndPoint(userTask); - return this.fetchTaskFormSchema(endpoint); + return this.fetchTaskFormSchema(endpoint, headers); } getCustomForm(userTask: UserTaskInstance): Promise { @@ -118,7 +106,7 @@ function getTaskSchemaEndPoint(task: UserTaskInstance, user?: User): string { function getTaskEndpointSecurityParams(task: UserTaskInstance, user?: User): string { if (!user || user.id === ANONYMOUS_USER.id) { - return `user=${task.potentialUsers?.[0] ?? "admin"}`; + return `user=${task.potentialUsers?.[0] ?? "Dev User"}`; } let groups = ""; @@ -126,5 +114,5 @@ function getTaskEndpointSecurityParams(task: UserTaskInstance, user?: User): str if (user.groups && user.groups.length > 0) { groups = `&group=${user.groups.join("&group=")}`; } - return `user=${user.id}${groups}`; + return `${user.id ? `user=${user.id}` : ""}${groups}`; } diff --git a/packages/runtime-tools-process-webapp-components/src/TaskInbox/TaskInboxContextProvider.tsx b/packages/runtime-tools-process-webapp-components/src/TaskInbox/TaskInboxContextProvider.tsx index 8f39f96de6f..1145abe4f0f 100644 --- a/packages/runtime-tools-process-webapp-components/src/TaskInbox/TaskInboxContextProvider.tsx +++ b/packages/runtime-tools-process-webapp-components/src/TaskInbox/TaskInboxContextProvider.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { ReactElement } from "react"; +import React, { ReactElement, useMemo } from "react"; import { ApolloClient } from "apollo-client"; import TaskInboxContext from "./TaskInboxContext"; import { TaskInboxGatewayApiImpl } from "./TaskInboxGatewayApi"; @@ -30,14 +30,12 @@ interface IOwnProps { export const TaskInboxContextProvider: React.FC = ({ apolloClient, children }) => { const appContext = useKogitoAppContext(); - - return ( - appContext.getCurrentUser())} - > - {children} - + const gatewayApi = useMemo( + () => new TaskInboxGatewayApiImpl(new GraphQLTaskInboxQueries(apolloClient), () => appContext.getCurrentUser()), + [apolloClient, appContext] ); + + return {children}; }; export default TaskInboxContextProvider; diff --git a/packages/runtime-tools-process-webapp-components/src/TaskInbox/TaskInboxGatewayApi.ts b/packages/runtime-tools-process-webapp-components/src/TaskInbox/TaskInboxGatewayApi.ts index d52fd8c6fe6..15232d34ba1 100644 --- a/packages/runtime-tools-process-webapp-components/src/TaskInbox/TaskInboxGatewayApi.ts +++ b/packages/runtime-tools-process-webapp-components/src/TaskInbox/TaskInboxGatewayApi.ts @@ -35,20 +35,25 @@ export interface TaskInboxGatewayApi { getTaskById(uuid: string): Promise; openTask: (userTask: UserTaskInstance) => void; clearOpenTask: () => Promise; - onOpenTaskListen: (listener: OnOpenTaskListener) => UnSubscribeHandler; + onUpdateTaskListState(listener: OnUpdateTaskListStateListener): UnSubscribeHandler; } export interface OnOpenTaskListener { onOpen: (userTask: UserTaskInstance) => void; } +export interface OnUpdateTaskListStateListener { + onUpdate: (taskInboxState: TaskInboxState) => void; +} + export interface UnSubscribeHandler { unSubscribe: () => void; } export class TaskInboxGatewayApiImpl implements TaskInboxGatewayApi { - private readonly listeners: OnOpenTaskListener[] = []; + private readonly onOpenTaskListeners: OnOpenTaskListener[] = []; + private readonly onUpdateTaskListStateListeners: OnUpdateTaskListStateListener[] = []; private getCurrentUser: () => User; private readonly queries: TaskInboxQueries; private _taskInboxState: TaskInboxState; @@ -75,17 +80,19 @@ export class TaskInboxGatewayApiImpl implements TaskInboxGatewayApi { openTask(task: UserTaskInstance): Promise { this.activeTask = task; - this.listeners.forEach((listener) => listener.onOpen(task)); + this.onOpenTaskListeners.forEach((listener) => listener.onOpen(task)); return Promise.resolve(); } applyFilter(filter: QueryFilter): Promise { this._taskInboxState.filters = filter; + this.onUpdateTaskListStateListeners.forEach((listener) => listener.onUpdate(this._taskInboxState)); return Promise.resolve(); } applySorting(sortBy: SortBy): Promise { this._taskInboxState.sortBy = sortBy; + this.onUpdateTaskListStateListeners.forEach((listener) => listener.onUpdate(this._taskInboxState)); return Promise.resolve(); } @@ -111,12 +118,27 @@ export class TaskInboxGatewayApiImpl implements TaskInboxGatewayApi { } onOpenTaskListen(listener: OnOpenTaskListener): UnSubscribeHandler { - this.listeners.push(listener); + this.onOpenTaskListeners.push(listener); + + const unSubscribe = () => { + const index = this.onOpenTaskListeners.indexOf(listener); + if (index > -1) { + this.onOpenTaskListeners.splice(index, 1); + } + }; + + return { + unSubscribe, + }; + } + + onUpdateTaskListState(listener: OnUpdateTaskListStateListener): UnSubscribeHandler { + this.onUpdateTaskListStateListeners.push(listener); const unSubscribe = () => { - const index = this.listeners.indexOf(listener); + const index = this.onUpdateTaskListStateListeners.indexOf(listener); if (index > -1) { - this.listeners.splice(index, 1); + this.onUpdateTaskListStateListeners.splice(index, 1); } }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 217fdd48396..3e99038592a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3294,7 +3294,7 @@ importers: version: 7.6.13(react@17.0.2) '@storybook/addon-webpack5-compiler-babel': specifier: ^3.0.3 - version: 3.0.3(webpack@5.94.0(webpack-cli@4.10.0)) + version: 3.0.3(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) '@storybook/blocks': specifier: ^7.3.2 version: 7.6.13(@types/react-dom@17.0.8)(@types/react@17.0.21)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) @@ -3309,7 +3309,7 @@ importers: version: 7.6.13(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.5.3) '@storybook/react-webpack5': specifier: ^7.3.2 - version: 7.6.13(@babel/core@7.23.0)(@types/webpack@4.41.39)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4) + version: 7.6.13(@babel/core@7.23.0)(@swc/core@1.3.92)(@types/webpack@4.41.39)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4) '@types/d3-drag': specifier: ^3.0.3 version: 3.0.7 @@ -3339,7 +3339,7 @@ importers: version: 8.3.0 copy-webpack-plugin: specifier: ^11.0.0 - version: 11.0.0(webpack@5.94.0(webpack-cli@4.10.0)) + version: 11.0.0(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) copyfiles: specifier: ^2.4.1 version: 2.4.1 @@ -3351,16 +3351,16 @@ importers: version: 1.1.9 file-loader: specifier: ^6.2.0 - version: 6.2.0(webpack@5.94.0(webpack-cli@4.10.0)) + version: 6.2.0(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@5.5.3)) + version: 29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.92)(@types/node@20.14.2)(typescript@5.5.3)) jest-junit: specifier: ^16.0.0 version: 16.0.0 jest-when: specifier: ^3.6.0 - version: 3.6.0(jest@29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@5.5.3))) + version: 3.6.0(jest@29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.92)(@types/node@20.14.2)(typescript@5.5.3))) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -3378,13 +3378,13 @@ importers: version: 7.6.13(encoding@0.1.13) ts-jest: specifier: ^29.1.5 - version: 29.1.5(@babel/core@7.23.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.0))(jest@29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@5.5.3)))(typescript@5.5.3) + version: 29.1.5(@babel/core@7.23.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.0))(esbuild@0.18.20)(jest@29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.92)(@types/node@20.14.2)(typescript@5.5.3)))(typescript@5.5.3) typescript: specifier: ^5.5.3 version: 5.5.3 webpack: specifier: ^5.94.0 - version: 5.94.0(webpack-cli@4.10.0) + version: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0) webpack-cli: specifier: ^4.10.0 version: 4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0) @@ -3550,7 +3550,7 @@ importers: version: 7.6.13(react@17.0.2) '@storybook/addon-webpack5-compiler-babel': specifier: ^3.0.3 - version: 3.0.3(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) + version: 3.0.3(webpack@5.94.0(webpack-cli@4.10.0)) '@storybook/blocks': specifier: ^7.3.2 version: 7.6.13(@types/react-dom@17.0.8)(@types/react@17.0.21)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) @@ -3565,7 +3565,7 @@ importers: version: 7.6.13(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.5.3) '@storybook/react-webpack5': specifier: ^7.3.2 - version: 7.6.13(@babel/core@7.23.9)(@swc/core@1.3.92)(@types/webpack@4.41.39)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4) + version: 7.6.13(@babel/core@7.23.9)(@types/webpack@4.41.39)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4) '@types/jest-when': specifier: ^3.5.5 version: 3.5.5 @@ -3598,7 +3598,7 @@ importers: version: 9.5.1 html-webpack-plugin: specifier: ^5.3.2 - version: 5.5.3(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) + version: 5.5.3(webpack@5.94.0(webpack-cli@4.10.0)) junit-report-merger: specifier: ^4.0.0 version: 4.0.0 @@ -3619,7 +3619,7 @@ importers: version: 0.11.10 raw-loader: specifier: ^4.0.2 - version: 4.0.2(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) + version: 4.0.2(webpack@5.94.0(webpack-cli@4.10.0)) react: specifier: ^17.0.2 version: 17.0.2 @@ -3640,7 +3640,7 @@ importers: version: 5.5.3 webpack: specifier: ^5.94.0 - version: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0) + version: 5.94.0(webpack-cli@4.10.0) webpack-bundle-analyzer: specifier: ^4.10.2 version: 4.10.2 @@ -7563,6 +7563,12 @@ importers: packages/runtime-tools-management-console-webapp: dependencies: + '@kie-tools-core/react-hooks': + specifier: workspace:* + version: link:../react-hooks + '@kie-tools-core/workspaces-git-fs': + specifier: workspace:* + version: link:../workspaces-git-fs '@kie-tools/runtime-tools-components': specifier: workspace:* version: link:../runtime-tools-components @@ -7590,12 +7596,21 @@ importers: '@patternfly/react-core': specifier: ^4.276.6 version: 4.276.6(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@patternfly/react-icons': + specifier: ^4.93.6 + version: 4.93.6(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@patternfly/react-styles': + specifier: ^4.92.6 + version: 4.92.6 apollo-cache-inmemory: specifier: 1.6.6 version: 1.6.6(graphql@14.3.1) apollo-client: specifier: 2.6.10 version: 2.6.10(graphql@14.3.1) + apollo-link: + specifier: ^1.2.14 + version: 1.2.14(graphql@14.3.1) apollo-link-context: specifier: ^1.0.20 version: 1.0.20(graphql@14.3.1) @@ -7614,6 +7629,12 @@ importers: history: specifier: ^4.9.0 version: 4.10.1 + oidc-client-ts: + specifier: ^3.1.0 + version: 3.1.0 + openid-client: + specifier: ^6.1.3 + version: 6.1.3 react: specifier: ^17.0.2 version: 17.0.2 @@ -7663,18 +7684,27 @@ importers: '@kie-tools-core/envelope-bus': specifier: workspace:* version: link:../envelope-bus + '@kie-tools-core/patternfly-base': + specifier: workspace:* + version: link:../patternfly-base '@kie-tools-core/webpack-base': specifier: workspace:* version: link:../webpack-base '@kie-tools/eslint': specifier: workspace:* version: link:../eslint + '@kie-tools/maven-base': + specifier: workspace:* + version: link:../maven-base '@kie-tools/root-env': specifier: workspace:* version: link:../root-env '@kie-tools/tsconfig': specifier: workspace:* version: link:../tsconfig + '@types/history': + specifier: ^4.7.3 + version: 4.7.11 '@types/react': specifier: ^17.0.6 version: 17.0.21 @@ -7687,15 +7717,15 @@ importers: '@types/react-router-dom': specifier: ^5.3.3 version: 5.3.3 + '@types/uuid': + specifier: ^8.3.0 + version: 8.3.0 apollo-server-express: specifier: ^3.13.0 version: 3.13.0(encoding@0.1.13)(express@4.21.1)(graphql@14.3.1) body-parser: specifier: ^1.20.3 version: 1.20.3 - concurrently: - specifier: ^8.2.2 - version: 8.2.2 copy-webpack-plugin: specifier: ^11.0.0 version: 11.0.0(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0)) @@ -7712,7 +7742,7 @@ importers: specifier: ^5.0.1 version: 5.0.1(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0)) express: - specifier: ^4.21.1 + specifier: ^4.21.0 version: 4.21.1 file-loader: specifier: ^6.2.0 @@ -7735,6 +7765,9 @@ importers: nodemon: specifier: ^3.1.4 version: 3.1.4 + oauth2-mock-server: + specifier: ^7.1.2 + version: 7.1.2 rimraf: specifier: ^3.0.2 version: 3.0.2 @@ -8099,6 +8132,9 @@ importers: '@kie-tools-core/patternfly-base': specifier: workspace:* version: link:../patternfly-base + '@kie-tools-core/react-hooks': + specifier: workspace:* + version: link:../react-hooks '@kie-tools/i18n-common-dictionary': specifier: workspace:* version: link:../i18n-common-dictionary @@ -24629,6 +24665,9 @@ packages: jose@4.14.6: resolution: {integrity: sha512-EqJPEUlZD0/CSUMubKtMaYUOtWe91tZXTWMJZoKSbLk+KtdhNdcvppH8lA9XwVu2V4Ailvsj0GBZJ2ZwDjfesQ==} + jose@5.9.6: + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + js-sha256@0.10.1: resolution: {integrity: sha512-5obBtsz9301ULlsgggLg542s/jqtddfOpV5KJc4hajc9JV8GeY2gZHSVpYBn4nWqAUTJ9v+xwtbJ1mIBgIH5Vw==} @@ -26013,6 +26052,14 @@ packages: nwsapi@2.2.7: resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} + oauth2-mock-server@7.1.2: + resolution: {integrity: sha512-xUg/YOTcMRe8W+q2jphecq1fB1BAjlAPbeeA9lvqwGaQSPJKxI2e8JUnDXHrrKGNJAVXQdHgE/9h4RpCtOfYOA==} + engines: {node: ^18.12 || ^20 || ^22, yarn: ^1.15.2} + hasBin: true + + oauth4webapi@3.1.3: + resolution: {integrity: sha512-dik5wEMdFL5p3JlijYvM7wMNCgaPhblLIDCZtdXcaZp5wgu5Iwmsu7lMzgFhIDTi5d0BJo03LVoOoFQvXMeOeQ==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -26083,6 +26130,10 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + oidc-client-ts@3.1.0: + resolution: {integrity: sha512-IDopEXjiwjkmJLYZo6BTlvwOtnlSniWZkKZoXforC/oLZHC9wkIxd25Kwtmo5yKFMMVcsp3JY6bhcNJqdYk8+g==} + engines: {node: '>=18'} + on-finished@2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} @@ -26140,6 +26191,9 @@ packages: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true + openid-client@6.1.3: + resolution: {integrity: sha512-74sc0bR4ptfwCwMheLPaJHTQnds+97Yu6O8eQgoO3MRcd53xkfKyl3gNAsRsYSYoO+AVG3eCgnRMjRkZ6n2RYw==} + optimism@0.10.3: resolution: {integrity: sha512-9A5pqGoQk49H6Vhjb9kPgAeeECfUDF6aIICbMDL23kDLStBn1MWk3YvcZ4xWF9CsSf6XEgvRLkXy4xof/56vVw==} @@ -36902,7 +36956,7 @@ snapshots: '@graphql-tools/utils': 9.2.1(graphql@14.3.1) '@whatwg-node/fetch': 0.8.8 graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - encoding @@ -36911,7 +36965,7 @@ snapshots: '@graphql-tools/utils': 9.2.1(graphql@14.3.1) dataloader: 2.2.2 graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 value-or-promise: 1.0.12 '@graphql-tools/code-file-loader@7.3.23(@babel/core@7.23.9)(graphql@14.3.1)': @@ -36934,7 +36988,7 @@ snapshots: '@graphql-tools/utils': 9.2.1(graphql@14.3.1) dataloader: 2.2.2 graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 value-or-promise: 1.0.12 '@graphql-tools/executor-graphql-ws@0.0.14(graphql@14.3.1)': @@ -36945,7 +36999,7 @@ snapshots: graphql: 14.3.1 graphql-ws: 5.12.1(graphql@14.3.1) isomorphic-ws: 5.0.0(ws@8.13.0) - tslib: 2.6.2 + tslib: 2.7.0 ws: 8.13.0 transitivePeerDependencies: - bufferutil @@ -36960,7 +37014,7 @@ snapshots: extract-files: 11.0.0 graphql: 14.3.1 meros: 1.3.0(@types/node@22.5.2) - tslib: 2.6.2 + tslib: 2.7.0 value-or-promise: 1.0.12 transitivePeerDependencies: - '@types/node' @@ -36971,7 +37025,7 @@ snapshots: '@types/ws': 8.5.5 graphql: 14.3.1 isomorphic-ws: 5.0.0(ws@8.13.0) - tslib: 2.6.2 + tslib: 2.7.0 ws: 8.13.0 transitivePeerDependencies: - bufferutil @@ -36983,7 +37037,7 @@ snapshots: '@graphql-typed-document-node/core': 3.2.0(graphql@14.3.1) '@repeaterjs/repeater': 3.0.4 graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 value-or-promise: 1.0.12 '@graphql-tools/git-loader@7.3.0(@babel/core@7.23.9)(graphql@14.3.1)': @@ -37021,7 +37075,7 @@ snapshots: '@graphql-tools/utils': 9.2.1(graphql@14.3.1) globby: 11.1.0 graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 unixify: 1.0.0 '@graphql-tools/graphql-tag-pluck@7.5.2(@babel/core@7.23.9)(graphql@14.3.1)': @@ -37042,14 +37096,14 @@ snapshots: '@graphql-tools/utils': 9.2.1(graphql@14.3.1) graphql: 14.3.1 resolve-from: 5.0.0 - tslib: 2.6.2 + tslib: 2.7.0 '@graphql-tools/json-file-loader@7.4.18(graphql@14.3.1)': dependencies: '@graphql-tools/utils': 9.2.1(graphql@14.3.1) globby: 11.1.0 graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 unixify: 1.0.0 '@graphql-tools/load@7.8.14(graphql@14.3.1)': @@ -37058,19 +37112,19 @@ snapshots: '@graphql-tools/utils': 9.2.1(graphql@14.3.1) graphql: 14.3.1 p-limit: 3.1.0 - tslib: 2.6.2 + tslib: 2.7.0 '@graphql-tools/merge@8.3.1(graphql@14.3.1)': dependencies: '@graphql-tools/utils': 8.9.0(graphql@14.3.1) graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 '@graphql-tools/merge@8.4.2(graphql@14.3.1)': dependencies: '@graphql-tools/utils': 9.2.1(graphql@14.3.1) graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 '@graphql-tools/mock@8.7.20(graphql@14.3.1)': dependencies: @@ -37078,12 +37132,12 @@ snapshots: '@graphql-tools/utils': 9.2.1(graphql@14.3.1) fast-json-stable-stringify: 2.1.0 graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 '@graphql-tools/optimize@1.4.0(graphql@14.3.1)': dependencies: graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 '@graphql-tools/prisma-loader@7.2.72(@types/node@22.5.2)(encoding@0.1.13)(graphql@14.3.1)': dependencies: @@ -37104,7 +37158,7 @@ snapshots: json-stable-stringify: 1.0.2 lodash: 4.17.21 scuid: 1.1.0 - tslib: 2.6.2 + tslib: 2.7.0 yaml-ast-parser: 0.0.43 transitivePeerDependencies: - '@types/node' @@ -37118,7 +37172,7 @@ snapshots: '@ardatan/relay-compiler': 12.0.0(encoding@0.1.13)(graphql@14.3.1) '@graphql-tools/utils': 9.2.1(graphql@14.3.1) graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - encoding - supports-color @@ -37128,7 +37182,7 @@ snapshots: '@graphql-tools/merge': 8.3.1(graphql@14.3.1) '@graphql-tools/utils': 8.9.0(graphql@14.3.1) graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 value-or-promise: 1.0.11 '@graphql-tools/schema@9.0.19(graphql@14.3.1)': @@ -37136,7 +37190,7 @@ snapshots: '@graphql-tools/merge': 8.4.2(graphql@14.3.1) '@graphql-tools/utils': 9.2.1(graphql@14.3.1) graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 value-or-promise: 1.0.12 '@graphql-tools/url-loader@7.17.18(@types/node@22.5.2)(encoding@0.1.13)(graphql@14.3.1)': @@ -37152,7 +37206,7 @@ snapshots: '@whatwg-node/fetch': 0.8.8 graphql: 14.3.1 isomorphic-ws: 5.0.0(ws@8.18.0) - tslib: 2.6.2 + tslib: 2.7.0 value-or-promise: 1.0.12 ws: 8.18.0 transitivePeerDependencies: @@ -37164,18 +37218,18 @@ snapshots: '@graphql-tools/utils@8.13.1(graphql@14.3.1)': dependencies: graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 '@graphql-tools/utils@8.9.0(graphql@14.3.1)': dependencies: graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 '@graphql-tools/utils@9.2.1(graphql@14.3.1)': dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@14.3.1) graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 '@graphql-tools/wrap@9.4.2(graphql@14.3.1)': dependencies: @@ -37183,7 +37237,7 @@ snapshots: '@graphql-tools/schema': 9.0.19(graphql@14.3.1) '@graphql-tools/utils': 9.2.1(graphql@14.3.1) graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 value-or-promise: 1.0.12 '@graphql-typed-document-node/core@3.2.0(graphql@14.3.1)': @@ -37802,21 +37856,21 @@ snapshots: '@jsdevtools/ono@7.1.3': {} - '@jsonjoy.com/base64@1.1.2(tslib@2.6.3)': + '@jsonjoy.com/base64@1.1.2(tslib@2.7.0)': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 - '@jsonjoy.com/json-pack@1.0.4(tslib@2.6.3)': + '@jsonjoy.com/json-pack@1.0.4(tslib@2.7.0)': dependencies: - '@jsonjoy.com/base64': 1.1.2(tslib@2.6.3) - '@jsonjoy.com/util': 1.3.0(tslib@2.6.3) + '@jsonjoy.com/base64': 1.1.2(tslib@2.7.0) + '@jsonjoy.com/util': 1.3.0(tslib@2.7.0) hyperdyperid: 1.2.0 - thingies: 1.21.0(tslib@2.6.3) - tslib: 2.6.3 + thingies: 1.21.0(tslib@2.7.0) + tslib: 2.7.0 - '@jsonjoy.com/util@1.3.0(tslib@2.6.3)': + '@jsonjoy.com/util@1.3.0(tslib@2.7.0)': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 '@juggle/resize-observer@3.4.0': {} @@ -37859,7 +37913,7 @@ snapshots: dependencies: ajv: 8.17.1 ajv-formats: 2.1.1(ajv@8.17.1) - tslib: 2.6.2 + tslib: 2.7.0 '@leichtgewicht/ip-codec@2.0.4': {} @@ -37897,7 +37951,7 @@ snapshots: '@motionone/easing': 10.15.1 '@motionone/types': 10.15.1 '@motionone/utils': 10.15.1 - tslib: 2.6.2 + tslib: 2.7.0 '@motionone/dom@10.16.2': dependencies: @@ -37906,18 +37960,18 @@ snapshots: '@motionone/types': 10.15.1 '@motionone/utils': 10.15.1 hey-listen: 1.0.8 - tslib: 2.6.2 + tslib: 2.7.0 '@motionone/easing@10.15.1': dependencies: '@motionone/utils': 10.15.1 - tslib: 2.6.2 + tslib: 2.7.0 '@motionone/generators@10.15.1': dependencies: '@motionone/types': 10.15.1 '@motionone/utils': 10.15.1 - tslib: 2.6.2 + tslib: 2.7.0 '@motionone/types@10.15.1': {} @@ -37925,7 +37979,7 @@ snapshots: dependencies: '@motionone/types': 10.15.1 hey-listen: 1.0.8 - tslib: 2.6.2 + tslib: 2.7.0 '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': optional: true @@ -38245,18 +38299,18 @@ snapshots: dependencies: asn1js: 3.0.5 pvtsutils: 1.3.5 - tslib: 2.6.2 + tslib: 2.7.0 '@peculiar/json-schema@1.1.12': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@peculiar/webcrypto@1.4.3': dependencies: '@peculiar/asn1-schema': 2.3.6 '@peculiar/json-schema': 1.1.12 pvtsutils: 1.3.5 - tslib: 2.6.2 + tslib: 2.7.0 webcrypto-core: 1.7.7 '@pkgjs/parseargs@0.11.0': @@ -40199,7 +40253,7 @@ snapshots: - uglify-js - webpack-cli - '@storybook/builder-webpack5@7.6.13(encoding@0.1.13)(esbuild@0.18.20)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))': + '@storybook/builder-webpack5@7.6.13(encoding@0.1.13)(esbuild@0.18.20)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))': dependencies: '@babel/core': 7.24.9 '@storybook/channels': 7.6.13 @@ -40249,6 +40303,56 @@ snapshots: - uglify-js - webpack-cli + '@storybook/builder-webpack5@7.6.13(encoding@0.1.13)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))': + dependencies: + '@babel/core': 7.24.9 + '@storybook/channels': 7.6.13 + '@storybook/client-logger': 7.6.13 + '@storybook/core-common': 7.6.13(encoding@0.1.13) + '@storybook/core-events': 7.6.13 + '@storybook/core-webpack': 7.6.13(encoding@0.1.13) + '@storybook/node-logger': 7.6.13 + '@storybook/preview': 7.6.13 + '@storybook/preview-api': 7.6.13 + '@swc/core': 1.3.92 + '@types/node': 18.17.18 + '@types/semver': 7.5.2 + babel-loader: 9.1.3(@babel/core@7.24.9)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))) + browser-assert: 1.2.1 + case-sensitive-paths-webpack-plugin: 2.4.0 + cjs-module-lexer: 1.2.3 + constants-browserify: 1.0.0 + css-loader: 6.7.1(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))) + es-module-lexer: 1.4.1 + express: 4.21.1 + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.5.3)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))) + fs-extra: 11.1.1 + html-webpack-plugin: 5.5.3(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))) + magic-string: 0.30.7 + path-browserify: 1.0.1 + process: 0.11.10 + semver: 7.5.4 + style-loader: 3.3.3(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))) + swc-loader: 0.2.3(@swc/core@1.3.92)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))) + terser-webpack-plugin: 5.3.10(@swc/core@1.3.92)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))) + ts-dedent: 2.2.0 + url: 0.11.3 + util: 0.12.5 + util-deprecate: 1.0.2 + webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + webpack-dev-middleware: 6.1.1(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))) + webpack-hot-middleware: 2.25.4 + webpack-virtual-modules: 0.5.0 + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - '@swc/helpers' + - encoding + - esbuild + - supports-color + - uglify-js + - webpack-cli + '@storybook/builder-webpack5@7.6.13(encoding@0.1.13)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))': dependencies: '@babel/core': 7.24.9 @@ -41083,16 +41187,16 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@7.6.13(@babel/core@7.23.0)(@types/webpack@4.41.39)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)': + '@storybook/preset-react-webpack@7.6.13(@babel/core@7.23.0)(@swc/core@1.3.92)(@types/webpack@4.41.39)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)': dependencies: '@babel/preset-flow': 7.22.15(@babel/core@7.23.0) '@babel/preset-react': 7.22.15(@babel/core@7.23.0) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.11(@types/webpack@4.41.39)(react-refresh@0.14.0)(type-fest@4.26.1)(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)(webpack@5.94.0(webpack-cli@4.10.0)) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.11(@types/webpack@4.41.39)(react-refresh@0.14.0)(type-fest@4.26.1)(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) '@storybook/core-webpack': 7.6.13(encoding@0.1.13) '@storybook/docs-tools': 7.6.13(encoding@0.1.13) '@storybook/node-logger': 7.6.13 '@storybook/react': 7.6.13(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.5.3) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.5.3)(webpack@5.94.0(webpack-cli@4.10.0)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.5.3)(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) '@types/node': 18.17.18 '@types/semver': 7.5.2 babel-plugin-add-react-displayname: 0.0.5 @@ -41103,7 +41207,7 @@ snapshots: react-dom: 17.0.2(react@17.0.2) react-refresh: 0.14.0 semver: 7.5.4 - webpack: 5.94.0(webpack-cli@4.10.0) + webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0) optionalDependencies: '@babel/core': 7.23.0 typescript: 5.5.3 @@ -41121,16 +41225,16 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@7.6.13(@babel/core@7.23.9)(@swc/core@1.3.92)(@types/webpack@4.41.39)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)': + '@storybook/preset-react-webpack@7.6.13(@babel/core@7.23.9)(@types/webpack@4.41.39)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)': dependencies: '@babel/preset-flow': 7.22.15(@babel/core@7.23.9) '@babel/preset-react': 7.22.15(@babel/core@7.23.9) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.11(@types/webpack@4.41.39)(react-refresh@0.14.0)(type-fest@4.26.1)(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.11(@types/webpack@4.41.39)(react-refresh@0.14.0)(type-fest@4.26.1)(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)(webpack@5.94.0(webpack-cli@4.10.0)) '@storybook/core-webpack': 7.6.13(encoding@0.1.13) '@storybook/docs-tools': 7.6.13(encoding@0.1.13) '@storybook/node-logger': 7.6.13 '@storybook/react': 7.6.13(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.5.3) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.5.3)(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.5.3)(webpack@5.94.0(webpack-cli@4.10.0)) '@types/node': 18.17.18 '@types/semver': 7.5.2 babel-plugin-add-react-displayname: 0.0.5 @@ -41141,7 +41245,7 @@ snapshots: react-dom: 17.0.2(react@17.0.2) react-refresh: 0.14.0 semver: 7.5.4 - webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0) + webpack: 5.94.0(webpack-cli@4.10.0) optionalDependencies: '@babel/core': 7.23.9 typescript: 5.5.3 @@ -41205,7 +41309,7 @@ snapshots: flat-cache: 3.0.4 micromatch: 4.0.5 react-docgen-typescript: 2.2.2(typescript@5.5.3) - tslib: 2.6.2 + tslib: 2.7.0 typescript: 5.5.3 webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0) transitivePeerDependencies: @@ -41219,7 +41323,7 @@ snapshots: flat-cache: 3.0.4 micromatch: 4.0.5 react-docgen-typescript: 2.2.2(typescript@5.5.3) - tslib: 2.6.2 + tslib: 2.7.0 typescript: 5.5.3 webpack: 5.94.0(esbuild@0.18.20) transitivePeerDependencies: @@ -41233,7 +41337,7 @@ snapshots: flat-cache: 3.0.4 micromatch: 4.0.5 react-docgen-typescript: 2.2.2(typescript@5.5.3) - tslib: 2.6.2 + tslib: 2.7.0 typescript: 5.5.3 webpack: 5.94.0(webpack-cli@4.10.0) transitivePeerDependencies: @@ -41331,10 +41435,10 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/react-webpack5@7.6.13(@babel/core@7.23.0)(@types/webpack@4.41.39)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)': + '@storybook/react-webpack5@7.6.13(@babel/core@7.23.0)(@swc/core@1.3.92)(@types/webpack@4.41.39)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)': dependencies: - '@storybook/builder-webpack5': 7.6.13(encoding@0.1.13)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0)) - '@storybook/preset-react-webpack': 7.6.13(@babel/core@7.23.0)(@types/webpack@4.41.39)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4) + '@storybook/builder-webpack5': 7.6.13(encoding@0.1.13)(esbuild@0.18.20)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0)) + '@storybook/preset-react-webpack': 7.6.13(@babel/core@7.23.0)(@swc/core@1.3.92)(@types/webpack@4.41.39)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4) '@storybook/react': 7.6.13(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.5.3) '@types/node': 18.17.18 react: 17.0.2 @@ -41357,10 +41461,10 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/react-webpack5@7.6.13(@babel/core@7.23.9)(@swc/core@1.3.92)(@types/webpack@4.41.39)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)': + '@storybook/react-webpack5@7.6.13(@babel/core@7.23.9)(@types/webpack@4.41.39)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4)': dependencies: - '@storybook/builder-webpack5': 7.6.13(encoding@0.1.13)(esbuild@0.18.20)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) - '@storybook/preset-react-webpack': 7.6.13(@babel/core@7.23.9)(@swc/core@1.3.92)(@types/webpack@4.41.39)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4) + '@storybook/builder-webpack5': 7.6.13(encoding@0.1.13)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + '@storybook/preset-react-webpack': 7.6.13(@babel/core@7.23.9)(@types/webpack@4.41.39)(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@4.26.1)(typescript@5.5.3)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))(webpack-dev-server@4.15.1(webpack-cli@4.10.0)(webpack@5.94.0))(webpack-hot-middleware@2.25.4) '@storybook/react': 7.6.13(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.5.3) '@types/node': 18.17.18 react: 17.0.2 @@ -42893,7 +42997,7 @@ snapshots: '@types/node': 22.5.2 '@whatwg-node/events': 0.0.2 busboy: 1.6.0 - tslib: 2.6.2 + tslib: 2.7.0 '@whatwg-node/node-fetch@0.3.6': dependencies: @@ -42901,7 +43005,7 @@ snapshots: busboy: 1.6.0 fast-querystring: 1.1.2 fast-url-parser: 1.1.3 - tslib: 2.6.2 + tslib: 2.7.0 '@wojtekmaj/date-utils@1.5.0': {} @@ -43050,7 +43154,7 @@ snapshots: '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.18.20)': dependencies: esbuild: 0.18.20 - tslib: 2.6.2 + tslib: 2.7.0 '@yarnpkg/extensions@1.1.0-rc.6(@yarnpkg/core@4.0.0-rc.50(typanion@3.9.0))': dependencies: @@ -43589,7 +43693,7 @@ snapshots: aria-hidden@1.2.3: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 aria-query@5.1.3: dependencies: @@ -43716,7 +43820,7 @@ snapshots: dependencies: pvtsutils: 1.3.5 pvutils: 1.1.3 - tslib: 2.6.2 + tslib: 2.7.0 assert-plus@1.0.0: {} @@ -43734,7 +43838,7 @@ snapshots: ast-types@0.14.2: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 ast-types@0.15.2: dependencies: @@ -43742,7 +43846,7 @@ snapshots: ast-types@0.16.1: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 astral-regex@2.0.0: {} @@ -43968,6 +44072,13 @@ snapshots: schema-utils: 4.2.0 webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20) + babel-loader@9.1.3(@babel/core@7.24.9)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))): + dependencies: + '@babel/core': 7.24.9 + find-cache-dir: 4.0.0 + schema-utils: 4.2.0 + webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + babel-loader@9.1.3(@babel/core@7.24.9)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))): dependencies: '@babel/core': 7.24.9 @@ -44909,7 +45020,7 @@ snapshots: camel-case@4.1.2: dependencies: pascal-case: 3.1.2 - tslib: 2.6.2 + tslib: 2.7.0 camelcase@4.1.0: {} @@ -44937,7 +45048,7 @@ snapshots: capital-case@1.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.7.0 upper-case-first: 2.0.2 capture-exit@2.0.0: @@ -45019,7 +45130,7 @@ snapshots: path-case: 3.0.4 sentence-case: 3.0.4 snake-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.7.0 char-regex@1.0.2: {} @@ -45407,7 +45518,7 @@ snapshots: constant-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.7.0 upper-case: 2.0.2 constants-browserify@1.0.0: {} @@ -45844,6 +45955,18 @@ snapshots: semver: 7.6.2 webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20) + css-loader@6.7.1(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))): + dependencies: + icss-utils: 5.1.0(postcss@8.4.38) + postcss: 8.4.38 + postcss-modules-extract-imports: 3.0.0(postcss@8.4.38) + postcss-modules-local-by-default: 4.0.0(postcss@8.4.38) + postcss-modules-scope: 3.0.0(postcss@8.4.38) + postcss-modules-values: 4.0.0(postcss@8.4.38) + postcss-value-parser: 4.2.0 + semver: 7.6.2 + webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + css-loader@6.7.1(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))): dependencies: icss-utils: 5.1.0(postcss@8.4.38) @@ -46691,7 +46814,7 @@ snapshots: dot-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.7.0 dotenv-expand@10.0.0: {} @@ -47845,11 +47968,11 @@ snapshots: file-selector@0.2.4: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 file-selector@0.4.0: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 file-system-cache@2.3.0: dependencies: @@ -48091,6 +48214,23 @@ snapshots: typescript: 5.5.3 webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20) + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.5.3)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))): + dependencies: + '@babel/code-frame': 7.23.5 + chalk: 4.1.2 + chokidar: 3.5.3 + cosmiconfig: 7.0.1 + deepmerge: 4.2.2 + fs-extra: 10.1.0 + memfs: 3.5.1 + minimatch: 3.1.2 + node-abort-controller: 3.1.1 + schema-utils: 3.3.0 + semver: 7.5.4 + tapable: 2.2.1 + typescript: 5.5.3 + webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.5.3)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))): dependencies: '@babel/code-frame': 7.23.5 @@ -48516,7 +48656,7 @@ snapshots: jiti: 1.17.1 minimatch: 4.2.3 string-env-interpolation: 1.0.1 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - '@types/node' - bufferutil @@ -48538,7 +48678,7 @@ snapshots: graphql-tag@2.12.6(graphql@14.3.1): dependencies: graphql: 14.3.1 - tslib: 2.6.2 + tslib: 2.7.0 graphql-ws@5.12.1(graphql@14.3.1): dependencies: @@ -48648,7 +48788,7 @@ snapshots: header-case@2.0.4: dependencies: capital-case: 1.0.4 - tslib: 2.6.2 + tslib: 2.7.0 heatmap.js@2.0.5: {} @@ -48773,6 +48913,15 @@ snapshots: tapable: 2.2.1 webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20) + html-webpack-plugin@5.5.3(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))): + dependencies: + '@types/html-minifier-terser': 6.1.0 + html-minifier-terser: 6.1.0 + lodash: 4.17.21 + pretty-error: 4.0.0 + tapable: 2.2.1 + webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + html-webpack-plugin@5.5.3(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))): dependencies: '@types/html-minifier-terser': 6.1.0 @@ -49295,7 +49444,7 @@ snapshots: is-lower-case@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 is-map@2.0.2: {} @@ -49387,7 +49536,7 @@ snapshots: is-upper-case@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 is-weakmap@2.0.1: {} @@ -50283,10 +50432,6 @@ snapshots: dependencies: jest: 29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.92)(@types/node@20.14.2)(typescript@5.5.3)) - jest-when@3.6.0(jest@29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@5.5.3))): - dependencies: - jest: 29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@5.5.3)) - jest-when@3.6.0(jest@29.7.0(@types/node@22.5.2)(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.92)(@types/node@22.5.2)(typescript@5.5.3))): dependencies: jest: 29.7.0(@types/node@22.5.2)(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.92)(@types/node@22.5.2)(typescript@5.5.3)) @@ -50416,6 +50561,8 @@ snapshots: jose@4.14.6: {} + jose@5.9.6: {} + js-sha256@0.10.1: {} js-tokens@4.0.0: {} @@ -51201,11 +51348,11 @@ snapshots: lower-case-first@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 lower-case@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 lowercase-keys@2.0.0: {} @@ -51391,10 +51538,10 @@ snapshots: memfs@4.11.1: dependencies: - '@jsonjoy.com/json-pack': 1.0.4(tslib@2.6.3) - '@jsonjoy.com/util': 1.3.0(tslib@2.6.3) - tree-dump: 1.0.2(tslib@2.6.3) - tslib: 2.6.3 + '@jsonjoy.com/json-pack': 1.0.4(tslib@2.7.0) + '@jsonjoy.com/util': 1.3.0(tslib@2.7.0) + tree-dump: 1.0.2(tslib@2.7.0) + tslib: 2.7.0 memoize-one@5.2.1: {} @@ -51835,7 +51982,7 @@ snapshots: no-case@3.0.4: dependencies: lower-case: 2.0.2 - tslib: 2.6.2 + tslib: 2.7.0 node-abi@3.43.0: dependencies: @@ -52160,6 +52307,18 @@ snapshots: nwsapi@2.2.7: {} + oauth2-mock-server@7.1.2: + dependencies: + basic-auth: 2.0.1 + cors: 2.8.5 + express: 4.21.1 + is-plain-object: 5.0.0 + jose: 5.9.6 + transitivePeerDependencies: + - supports-color + + oauth4webapi@3.1.3: {} + object-assign@4.1.1: {} object-copy@0.1.0: @@ -52247,6 +52406,10 @@ snapshots: obuf@1.1.2: {} + oidc-client-ts@3.1.0: + dependencies: + jwt-decode: 4.0.0 + on-finished@2.3.0: dependencies: ee-first: 1.1.1 @@ -52310,6 +52473,11 @@ snapshots: opener@1.5.2: {} + openid-client@6.1.3: + dependencies: + jose: 5.9.6 + oauth4webapi: 3.1.3 + optimism@0.10.3: dependencies: '@wry/context': 0.4.4 @@ -52463,7 +52631,7 @@ snapshots: param-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.7.0 parent-module@1.0.1: dependencies: @@ -52527,7 +52695,7 @@ snapshots: pascal-case@3.1.2: dependencies: no-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.7.0 pascalcase@0.1.1: {} @@ -52554,7 +52722,7 @@ snapshots: path-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.7.0 path-exists@3.0.0: {} @@ -53232,7 +53400,7 @@ snapshots: pvtsutils@1.3.5: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 pvutils@1.1.3: {} @@ -53302,12 +53470,6 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 - raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)): - dependencies: - loader-utils: 2.0.4 - schema-utils: 3.3.0 - webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0) - raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0)): dependencies: loader-utils: 2.0.4 @@ -53654,7 +53816,7 @@ snapshots: dependencies: react: 17.0.2 react-style-singleton: 2.2.1(@types/react@17.0.21)(react@17.0.2) - tslib: 2.6.2 + tslib: 2.7.0 optionalDependencies: '@types/react': 17.0.21 @@ -53663,7 +53825,7 @@ snapshots: react: 17.0.2 react-remove-scroll-bar: 2.3.4(@types/react@17.0.21)(react@17.0.2) react-style-singleton: 2.2.1(@types/react@17.0.21)(react@17.0.2) - tslib: 2.6.2 + tslib: 2.7.0 use-callback-ref: 1.3.0(@types/react@17.0.21)(react@17.0.2) use-sidecar: 1.1.2(@types/react@17.0.21)(react@17.0.2) optionalDependencies: @@ -53733,7 +53895,7 @@ snapshots: get-nonce: 1.0.1 invariant: 2.2.4 react: 17.0.2 - tslib: 2.6.2 + tslib: 2.7.0 optionalDependencies: '@types/react': 17.0.21 @@ -53948,7 +54110,7 @@ snapshots: ast-types: 0.16.1 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.6.2 + tslib: 2.7.0 rechoir@0.6.2: dependencies: @@ -54557,7 +54719,7 @@ snapshots: sentence-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.7.0 upper-case-first: 2.0.2 serialize-javascript@6.0.1: @@ -54786,7 +54948,7 @@ snapshots: snake-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.7.0 snapdragon-node@2.1.1: dependencies: @@ -54968,7 +55130,7 @@ snapshots: sponge-case@1.0.1: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 sprintf-js@1.0.3: {} @@ -55271,6 +55433,10 @@ snapshots: dependencies: webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20) + style-loader@3.3.3(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))): + dependencies: + webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + style-loader@3.3.3(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))): dependencies: webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0)) @@ -55368,7 +55534,7 @@ snapshots: swap-case@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 swc-loader@0.2.3(@swc/core@1.3.92)(webpack@5.94.0(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0)): dependencies: @@ -55380,6 +55546,11 @@ snapshots: '@swc/core': 1.3.92 webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20) + swc-loader@0.2.3(@swc/core@1.3.92)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))): + dependencies: + '@swc/core': 1.3.92 + webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + swc-loader@0.2.3(@swc/core@1.3.92)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))): dependencies: '@swc/core': 1.3.92 @@ -55530,6 +55701,17 @@ snapshots: '@swc/core': 1.3.92 esbuild: 0.18.20 + terser-webpack-plugin@5.3.10(@swc/core@1.3.92)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.31.6 + webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + optionalDependencies: + '@swc/core': 1.3.92 + terser-webpack-plugin@5.3.10(@swc/core@1.3.92)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -55643,9 +55825,9 @@ snapshots: text-table@0.2.0: {} - thingies@1.21.0(tslib@2.6.3): + thingies@1.21.0(tslib@2.7.0): dependencies: - tslib: 2.6.3 + tslib: 2.7.0 throttleit@1.0.0: {} @@ -55687,7 +55869,7 @@ snapshots: title-case@3.0.3: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 tmp@0.0.33: dependencies: @@ -55758,9 +55940,9 @@ snapshots: transformation-matrix@2.16.1: {} - tree-dump@1.0.2(tslib@2.6.3): + tree-dump@1.0.2(tslib@2.7.0): dependencies: - tslib: 2.6.3 + tslib: 2.7.0 tree-kill@1.2.2: {} @@ -55872,11 +56054,11 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.18.10) - ts-jest@29.1.5(@babel/core@7.23.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.0))(jest@29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@5.5.3)))(typescript@5.5.3): + ts-jest@29.1.5(@babel/core@7.23.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.0))(esbuild@0.18.20)(jest@29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.92)(@types/node@20.14.2)(typescript@5.5.3)))(typescript@5.5.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@5.5.3)) + jest: 29.7.0(@types/node@20.14.2)(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.92)(@types/node@20.14.2)(typescript@5.5.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -55889,6 +56071,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.23.0) + esbuild: 0.18.20 ts-jest@29.1.5(@babel/core@7.23.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.0))(jest@29.7.0(@types/node@22.5.2)(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.92)(@types/node@22.5.2)(typescript@5.5.3)))(typescript@5.5.3): dependencies: @@ -56527,11 +56710,11 @@ snapshots: upper-case-first@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 upper-case@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.7.0 uri-js@4.4.1: dependencies: @@ -56587,7 +56770,7 @@ snapshots: use-callback-ref@1.3.0(@types/react@17.0.21)(react@17.0.2): dependencies: react: 17.0.2 - tslib: 2.6.2 + tslib: 2.7.0 optionalDependencies: '@types/react': 17.0.21 @@ -56618,7 +56801,7 @@ snapshots: dependencies: detect-node-es: 1.1.0 react: 17.0.2 - tslib: 2.6.2 + tslib: 2.7.0 optionalDependencies: '@types/react': 17.0.21 @@ -57027,7 +57210,7 @@ snapshots: '@peculiar/json-schema': 1.1.12 asn1js: 3.0.5 pvtsutils: 1.3.5 - tslib: 2.6.2 + tslib: 2.7.0 webidl-conversions@3.0.1: {} @@ -57142,6 +57325,16 @@ snapshots: optionalDependencies: webpack: 5.94.0(@swc/core@1.3.92)(esbuild@0.18.20) + webpack-dev-middleware@6.1.1(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))): + dependencies: + colorette: 2.0.20 + memfs: 3.5.1 + mime-types: 2.1.35 + range-parser: 1.2.1 + schema-utils: 4.2.0 + optionalDependencies: + webpack: 5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)) + webpack-dev-middleware@6.1.1(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0))): dependencies: colorette: 2.0.20 @@ -57441,6 +57634,38 @@ snapshots: - esbuild - uglify-js + webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0)): + dependencies: + '@types/estree': 1.0.5 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + acorn: 8.12.1 + acorn-import-attributes: 1.9.5(acorn@8.12.1) + browserslist: 4.23.3 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.17.1 + es-module-lexer: 1.5.4 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.10(@swc/core@1.3.92)(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0))) + watchpack: 2.4.2 + webpack-sources: 3.2.3 + optionalDependencies: + webpack-cli: 4.10.0(webpack-bundle-analyzer@4.10.2)(webpack-dev-server@4.15.1)(webpack@5.94.0) + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0(webpack-dev-server@4.15.1)(webpack@5.94.0)): dependencies: '@types/estree': 1.0.5 diff --git a/repo/graph.dot b/repo/graph.dot index 3e22c2ef251..1005d8fa43f 100644 --- a/repo/graph.dot +++ b/repo/graph.dot @@ -502,10 +502,13 @@ digraph G { "@kie-tools/runtime-tools-components" -> "@kie-tools/runtime-tools-shared-gateway-api" [ style = "solid", color = "blue" ]; "@kie-tools/runtime-tools-components" -> "@kie-tools/uniforms-patternfly" [ style = "solid", color = "blue" ]; "@kie-tools/runtime-tools-consoles-helm-chart" -> "@kie-tools/kogito-management-console" [ style = "solid", color = "black" ]; + "@kie-tools/runtime-tools-management-console-webapp" -> "@kie-tools-core/workspaces-git-fs" [ style = "solid", color = "blue" ]; "@kie-tools/runtime-tools-management-console-webapp" -> "@kie-tools/runtime-tools-process-webapp-components" [ style = "solid", color = "blue" ]; "@kie-tools/runtime-tools-management-console-webapp" -> "@kie-tools/runtime-tools-shared-webapp-components" [ style = "solid", color = "blue" ]; + "@kie-tools/runtime-tools-management-console-webapp" -> "@kie-tools/maven-base" [ style = "dashed", color = "blue" ]; "@kie-tools/runtime-tools-process-dev-ui-webapp" -> "@kie-tools/runtime-tools-process-webapp-components" [ style = "solid", color = "blue" ]; "@kie-tools/runtime-tools-process-dev-ui-webapp" -> "@kie-tools/runtime-tools-shared-webapp-components" [ style = "solid", color = "blue" ]; + "@kie-tools/runtime-tools-process-enveloped-components" -> "@kie-tools-core/react-hooks" [ style = "solid", color = "blue" ]; "@kie-tools/runtime-tools-process-enveloped-components" -> "@kie-tools/runtime-tools-process-gateway-api" [ style = "solid", color = "blue" ]; "@kie-tools/runtime-tools-process-enveloped-components" -> "@kie-tools/runtime-tools-shared-enveloped-components" [ style = "solid", color = "blue" ]; "@kie-tools/runtime-tools-process-gateway-api" -> "@kie-tools/runtime-tools-shared-gateway-api" [ style = "solid", color = "blue" ]; @@ -601,7 +604,6 @@ digraph G { "@kie-tools/sonataflow-management-console-image" -> "@kie-tools/sonataflow-management-console-image-env" [ style = "dashed", color = "black" ]; "@kie-tools/sonataflow-management-console-image" -> "@kie-tools/sonataflow-management-console-webapp" [ style = "dashed", color = "black" ]; "@kie-tools/sonataflow-management-console-image-env" -> "@kie-tools/root-env" [ style = "dashed", color = "black" ]; - "@kie-tools/sonataflow-management-console-webapp" -> "@kie-tools-core/react-hooks" [ style = "solid", color = "blue" ]; "@kie-tools/sonataflow-management-console-webapp" -> "@kie-tools/runtime-tools-process-webapp-components" [ style = "solid", color = "blue" ]; "@kie-tools/sonataflow-management-console-webapp" -> "@kie-tools/runtime-tools-shared-webapp-components" [ style = "solid", color = "blue" ]; "@kie-tools/sonataflow-management-console-webapp" -> "@kie-tools/runtime-tools-swf-webapp-components" [ style = "solid", color = "blue" ]; diff --git a/repo/graph.json b/repo/graph.json index 0f3378f7b52..5a47189f58d 100644 --- a/repo/graph.json +++ b/repo/graph.json @@ -479,6 +479,11 @@ "target": "@kie-tools/tsconfig", "weight": 1 }, + { + "source": "@kie-tools/runtime-tools-management-console-webapp", + "target": "@kie-tools-core/workspaces-git-fs", + "weight": 1 + }, { "source": "@kie-tools/runtime-tools-management-console-webapp", "target": "@kie-tools/runtime-tools-process-webapp-components", @@ -489,6 +494,11 @@ "target": "@kie-tools/runtime-tools-shared-webapp-components", "weight": 1 }, + { + "source": "@kie-tools/runtime-tools-management-console-webapp", + "target": "@kie-tools/maven-base", + "weight": 1 + }, { "source": "@kie-tools-examples/ping-pong-view", "target": "@kie-tools-core/envelope", @@ -2064,6 +2074,11 @@ "target": "@kie-tools/kogito-management-console", "weight": 1 }, + { + "source": "@kie-tools/runtime-tools-process-enveloped-components", + "target": "@kie-tools-core/react-hooks", + "weight": 1 + }, { "source": "@kie-tools/runtime-tools-process-enveloped-components", "target": "@kie-tools/runtime-tools-process-gateway-api", @@ -2459,11 +2474,6 @@ "target": "@kie-tools/root-env", "weight": 1 }, - { - "source": "@kie-tools/sonataflow-management-console-webapp", - "target": "@kie-tools-core/react-hooks", - "weight": 1 - }, { "source": "@kie-tools/sonataflow-management-console-webapp", "target": "@kie-tools/runtime-tools-process-webapp-components", From 7827bc1559ccf79c5dcd09f868ae2541aebba12e Mon Sep 17 00:00:00 2001 From: Tiago Bento Date: Fri, 22 Nov 2024 12:37:14 -0500 Subject: [PATCH 2/5] Prettifying impersonation on Management Console --- .../src/authSessions/AuthSessionApi.ts | 27 ++- .../src/navigation/Routes.ts | 8 +- .../src/runtime/RuntimeContext.tsx | 25 ++- .../src/styles.css | 7 + .../src/tasks/TaskDetails.tsx | 17 +- .../src/tasks/TaskDetailsPage.tsx | 6 +- .../src/tasks/TasksPage.tsx | 12 +- .../tasks/components/ImpersonationForm.tsx | 171 --------------- .../components/ImpersonationPageSection.tsx | 206 ++++++++++++++++++ .../server/server.js | 2 +- .../pages/TaskDetailsPage/TaskDetailsPage.tsx | 11 +- .../envelope/components/TaskDetails.tsx | 2 +- .../envelope/TaskFormEnvelopeView.tsx | 2 +- .../CustomTaskFormDisplayer.tsx | 2 +- .../envelope/components/TaskForm/TaskForm.tsx | 2 +- 15 files changed, 286 insertions(+), 214 deletions(-) delete mode 100644 packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationForm.tsx create mode 100644 packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationPageSection.tsx diff --git a/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionApi.ts b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionApi.ts index 01e4c35dbd3..5e1bcd69c15 100644 --- a/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionApi.ts +++ b/packages/runtime-tools-management-console-webapp/src/authSessions/AuthSessionApi.ts @@ -73,7 +73,7 @@ export type OpenIDConfiguration = { export enum AuthSessionType { OPENID_CONNECT = "oidc", - UNAUTHENTICATED = "unauthenticaded", + UNAUTHENTICATED = "unauthenticated", } export type OpenIDConnectAuthSession = { @@ -147,21 +147,38 @@ export function isUnauthenticatedAuthSession(authSession?: AuthSession): authSes return authSession?.type === AuthSessionType.UNAUTHENTICATED; } -export function getAuthSessionDisplayInfo(authSession: AuthSession) { +export function getAuthSessionDisplayInfo(authSession: undefined | AuthSession) { + authSession ??= { + id: "unknwon", + type: AuthSessionType.UNAUTHENTICATED, + version: 0, + name: "Unknown", + impersonator: true, + runtimeUrl: "", + status: AuthSessionStatus.INVALID, + createdAtDateISO: new Date().toISOString(), + }; + // username @ http://runtime.url const shortDisplayName = `${isOpenIdConnectAuthSession(authSession) ? `${authSession.username ?? "Unknown user"} @ ` : "Unknown user @ "}${authSession.runtimeUrl}`; - // Session Name [username @ http://runtime.url] + + // Session Name (username @ http://runtime.url) const fullDisplayName = `${authSession.name} (${shortDisplayName})`; + // username @ Auth Session Name const userFriendlyName = `${isOpenIdConnectAuthSession(authSession) ? `${authSession.username ?? "Unknown user"} @ ` : "Unknown user @ "}${authSession.name}`; - // OpenID Connect | Unauthenticaded - const type = isOpenIdConnectAuthSession(authSession) ? "OpenID Connect" : "Unauthenticaded"; + + // OpenID Connect | Unauthenticated + const type = isOpenIdConnectAuthSession(authSession) ? "OpenID Connect" : "Unauthenticated"; + + const username = `${isOpenIdConnectAuthSession(authSession) ? `${authSession.username ?? "Unknown user"}` : "Unknown user"}`; return { shortDisplayName, fullDisplayName, userFriendlyName, type, + username, }; } diff --git a/packages/runtime-tools-management-console-webapp/src/navigation/Routes.ts b/packages/runtime-tools-management-console-webapp/src/navigation/Routes.ts index 797e7951ba2..2f7c56f882f 100644 --- a/packages/runtime-tools-management-console-webapp/src/navigation/Routes.ts +++ b/packages/runtime-tools-management-console-webapp/src/navigation/Routes.ts @@ -17,8 +17,6 @@ * under the License. */ -import { LocationDescriptor } from "history"; - declare global { interface Window { BASE_PATH: string; @@ -33,7 +31,7 @@ export enum QueryParams { SORT_BY = "sort", ORDER_BY = "order", IMPERSONATION_USER = "impersonationUsername", - IMPERSONATION_GROUP = "impersonationGroup", + IMPERSONATION_GROUPS = "impersonationGroups", } export enum PathParams { @@ -155,12 +153,12 @@ export const routes = { | QueryParams.FILTERS | QueryParams.SORT_BY | QueryParams.IMPERSONATION_USER - | QueryParams.IMPERSONATION_GROUP; + | QueryParams.IMPERSONATION_GROUPS; }>(({ runtimeUrl }) => `/${runtimeUrl}/tasks`), taskDetails: new Route<{ pathParams: PathParams.RUNTIME_URL | PathParams.TASK_ID; - queryParams: QueryParams.USER | QueryParams.IMPERSONATION_USER | QueryParams.IMPERSONATION_GROUP; + queryParams: QueryParams.USER | QueryParams.IMPERSONATION_USER | QueryParams.IMPERSONATION_GROUPS; }>(({ runtimeUrl, taskId }) => `/${runtimeUrl}/task/${taskId}`), }, diff --git a/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeContext.tsx b/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeContext.tsx index d91cacd59cf..8f24e62c751 100644 --- a/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeContext.tsx +++ b/packages/runtime-tools-management-console-webapp/src/runtime/RuntimeContext.tsx @@ -64,7 +64,7 @@ export type RuntimeContextType = { isRefreshingToken: boolean; runtimePathSearchParams: Map; impersonationUsername?: string; - impersonationGroup?: string; + impersonationGroups?: string; }; export const RuntimeContext = createContext({} as RuntimeContextType); @@ -75,7 +75,7 @@ export type RuntimeDispatchContextType = { React.SetStateAction> >; setImpersonationUsername: React.Dispatch>; - setImpersonationGroup: React.Dispatch>; + setImpersonationGroups: React.Dispatch>; }; export const RuntimeDispatchContext = createContext({} as RuntimeDispatchContextType); @@ -101,14 +101,14 @@ export const RuntimeContextProvider: React.FC = (pr const routes = useRoutes(); const user = useQueryParam(QueryParams.USER); const impersonationUsernameQueryParam = useQueryParam(QueryParams.IMPERSONATION_USER); - const impersonationGroupQueryParam = useQueryParam(QueryParams.IMPERSONATION_GROUP); + const impersonationGroupsQueryParam = useQueryParam(QueryParams.IMPERSONATION_GROUPS); const queryParams = useQueryParams(); const [runtimeUrl, setRuntimeUrl] = useState(); const [username, setUsername] = useState(); const [impersonationUsername, setImpersonationUsername] = useState( impersonationUsernameQueryParam ); - const [impersonationGroup, setImpersonationGroup] = useState(impersonationGroupQueryParam); + const [impersonationGroups, setImpersonationGroups] = useState(impersonationGroupsQueryParam); const [accessToken, setAccessToken] = useState(); const [apolloClient, setApolloClient] = useState>(); const [userContext, setUserContext] = useState(); @@ -327,8 +327,8 @@ export const RuntimeContextProvider: React.FC = (pr }, [createApolloClient, runtimeUrl, accessToken]); useEffect(() => { - setUserContext(createUserContext(username, impersonationUsername, impersonationGroup)); - }, [createUserContext, username, impersonationUsername, impersonationGroup]); + setUserContext(createUserContext(username, impersonationUsername, impersonationGroups)); + }, [createUserContext, username, impersonationUsername, impersonationGroups]); const value = useMemo( () => ({ @@ -339,7 +339,7 @@ export const RuntimeContextProvider: React.FC = (pr isRefreshingToken, runtimePathSearchParams, impersonationUsername, - impersonationGroup, + impersonationGroups, }), [ apolloClient, @@ -349,12 +349,17 @@ export const RuntimeContextProvider: React.FC = (pr isRefreshingToken, runtimePathSearchParams, impersonationUsername, - impersonationGroup, + impersonationGroups, ] ); const dispatch = useMemo( - () => ({ refreshToken, setRuntimePathSearchParams, setImpersonationUsername, setImpersonationGroup }), + () => ({ + refreshToken, + setRuntimePathSearchParams, + setImpersonationUsername, + setImpersonationGroups, + }), [refreshToken, setRuntimePathSearchParams] ); @@ -411,7 +416,7 @@ export function useRuntimeInfo() { return currentAuthSession.tokens.access_token; }, [currentAuthSession]); - const canImpersonate = useMemo(() => currentAuthSession?.impersonator, [currentAuthSession?.impersonator]); + const canImpersonate = useMemo(() => currentAuthSession?.impersonator ?? false, [currentAuthSession?.impersonator]); return useMemo( () => ({ runtimeUrl, username, accessToken, runtimeDisplayInfo, isRefreshingToken, canImpersonate }), diff --git a/packages/runtime-tools-management-console-webapp/src/styles.css b/packages/runtime-tools-management-console-webapp/src/styles.css index d81a1e4df80..640b4cd6362 100644 --- a/packages/runtime-tools-management-console-webapp/src/styles.css +++ b/packages/runtime-tools-management-console-webapp/src/styles.css @@ -88,3 +88,10 @@ .kogito-consoles-common--PageLayout .pf-c-page__header-brand-link .pf-c-brand { --pf-c-page__header-brand-link--c-brand--MaxHeight: 42px; } + +.kogito-management-console__impersonation-hint { + width: 100%; + padding: 0; + margin-bottom: 24px; + border-radius: 16px; +} diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetails.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetails.tsx index 5c356eddbd9..eacbf522a74 100644 --- a/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetails.tsx +++ b/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetails.tsx @@ -51,10 +51,9 @@ import { UserTaskInstance } from "@kie-tools/runtime-tools-process-gateway-api/d import { TaskState } from "@kie-tools/runtime-tools-process-enveloped-components/dist/taskDetails"; import { TaskForm } from "./TaskForm"; import { FormNotification, Notification } from "./components"; -import { useRuntimeDispatch, useRuntimeInfo, useRuntimeSpecificRoutes } from "../runtime/RuntimeContext"; +import { useRuntime, useRuntimeDispatch, useRuntimeInfo, useRuntimeSpecificRoutes } from "../runtime/RuntimeContext"; import { useCancelableEffect } from "@kie-tools-core/react-hooks/dist/useCancelableEffect"; import { isOpenIdConnectAuthSession, useAuthSessions } from "../authSessions"; -import { Divider } from "@patternfly/react-core/dist/js/components/Divider"; interface Props { taskId?: string; @@ -65,6 +64,7 @@ export const TaskDetails: React.FC = ({ taskId }) => { const history = useHistory(); const runtimeRoutes = useRuntimeSpecificRoutes(); const { username, accessToken } = useRuntimeInfo(); + const { impersonationUsername } = useRuntime(); const { currentAuthSession } = useAuthSessions(); const { refreshToken } = useRuntimeDispatch(); const [isLoading, setIsLoading] = useState(true); @@ -88,8 +88,13 @@ export const TaskDetails: React.FC = ({ taskId }) => { return; } setUserTask(taskData); - if (username && !taskData?.potentialUsers?.includes(username)) { + if ( + (username && !taskData?.potentialUsers?.includes(username)) || + (!(username || impersonationUsername) && (taskData?.potentialUsers?.length ?? 0) > 0) + ) { setIsDetailsExpanded(true); + } else { + setIsDetailsExpanded(false); } }) .catch((e) => { @@ -100,7 +105,7 @@ export const TaskDetails: React.FC = ({ taskId }) => { setIsLoading(false); }); }, - [taskId, taskInboxGatewayApi, username] + [impersonationUsername, taskId, taskInboxGatewayApi, username] ) ); @@ -205,8 +210,8 @@ export const TaskDetails: React.FC = ({ taskId }) => { diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetailsPage.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetailsPage.tsx index 0bede2391fb..4e003255970 100644 --- a/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetailsPage.tsx +++ b/packages/runtime-tools-management-console-webapp/src/tasks/TaskDetailsPage.tsx @@ -24,7 +24,7 @@ import { useEnv } from "../env/hooks/EnvContext"; import { useRoutes } from "../navigation/Hooks"; import { TaskDetails } from "./TaskDetails"; import { useRuntimePageLayoutDispatch } from "../runtime/RuntimePageLayoutContext"; -import { ImpersonationForm } from "./components/ImpersonationForm"; +import { ImpersonationPageSection } from "./components/ImpersonationPageSection"; interface Props { taskId?: string; @@ -63,7 +63,6 @@ export const TaskDetailsPage: React.FC = ({ taskId }) => { }, [history, onNavigateToTaskDetails, setOnSelectAuthSession]); useEffect(() => { - setCurrentPageTitle("Task"); setBreadcrumbText(["Home", runtimeDisplayInfo?.fullDisplayName ?? "Runtime", "Tasks", taskId ?? ""]); setBreadcrumbPath([ routes.home.path({}), @@ -73,7 +72,6 @@ export const TaskDetailsPage: React.FC = ({ taskId }) => { ]); return () => { - setCurrentPageTitle(""); setBreadcrumbText([]); setBreadcrumbPath([]); }; @@ -89,7 +87,7 @@ export const TaskDetailsPage: React.FC = ({ taskId }) => { return ( <> - + ); diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/TasksPage.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/TasksPage.tsx index 494215b8a34..1268f1fc892 100644 --- a/packages/runtime-tools-management-console-webapp/src/tasks/TasksPage.tsx +++ b/packages/runtime-tools-management-console-webapp/src/tasks/TasksPage.tsx @@ -25,7 +25,7 @@ import { useHistory } from "react-router"; import { useRoutes } from "../navigation/Hooks"; import { AuthSession, useAuthSessionsDispatch } from "../authSessions"; import { useRuntimePageLayoutDispatch } from "../runtime/RuntimePageLayoutContext"; -import { ImpersonationForm } from "./components/ImpersonationForm"; +import { ImpersonationPageSection } from "./components/ImpersonationPageSection"; export const TasksPage: React.FC = (ouiaId, ouiaSafe) => { const { env } = useEnv(); @@ -77,9 +77,11 @@ export const TasksPage: React.FC = (ouiaId, ouiaSafe) => { ); return ( - - - - + <> + + + + + ); }; diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationForm.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationForm.tsx deleted file mode 100644 index 01798fa84f2..00000000000 --- a/packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationForm.tsx +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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, { useCallback, useEffect, useState } from "react"; -import { FormGroup } from "@patternfly/react-core/dist/js/components/Form"; -import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput"; -import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button"; -import { - RuntimePathSearchParamsRoutes, - useRuntime, - useRuntimeDispatch, - useRuntimeInfo, -} from "../../runtime/RuntimeContext"; -import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex"; -import { QueryParams } from "../../navigation/Routes"; -import { useQueryParams } from "../../navigation/queryParams/QueryParamsContext"; -import { useHistory } from "react-router"; - -export const ImpersonationForm: React.FC = () => { - const { impersonationUsername, impersonationGroup } = useRuntime(); - const { canImpersonate } = useRuntimeInfo(); - const queryParams = useQueryParams(); - const history = useHistory(); - const { setImpersonationUsername, setImpersonationGroup, setRuntimePathSearchParams } = useRuntimeDispatch(); - const [username, setUsername] = useState(); - const [group, setGroup] = useState(); - - useEffect(() => { - setUsername(impersonationUsername); - setGroup(impersonationGroup); - }, [impersonationGroup, impersonationUsername]); - - const onClear = useCallback(() => { - setUsername(undefined); - setGroup(undefined); - setImpersonationUsername(undefined); - setImpersonationGroup(undefined); - const newQueryParams = { - [QueryParams.IMPERSONATION_USER]: undefined, - [QueryParams.IMPERSONATION_GROUP]: undefined, - }; - - setRuntimePathSearchParams((currentRuntimePathSearchParams) => { - const tasksNewSearchParams = { - ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASKS), - ...newQueryParams, - }; - const taskDetailsNewSearchParams = { - ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASK_DETAILS), - ...newQueryParams, - }; - currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASKS, tasksNewSearchParams); - currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASK_DETAILS, taskDetailsNewSearchParams); - - return new Map(currentRuntimePathSearchParams); - }); - history.replace({ - pathname: history.location.pathname, - search: queryParams - .with(QueryParams.IMPERSONATION_USER, newQueryParams[QueryParams.IMPERSONATION_USER]) - .with(QueryParams.IMPERSONATION_GROUP, newQueryParams[QueryParams.IMPERSONATION_GROUP]) - .toString(), - }); - }, [history, queryParams, setImpersonationGroup, setImpersonationUsername, setRuntimePathSearchParams]); - - const onApply = useCallback(() => { - setImpersonationUsername(username); - setImpersonationGroup(group); - const newQueryParams = { - [QueryParams.IMPERSONATION_USER]: username, - [QueryParams.IMPERSONATION_GROUP]: group, - }; - - setRuntimePathSearchParams((currentRuntimePathSearchParams) => { - const tasksNewSearchParams = { - ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASKS), - ...newQueryParams, - }; - const taskDetailsNewSearchParams = { - ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASK_DETAILS), - ...newQueryParams, - }; - currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASKS, tasksNewSearchParams); - currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASK_DETAILS, taskDetailsNewSearchParams); - - return new Map(currentRuntimePathSearchParams); - }); - history.replace({ - pathname: history.location.pathname, - search: queryParams - .with(QueryParams.IMPERSONATION_USER, newQueryParams[QueryParams.IMPERSONATION_USER]) - .with(QueryParams.IMPERSONATION_GROUP, newQueryParams[QueryParams.IMPERSONATION_GROUP]) - .toString(), - }); - }, [ - group, - history, - queryParams, - setImpersonationGroup, - setImpersonationUsername, - setRuntimePathSearchParams, - username, - ]); - - useEffect(() => { - if (!canImpersonate) { - onClear(); - } - }, [canImpersonate, onClear]); - - return canImpersonate ? ( - - -
Impersonation:
-
- - - - - - - - - - - - - - - - - -
- ) : ( - <> - ); -}; diff --git a/packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationPageSection.tsx b/packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationPageSection.tsx new file mode 100644 index 00000000000..19ee18f48f0 --- /dev/null +++ b/packages/runtime-tools-management-console-webapp/src/tasks/components/ImpersonationPageSection.tsx @@ -0,0 +1,206 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { Hint } from "@patternfly/react-core/dist/esm/components/Hint"; +import { Button, ButtonType, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button"; +import { + ActionGroup, + Form, + FormFieldGroupExpandable, + FormFieldGroupHeader, + FormGroup, +} from "@patternfly/react-core/dist/js/components/Form"; +import { PageSection } from "@patternfly/react-core/dist/js/components/Page"; +import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput"; +import UserTagIcon from "@patternfly/react-icons/dist/esm/icons/user-tag-icon"; +import UserIcon from "@patternfly/react-icons/dist/js/icons/user-icon"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { useHistory } from "react-router"; +import { AuthSessionType, getAuthSessionDisplayInfo, useAuthSession, useAuthSessions } from "../../authSessions"; +import { QueryParams } from "../../navigation/Routes"; +import { useQueryParams } from "../../navigation/queryParams/QueryParamsContext"; +import { + RuntimePathSearchParamsRoutes, + useRuntime, + useRuntimeDispatch, + useRuntimeInfo, +} from "../../runtime/RuntimeContext"; + +export const ImpersonationPageSection: React.FC<{}> = () => { + const { impersonationUsername, impersonationGroups } = useRuntime(); + const { canImpersonate } = useRuntimeInfo(); + const queryParams = useQueryParams(); + const history = useHistory(); + + const { + setImpersonationUsername, + setImpersonationGroups: setImpersonationGroup, + setRuntimePathSearchParams, + } = useRuntimeDispatch(); + + const [username, setUsername] = useState(); + const [groups, setGroups] = useState(); + + useEffect(() => { + console.log(impersonationUsername); + console.log(impersonationGroups); + setUsername((prev) => prev || impersonationUsername); + setGroups((prev) => prev || impersonationGroups); + }, [impersonationGroups, impersonationUsername]); + + const impersonate = useCallback( + (u: string | undefined, g: string | undefined) => { + setImpersonationUsername(u); + setImpersonationGroup(g); + + const newQueryParams = { + [QueryParams.IMPERSONATION_USER]: u, + [QueryParams.IMPERSONATION_GROUPS]: g, + }; + + setRuntimePathSearchParams((currentRuntimePathSearchParams) => { + currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASKS, { + ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASKS), + ...newQueryParams, + }); + currentRuntimePathSearchParams.set(RuntimePathSearchParamsRoutes.TASK_DETAILS, { + ...currentRuntimePathSearchParams.get(RuntimePathSearchParamsRoutes.TASK_DETAILS), + ...newQueryParams, + }); + + return new Map(currentRuntimePathSearchParams); + }); + + history.replace({ + pathname: history.location.pathname, + search: queryParams + .with(QueryParams.IMPERSONATION_USER, newQueryParams[QueryParams.IMPERSONATION_USER]) + .with(QueryParams.IMPERSONATION_GROUPS, newQueryParams[QueryParams.IMPERSONATION_GROUPS]) + .toString(), + }); + }, + [history, queryParams, setImpersonationGroup, setImpersonationUsername, setRuntimePathSearchParams] + ); + + const onClear = useCallback(() => { + setUsername(undefined); + setGroups(undefined); + impersonate(undefined, undefined); + }, [impersonate]); + + const onApply = useCallback( + (e: React.FormEvent) => { + e.stopPropagation(); + e.preventDefault(); + impersonate(username, groups); + }, + [groups, impersonate, username] + ); + + useEffect(() => { + if (!canImpersonate) { + onClear(); + } + }, [canImpersonate, onClear]); + + const { currentAuthSession } = useAuthSessions(); + const authSessionInfo = useMemo(() => getAuthSessionDisplayInfo(currentAuthSession), [currentAuthSession]); + + return canImpersonate ? ( + + + + + {impersonationUsername + ? `Viewing and completing Tasks as '${impersonationUsername}'` + : `View and complete Tasks as if you were another user`} + + } + titleText={{ + id: "impersonation-hint", + text: impersonationUsername ? ( + <> + +   + {`Impersonating '${impersonationUsername}'`} + + ) : ( + <> + +   + {`Impersonate`} + + ), + }} + /> + } + > + + + + + + + + + + + + + + + ) : ( + <> + ); +}; diff --git a/packages/runtime-tools-process-dev-ui-webapp/server/server.js b/packages/runtime-tools-process-dev-ui-webapp/server/server.js index acdf370be6a..8cc617e7799 100644 --- a/packages/runtime-tools-process-dev-ui-webapp/server/server.js +++ b/packages/runtime-tools-process-dev-ui-webapp/server/server.js @@ -504,7 +504,7 @@ const resolvers = { await timeout(2000); if (args.where.id && taskDetailsError.includes(args.where.id.equal)) { - throw new Error(`Cannot find task ${args.where.id.equal}`); + throw new Error(`Cannot find Task ${args.where.id.equal}`); } if (args.pagination) { const offset = args.pagination.offset; diff --git a/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx b/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx index 0eadc482a88..7d6a0cc5843 100644 --- a/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx +++ b/packages/runtime-tools-process-dev-ui-webapp/src/components/pages/TaskDetailsPage/TaskDetailsPage.tsx @@ -81,8 +81,13 @@ const TaskDetailsPage: React.FC & OUIAProps> = ({ oui try { const task = await taskInboxGatewayApi.getTaskById(taskId); setUserTask(task); - if (appContext.getCurrentUser()?.id && !task?.potentialUsers?.includes(appContext.getCurrentUser()?.id)) { + if ( + (appContext.getCurrentUser().id && !task?.potentialUsers?.includes(appContext.getCurrentUser()?.id)) || + (!appContext.getCurrentUser().id && (task?.potentialUsers?.length ?? 0) > 0) + ) { setIsDetailsExpanded(true); + } else { + setIsDetailsExpanded(false); } } catch (err) { setError(err); @@ -180,8 +185,8 @@ const TaskDetailsPage: React.FC & OUIAProps> = ({ oui diff --git a/packages/runtime-tools-process-enveloped-components/src/taskDetails/envelope/components/TaskDetails.tsx b/packages/runtime-tools-process-enveloped-components/src/taskDetails/envelope/components/TaskDetails.tsx index 2f4c17215a8..acb3c12c49a 100755 --- a/packages/runtime-tools-process-enveloped-components/src/taskDetails/envelope/components/TaskDetails.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/taskDetails/envelope/components/TaskDetails.tsx @@ -35,7 +35,7 @@ export const TaskDetails: React.FC = ({ userTask, return ( ); } diff --git a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/TaskFormEnvelopeView.tsx b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/TaskFormEnvelopeView.tsx index f5bf7553e23..1ef21f93ae9 100644 --- a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/TaskFormEnvelopeView.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/TaskFormEnvelopeView.tsx @@ -113,7 +113,7 @@ export const TaskFormEnvelopeView = React.forwardRef - + ); } diff --git a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/CustomTaskFormDisplayer/CustomTaskFormDisplayer.tsx b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/CustomTaskFormDisplayer/CustomTaskFormDisplayer.tsx index 19435dffa90..ad5ed5952fc 100644 --- a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/CustomTaskFormDisplayer/CustomTaskFormDisplayer.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/CustomTaskFormDisplayer/CustomTaskFormDisplayer.tsx @@ -116,7 +116,7 @@ const CustomTaskFormDisplayer: React.FC - + )} diff --git a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/TaskForm/TaskForm.tsx b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/TaskForm/TaskForm.tsx index 46ddaadbfff..9a16b68eddd 100644 --- a/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/TaskForm/TaskForm.tsx +++ b/packages/runtime-tools-process-enveloped-components/src/taskForm/envelope/components/TaskForm/TaskForm.tsx @@ -97,7 +97,7 @@ export const TaskForm: React.FC = ({ userTask, schema if (!taskFormSchema) { return ( - + ); } From c61d1a98fa18c606837291f414a0f8a0ddd96679 Mon Sep 17 00:00:00 2001 From: Tiago Bento Date: Mon, 25 Nov 2024 16:48:03 -0500 Subject: [PATCH 3/5] Fix dependencies consistency --- .../package.json | 2 +- pnpm-lock.yaml | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/runtime-tools-management-console-webapp/package.json b/packages/runtime-tools-management-console-webapp/package.json index 27cbe4e4ccc..ebce99fffa0 100644 --- a/packages/runtime-tools-management-console-webapp/package.json +++ b/packages/runtime-tools-management-console-webapp/package.json @@ -85,7 +85,7 @@ "cors": "^2.8.5", "css-loader": "^5.2.6", "css-minimizer-webpack-plugin": "^5.0.1", - "express": "^4.21.0", + "express": "^4.21.1", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.3.2", "https-browserify": "^1.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3e99038592a..c5d6168faa0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7742,7 +7742,7 @@ importers: specifier: ^5.0.1 version: 5.0.1(webpack@5.94.0(@swc/core@1.3.92)(webpack-cli@4.10.0)) express: - specifier: ^4.21.0 + specifier: ^4.21.1 version: 4.21.1 file-loader: specifier: ^6.2.0 @@ -36388,7 +36388,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.9 '@babel/types': 7.23.9 - debug: 4.3.5 + debug: 4.3.6 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -36418,7 +36418,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.9 '@babel/types': 7.23.9 - debug: 4.3.5 + debug: 4.3.6 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -36504,7 +36504,7 @@ snapshots: is-typedarray: 1.0.0 isstream: 0.1.2 json-stringify-safe: 5.0.1 - mime-types: 2.1.34 + mime-types: 2.1.35 performance-now: 2.1.0 qs: 6.10.4 safe-buffer: 5.2.1 @@ -37882,7 +37882,7 @@ snapshots: '@koa/router@10.1.1': dependencies: - debug: 4.3.5 + debug: 4.3.6 http-errors: 1.8.1 koa-compose: 4.1.0 methods: 1.1.2 @@ -40408,7 +40408,7 @@ snapshots: '@storybook/client-logger': 7.4.6 '@storybook/core-events': 7.4.6 '@storybook/global': 5.0.0 - qs: 6.11.2 + qs: 6.13.0 telejson: 7.2.0 tiny-invariant: 1.3.1 @@ -41584,7 +41584,7 @@ snapshots: dependencies: '@storybook/client-logger': 7.4.6 memoizerific: 1.11.3 - qs: 6.11.2 + qs: 6.13.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) @@ -48260,7 +48260,7 @@ snapshots: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 - mime-types: 2.1.34 + mime-types: 2.1.35 formdata-polyfill@4.0.10: dependencies: @@ -49019,7 +49019,7 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.5 + debug: 4.3.6 transitivePeerDependencies: - supports-color @@ -49118,7 +49118,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.5 + debug: 4.3.6 transitivePeerDependencies: - supports-color @@ -51021,7 +51021,7 @@ snapshots: koa-mount@4.0.0: dependencies: - debug: 4.3.5 + debug: 4.3.6 koa-compose: 4.1.0 transitivePeerDependencies: - supports-color @@ -51048,7 +51048,7 @@ snapshots: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.8.0 - debug: 4.3.5 + debug: 4.3.6 delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -53414,7 +53414,7 @@ snapshots: qs@6.11.0: dependencies: - side-channel: 1.0.4 + side-channel: 1.0.6 qs@6.11.2: dependencies: @@ -55310,7 +55310,7 @@ snapshots: has-symbols: 1.0.3 internal-slot: 1.0.7 regexp.prototype.flags: 1.5.2 - side-channel: 1.0.4 + side-channel: 1.0.6 string.prototype.trim@1.2.9: dependencies: From 091fe74450c81d3ad090dd5b00bd6d0540a03b73 Mon Sep 17 00:00:00 2001 From: Thiago Lugli Date: Wed, 8 Jan 2025 19:10:03 -0300 Subject: [PATCH 4/5] Fix PageSectionHeader --- .../common/components/PageSectionHeader/PageSectionHeader.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-tools-components/src/common/components/PageSectionHeader/PageSectionHeader.tsx b/packages/runtime-tools-components/src/common/components/PageSectionHeader/PageSectionHeader.tsx index 98a8451a8b5..0b228b677ad 100644 --- a/packages/runtime-tools-components/src/common/components/PageSectionHeader/PageSectionHeader.tsx +++ b/packages/runtime-tools-components/src/common/components/PageSectionHeader/PageSectionHeader.tsx @@ -25,7 +25,7 @@ import { PageTitle } from "../PageTitle"; import { componentOuiaProps, OUIAProps } from "../../ouiaTools"; import * as H from "history"; -type pathType = Pick; +type pathType = Pick | H.LocationDescriptor; interface PageSectionHeaderProps { titleText: string; breadcrumbText?: string[]; From a8cb3689e8f9d8043cbb0dbea7fbc68a6e391618 Mon Sep 17 00:00:00 2001 From: Thiago Lugli Date: Thu, 9 Jan 2025 12:31:46 -0300 Subject: [PATCH 5/5] License headers --- .../resources/META-INF/processSVG/hiring.svg | 18 ++++++++++++++++++ .../src/main/resources/NewHiringOffer.dmn | 18 ++++++++++++++++++ .../src/main/resources/hiring.bpmn | 18 ++++++++++++++++++ .../resources/META-INF/processSVG/hiring.svg | 18 ++++++++++++++++++ .../src/main/resources/NewHiringOffer.dmn | 18 ++++++++++++++++++ .../src/main/resources/hiring.bpmn | 18 ++++++++++++++++++ .../images/app_logo_rgb_fullcolor_default.svg | 18 ++++++++++++++++++ .../images/app_logo_rgb_fullcolor_reverse.svg | 18 ++++++++++++++++++ 8 files changed, 144 insertions(+) diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/META-INF/processSVG/hiring.svg b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/META-INF/processSVG/hiring.svg index 37c2237d5ca..50ae8cf0e65 100644 --- a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/META-INF/processSVG/hiring.svg +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/META-INF/processSVG/hiring.svg @@ -6,6 +6,24 @@ height="521" viewBox="0 0 1575 521" > + diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/NewHiringOffer.dmn b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/NewHiringOffer.dmn index dd172b5ce80..b83903143ac 100644 --- a/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/NewHiringOffer.dmn +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/secured-runtime/src/main/resources/NewHiringOffer.dmn @@ -1,4 +1,22 @@ + + + diff --git a/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/NewHiringOffer.dmn b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/NewHiringOffer.dmn index dd172b5ce80..b83903143ac 100644 --- a/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/NewHiringOffer.dmn +++ b/packages/runtime-tools-management-console-webapp/dev-webapp/unsecured-runtime/src/main/resources/NewHiringOffer.dmn @@ -1,4 +1,22 @@ + + + +