From cf03635edb9f61960511a9f33f4ee5669b5e6d87 Mon Sep 17 00:00:00 2001 From: "fabio.d.mota" Date: Tue, 7 May 2024 14:45:24 +0100 Subject: [PATCH 1/2] fix(frontend): Unify frontend with new page and style css --- CHANGELOG.md | 22 ++ backend/pom.xml | 2 +- frontend/package-lock.json | 335 ++++-------------- frontend/package.json | 19 +- frontend/public/index.html | 4 +- frontend/src/App.js | 7 + .../dashboard/CountryPicker/CountryPicker.js | 54 +-- .../dashboard/CountryPicker/styles.scss | 4 + .../DashBoardTable/DashboardTable.js | 33 +- .../dashboard/DashBoardTable/styles.scss | 6 - .../dashboard/DashBoardTable/tableColumns.js | 21 +- .../dashboard/DatePicker/DatePicker.js | 4 +- .../DeleteUpdateComponent.js | 7 +- .../DeleteUpdateComponent/styles.scss | 2 +- .../dashboard/GatePicker/GatePicker.js | 4 +- .../components/dashboard/LeftMap/LeftMap.js | 4 +- .../components/dashboard/LeftMap/styles.scss | 3 +- .../DialogContent/DialogHelpContent.js | 226 ++++++------ .../dashboard/NavigationBar/NavigationBar.js | 12 +- .../NavigationBar/UserInformation/UserInfo.js | 53 +-- .../UserInformation/UserInfo.scss | 6 +- .../dashboard/NavigationBar/styles.scss | 7 +- .../NegotiationPage/NegotiationPage.js | 215 +++++++++++ .../NegotiationPage/NegotiationPage.scss | 54 +++ .../dashboard/ProgressBar/styles.scss | 7 + .../dashboard/RangeSlider/RangeSlider.js | 38 +- .../components/dashboard/Ratings/Ratings.js | 122 ++++--- .../dashboard/Ratings/ratingUserColumns.js | 42 +-- .../components/dashboard/Ratings/styles.scss | 18 +- .../components/dashboard/Reports/Reports.js | 107 +++--- .../components/dashboard/Reports/styles.scss | 29 +- .../components/dashboard/RightMap/RightMap.js | 2 +- .../components/dashboard/RightMap/styles.scss | 5 +- .../dashboard/ShareReport/ShareReport.js | 39 +- .../dashboard/ShareReport/styles.scss | 46 +-- .../src/components/dashboard/SignOut/index.js | 26 ++ .../DropZoneComponent/DropZone.js | 153 ++++++++ .../UploadDownloadZone/UploadDownloadZone.js | 169 ++++----- .../UploadDownloadZone/dialog-upload.scss | 2 +- frontend/src/components/dashboard/styles.scss | 4 +- .../components/services/EnvironmentService.js | 6 +- .../src/components/services/UserService.js | 3 - .../src/components/services/negotiation.js | 62 ++++ .../src/components/services/upload-api.js | 45 +++ frontend/src/index.js | 4 +- 45 files changed, 1222 insertions(+), 811 deletions(-) create mode 100644 frontend/src/components/dashboard/NegotiationPage/NegotiationPage.js create mode 100644 frontend/src/components/dashboard/NegotiationPage/NegotiationPage.scss create mode 100644 frontend/src/components/dashboard/SignOut/index.js create mode 100644 frontend/src/components/dashboard/UploadDownloadZone/DropZoneComponent/DropZone.js create mode 100644 frontend/src/components/services/negotiation.js create mode 100644 frontend/src/components/services/upload-api.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae48c71..ffe76fa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,28 @@ All notable changes to this project (both backend and frontend) will be document The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.0] - [unreleased] + +### Frontend + +#### Added +- Create `NegotiationPage` component to provide a user interface for triggering negotiations, displaying negotiation statuses, and managing catalog items. +- Implement `fetchCatalogItems` and `triggerNegotiation` service functions to interact with backend endpoints for retrieving catalog items and initiating negotiations. +- Introduce dynamic status icons in the negotiation table to reflect the real-time status of each negotiation, enhancing user feedback and interaction. +- Added SnackBar for Report Table and Ratings for error and success messages + + +### Changed +- Update `UserInfo` component to conditionally display the negotiation page link in the user menu based on user roles, enhancing role-based access control. +- Modify the negotiation initiation process to reset item statuses to "Pending" before sending requests, providing clearer feedback on ongoing negotiations. +- Refine error handling in the negotiation process to alert users of failures and log errors for debugging purposes. + +### Fixed +- Resolve visual feedback issue where status icons would not reset to default state after re-initiating negotiations. +- Update Report and Table components from catena-x lib +- Configure css with new update components + + ## [1.3.2] - [2024-04-17] ### Backend diff --git a/backend/pom.xml b/backend/pom.xml index 08522a01..222c4e43 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -28,7 +28,7 @@ org.eclipse.tractusx value-added-service - 1.3.2 + 2.0.0 vas-country-risk-backend Project to Validate Country Risks Score diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 45a758c3..a342501b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,20 +1,19 @@ { "name": "dashboard-app", - "version": "1.3.1", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dashboard-app", - "version": "1.3.1", + "version": "2.0.0", "license": "Apache-2.0", "dependencies": { - "@catena-x/portal-shared-components": "2.1.30", + "@catena-x/portal-shared-components": "^2.1.40", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@mui/icons-material": "5.10.6", "@mui/types": "7.2.5", - "@mui/x-data-grid": "5.17.26", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "14.1.0", "@testing-library/user-event": "^14.5.1", @@ -32,24 +31,20 @@ "keycloak-js": "20.0.5", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-dropzone": "^14.2.3", "react-scripts": "^5.0.1", "react-simple-maps": "^3.0.0", "react-svg-worldmap": "^2.0.0-alpha.16", "react-test-renderer": "^18.2.0", - "react-tooltip": "4.2.21", - "web-vitals": "^3.5.0", - "webpack": "5.89.0" + "react-tooltip": "4.2.21" }, "devDependencies": { - "@adobe/css-tools": ">=4.3.2", "@babel/core": "^7.24.4", "@babel/preset-env": "^7.23.3", "@babel/preset-react": "^7.23.3", "babel-jest": "^29.7.0", "follow-redirects": ">=1.15.4", - "jsdom": "22.0.0", - "postcss": "^8.4.38", - "sass": "^1.69.5" + "postcss": "^8.4.31" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -61,8 +56,7 @@ }, "node_modules/@adobe/css-tools": { "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz", - "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==" + "license": "MIT" }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", @@ -1869,9 +1863,9 @@ "license": "MIT" }, "node_modules/@catena-x/portal-shared-components": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/@catena-x/portal-shared-components/-/portal-shared-components-2.1.30.tgz", - "integrity": "sha512-BHO/2OOUihdOAA/Uql+s/VUBfl9ToHVQRL8mFMXhb9DuYPi213+LDXP3422sGLNQrlzIdCdD2U6yRHh8CVMlEQ==", + "version": "2.1.40", + "resolved": "https://registry.npmjs.org/@catena-x/portal-shared-components/-/portal-shared-components-2.1.40.tgz", + "integrity": "sha512-Zlw/sobpzF96fI4A0DcLoibIP4M7sIY1AY4eEgnJ2+i6Ux0ZsSzYHt/9HVrUKNpI7SpVPDHaiXjn0JHUc/k8cg==", "dependencies": { "@mui/base": "^5.0.0-beta.3", "@mui/system": "^5.13.2", @@ -1925,8 +1919,7 @@ }, "node_modules/@catena-x/portal-shared-components/node_modules/@mui/x-data-grid": { "version": "6.18.4", - "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-6.18.4.tgz", - "integrity": "sha512-uiinfqioCRoesUlJF3gvh67Ja3TrJJvPRTu4Gkf/RQBjr0BDNQ8BJrnuffqD8D/0SVUiqRZvcrjtgG1BIyjKRw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.2", "@mui/utils": "^5.14.16", @@ -3198,8 +3191,7 @@ }, "node_modules/@mui/private-theming": { "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.20.tgz", - "integrity": "sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.4", "@mui/utils": "^5.14.20", @@ -3224,8 +3216,7 @@ }, "node_modules/@mui/styled-engine": { "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.20.tgz", - "integrity": "sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.4", "@emotion/cache": "^11.11.0", @@ -3255,8 +3246,7 @@ }, "node_modules/@mui/system": { "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.20.tgz", - "integrity": "sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.4", "@mui/private-theming": "^5.14.20", @@ -3294,8 +3284,7 @@ }, "node_modules/@mui/system/node_modules/@mui/types": { "version": "7.2.12", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.12.tgz", - "integrity": "sha512-3kaHiNm9khCAo0pVe0RenketDSFoZGAlVZ4zDjB/QNZV0XiCj+sh1zkX0VVhQPgYJDlBEzAag+MHJ1tU3vf0Zw==", + "license": "MIT", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" }, @@ -3307,8 +3296,7 @@ }, "node_modules/@mui/system/node_modules/clsx": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "license": "MIT", "engines": { "node": ">=6" } @@ -4262,15 +4250,6 @@ "@testing-library/dom": ">=7.21.4" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/@trysound/sax": { "version": "0.2.0", "license": "ISC", @@ -4505,7 +4484,7 @@ } }, "node_modules/@types/react-redux": { - "version": "7.1.30", + "version": "7.1.33", "license": "MIT", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", @@ -4515,7 +4494,7 @@ } }, "node_modules/@types/react-slick": { - "version": "0.23.12", + "version": "0.23.13", "license": "MIT", "dependencies": { "@types/react": "*" @@ -5411,6 +5390,14 @@ "node": ">= 4.5.0" } }, + "node_modules/attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "engines": { + "node": ">=4" + } + }, "node_modules/autoprefixer": { "version": "10.4.16", "funding": [ @@ -5472,8 +5459,7 @@ }, "node_modules/axios": { "version": "1.6.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.4.tgz", - "integrity": "sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.4", "form-data": "^4.0.0", @@ -6046,9 +6032,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001605", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", - "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", + "version": "1.0.30001607", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001607.tgz", + "integrity": "sha512-WcvhVRjXLKFB/kmOFVwELtMxyhq3iM/MvmXcyCe2PNf166c39mptscOc/45TTS96n2gpNV2z7+NakArTWZCQ3w==", "funding": [ { "type": "opencollective", @@ -6953,18 +6939,6 @@ "version": "0.4.4", "license": "MIT" }, - "node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", - "dev": true, - "dependencies": { - "rrweb-cssom": "^0.6.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/csstype": { "version": "3.1.2", "license": "MIT" @@ -7149,20 +7123,6 @@ "version": "1.0.8", "license": "BSD-2-Clause" }, - "node_modules/data-urls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/date-fns": { "version": "2.30.0", "license": "MIT", @@ -7453,19 +7413,6 @@ ], "license": "BSD-2-Clause" }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "deprecated": "Use your platform's native DOMException instead", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/domhandler": { "version": "5.0.3", "license": "BSD-2-Clause", @@ -7537,9 +7484,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.725", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.725.tgz", - "integrity": "sha512-OGkMXLY7XH6ykHE5ZOVVIMHaGAvvxqw98cswTKB683dntBJre7ufm9wouJ0ExDm0VXhHenU8mREvxIbV5nNoVQ==" + "version": "1.4.729", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.729.tgz", + "integrity": "sha512-bx7+5Saea/qu14kmPTDHQxkp2UnziG3iajUQu3BxFvCOnpAJdDbMV4rSl+EqFDkkpNNVUFlR1kDfpL59xfy1HA==" }, "node_modules/emittery": { "version": "0.13.1", @@ -8786,6 +8733,17 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/filelist": { "version": "1.0.4", "license": "Apache-2.0", @@ -8915,14 +8873,13 @@ }, "node_modules/follow-redirects": { "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -9554,18 +9511,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/html-entities": { "version": "2.4.0", "funding": [ @@ -9612,8 +9557,7 @@ }, "node_modules/html-parse-stringify": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", - "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", "dependencies": { "void-elements": "3.1.0" } @@ -9706,20 +9650,6 @@ "node": ">=8.0.0" } }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/http-proxy-middleware": { "version": "2.0.6", "license": "MIT", @@ -9762,8 +9692,6 @@ }, "node_modules/i18next": { "version": "22.5.1", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.5.1.tgz", - "integrity": "sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==", "funding": [ { "type": "individual", @@ -9778,6 +9706,7 @@ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" } ], + "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.6" } @@ -9851,8 +9780,9 @@ }, "node_modules/immutable": { "version": "4.3.4", - "devOptional": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -13089,48 +13019,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsdom": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.0.0.tgz", - "integrity": "sha512-p5ZTEb5h+O+iU02t0GfEjAnkdYPrQSkfuTSMkMYyIoMvUNEHsbG0bHHbfXIcfTqD2UfvjQX7mmgiFsyRwGscVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", - "decimal.js": "^10.4.3", - "domexception": "^4.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, "node_modules/jsesc": { "version": "2.5.2", "license": "MIT", @@ -15899,6 +15787,22 @@ "react": "^18.2.0" } }, + "node_modules/react-dropzone": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz", + "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==", + "dependencies": { + "attr-accept": "^2.2.2", + "file-selector": "^0.6.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, "node_modules/react-error-overlay": { "version": "6.0.11", "license": "MIT" @@ -15909,8 +15813,7 @@ }, "node_modules/react-i18next": { "version": "13.5.0", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-13.5.0.tgz", - "integrity": "sha512-CFJ5NDGJ2MUyBohEHxljOq/39NQ972rh1ajnadG9BjTk+UXbHLq4z5DKEbEQBDoIhUmmbuS/fIMJKo6VOax1HA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.22.5", "html-parse-stringify": "^3.0.1" @@ -17920,12 +17823,6 @@ "node": ">=8" } }, - "node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", - "dev": true - }, "node_modules/rst-selector-parser": { "version": "2.2.3", "license": "BSD-3-Clause", @@ -18015,8 +17912,9 @@ }, "node_modules/sass": { "version": "1.69.5", - "devOptional": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -18065,18 +17963,6 @@ } } }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, "node_modules/scheduler": { "version": "0.23.0", "license": "MIT", @@ -19120,18 +19006,6 @@ "node": ">= 4.0.0" } }, - "node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/tryer": { "version": "1.0.1", "license": "MIT" @@ -19481,8 +19355,7 @@ }, "node_modules/void-elements": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -19494,18 +19367,6 @@ "browser-process-hrtime": "^1.0.0" } }, - "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/walker": { "version": "1.0.8", "license": "Apache-2.0", @@ -19531,19 +19392,6 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/web-vitals": { - "version": "3.5.0", - "license": "Apache-2.0" - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/webpack": { "version": "5.89.0", "license": "MIT", @@ -19833,44 +19681,10 @@ "node": ">=0.8.0" } }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/whatwg-fetch": { "version": "3.6.19", "license": "MIT" }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", - "dev": true, - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/which": { "version": "2.0.2", "license": "ISC", @@ -20302,15 +20116,6 @@ } } }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/xmlchars": { "version": "2.2.0", "license": "MIT" diff --git a/frontend/package.json b/frontend/package.json index 6ec52d5e..da199204 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,14 +1,14 @@ { "name": "dashboard-app", - "version": "1.3.1", + "version": "2.0.0", "license": "Apache-2.0", "private": true, "dependencies": { - "@catena-x/portal-shared-components": "2.1.30", + "react-dropzone": "^14.2.3", + "@catena-x/portal-shared-components": "^2.1.40", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@mui/icons-material": "5.10.6", - "@mui/x-data-grid": "5.17.26", "@mui/types": "7.2.5", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "14.1.0", @@ -31,9 +31,7 @@ "react-simple-maps": "^3.0.0", "react-svg-worldmap": "^2.0.0-alpha.16", "react-test-renderer": "^18.2.0", - "react-tooltip": "4.2.21", - "web-vitals": "^3.5.0", - "webpack": "5.89.0" + "react-tooltip": "4.2.21" }, "scripts": { "start": "react-scripts start", @@ -71,11 +69,8 @@ "@babel/preset-env": "^7.23.3", "@babel/preset-react": "^7.23.3", "babel-jest": "^29.7.0", - "jsdom": "22.0.0", - "sass": "^1.69.5", - "@adobe/css-tools": ">=4.3.2", "follow-redirects": ">=1.15.4", - "postcss": "^8.4.38" + "postcss": "^8.4.31" }, "overrides": { "react-simple-maps": { @@ -89,7 +84,6 @@ "postcss": "^8.4.31" }, "eslint": "8.32.0", - "react-router-dom": "6.14.1", "keycloak-js": "20.0.5", "@mui/icons-material": "5.10.6", "@mui/material": "5.10.7", @@ -98,8 +92,7 @@ "@mui/types": "7.2.5", "@mui/system": { "@mui/types": "7.2.5" - }, - "@mui/x-data-grid": "6.18.4" + } }, "i18next": "22.5.1" }, diff --git a/frontend/public/index.html b/frontend/public/index.html index 12bc3bdc..3c864d33 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -6,10 +6,10 @@ React App diff --git a/frontend/src/App.js b/frontend/src/App.js index 6d303e43..20b2e3a4 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -32,6 +32,8 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import AboutPage from "./components/dashboard/AboutCard/AboutPage"; import { FooterPortal } from "./components/dashboard/Footer/FooterPortal"; import ErrorPageCR from "./components/dashboard/ErrorPage/ErrorPageCR"; +import SignOut from "./components/dashboard/SignOut"; +import NegotiationPage from "./components/dashboard/NegotiationPage/NegotiationPage"; function App() { return ( @@ -51,6 +53,11 @@ function App() { } /> } /> } /> + } /> + } + /> diff --git a/frontend/src/components/dashboard/CountryPicker/CountryPicker.js b/frontend/src/components/dashboard/CountryPicker/CountryPicker.js index c894e96e..91e52741 100644 --- a/frontend/src/components/dashboard/CountryPicker/CountryPicker.js +++ b/frontend/src/components/dashboard/CountryPicker/CountryPicker.js @@ -1,22 +1,22 @@ /******************************************************************************** -* Copyright (c) 2022,2024 BMW Group AG -* Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License, Version 2.0 which is available at -* https://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. -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ + * Copyright (c) 2022,2024 BMW Group AG + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ import React, { useState, useEffect, useContext } from "react"; import "./styles.scss"; import Box from "@mui/material/Box"; @@ -58,7 +58,7 @@ const CountryPicker = () => { fullWidth variant="filled" size="small" - noOptionsText={'No country found'} + noOptionsText={"No country found"} onChange={handleChange} options={Countries || []} autoHighlight @@ -81,11 +81,17 @@ const CountryPicker = () => { )} renderInput={(params) => ( - + )} /> ); diff --git a/frontend/src/components/dashboard/CountryPicker/styles.scss b/frontend/src/components/dashboard/CountryPicker/styles.scss index f1b43372..31fe3971 100644 --- a/frontend/src/components/dashboard/CountryPicker/styles.scss +++ b/frontend/src/components/dashboard/CountryPicker/styles.scss @@ -23,3 +23,7 @@ max-width: 300px; } +.MuiInputBase-root { + background-color: white; +} + diff --git a/frontend/src/components/dashboard/DashBoardTable/DashboardTable.js b/frontend/src/components/dashboard/DashBoardTable/DashboardTable.js index e23dc42b..189f3f57 100644 --- a/frontend/src/components/dashboard/DashBoardTable/DashboardTable.js +++ b/frontend/src/components/dashboard/DashBoardTable/DashboardTable.js @@ -21,7 +21,8 @@ import React, { useState, useEffect, useContext, useCallback } from "react"; import { getAll } from "../../services/dashboard-api"; -import { Dialog, Table } from "cx-portal-shared-components"; +import { Dialog } from "@catena-x/portal-shared-components"; +import { Table } from "@catena-x/portal-shared-components"; import "./styles.scss"; import { columns } from "./tableColumns"; import { RangesContext } from "../../../contexts/ranges"; @@ -31,7 +32,7 @@ import { CompanyUserContext } from "../../../contexts/companyuser"; import { GatesContext } from "../../../contexts/gates"; import DetailDialog from "../DetailDialog/DetailDialog"; -const DashboardTable = (ratings, years) => { +const DashboardTable2 = (ratings, years) => { //Data Fetch const [data, setData] = useState([]); const [globalData, setGlobalData] = useState([]); @@ -44,6 +45,7 @@ const DashboardTable = (ratings, years) => { const [openDetailGrid, setOpenDetailGrid] = useState(false); const [selectedDetailRow, setSelectedDetailRow] = useState([]); const [tableColumns, setTableColumns] = useState([]); + const [expr, setExpr] = useState(""); const openDetailGridFunction = (row) => { setOpenDetailGrid(true); setSelectedDetailRow([row]); @@ -55,6 +57,7 @@ const DashboardTable = (ratings, years) => { const fetchData = (expr) => { const lexpr = expr.toLowerCase(); + setExpr(expr); getAll( ratings.getRatings, ratings.years, @@ -76,7 +79,6 @@ const DashboardTable = (ratings, years) => { const exportCsv = () => { const newArray = []; let csvContent = "data:text/csv;charset=utf-8,\uFEFF"; - newArray.push(Object.keys(selectedRows[0])); const values = selectedRows.map((row) => Object.values(row)); [...newArray, ...values].forEach(function (rowArray) { @@ -133,27 +135,24 @@ const DashboardTable = (ratings, years) => { className="table" columns={tableColumns} rowsCount={data.length} + checkboxSelection + columnHeadersBackgroundColor="rgb(233, 233, 233);" rows={data} pageSize={15} rowHeight={50} headerHeight={40} - autoHeight={true} - checkboxSelection - columnBuffer={columns().length} - disableColumnMenu={true} //Remove Filtering - getRowClassName={(params) => `${params.row.status}`} - onSelectionModelChange={(ids) => { + onRowSelectionModelChange={(ids) => { const selectedIds = new Set(ids); const selectedRows = data.filter((row) => selectedIds.has(row.id)); setSelectedRows(selectedRows); }} - toolbar={{ - buttonLabel: "Export to csv", - onButtonClick: exportCsv, - onSearch: fetchData, - title: "Number of Filtered Business Partners:", - }} - > + buttonLabel="Export to csv" + onButtonClick={exportCsv} + onSearch={fetchData} + searchExpr={expr} + title="Number of Filtered Business Partners:" + toolbarVariant="basic" + /> { ); }; -export default DashboardTable; +export default DashboardTable2; diff --git a/frontend/src/components/dashboard/DashBoardTable/styles.scss b/frontend/src/components/dashboard/DashBoardTable/styles.scss index 3e4bb881..c7a3366b 100644 --- a/frontend/src/components/dashboard/DashBoardTable/styles.scss +++ b/frontend/src/components/dashboard/DashBoardTable/styles.scss @@ -18,15 +18,9 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ .dashboard-table-style { - height: inherit !important; - display: flex; .table { - display: flex; - flex-direction: column; - width: 100% !important; background-color: white; font-size: 10px !important; - height: 100% !important; .maxColor { background-color: green; } diff --git a/frontend/src/components/dashboard/DashBoardTable/tableColumns.js b/frontend/src/components/dashboard/DashBoardTable/tableColumns.js index 25540897..21d396c3 100644 --- a/frontend/src/components/dashboard/DashBoardTable/tableColumns.js +++ b/frontend/src/components/dashboard/DashBoardTable/tableColumns.js @@ -19,7 +19,7 @@ ********************************************************************************/ import clsx from "clsx"; import ArrowForwardIcon from "@mui/icons-material/ArrowForward"; -import { IconButton } from "cx-portal-shared-components"; +import { IconButton } from "@catena-x/portal-shared-components"; import { capitalize } from "@mui/material"; import CheckCircleIcon from "@mui/icons-material/CheckCircle"; import CancelIcon from "@mui/icons-material/Cancel"; @@ -38,39 +38,32 @@ export const columns = (ranges, onDetailClick, roles) => { { description: "Business Partner Number", field: "bpn", - flex: 1.5, + flex: 2.5, headerName: "Business Partner Number", }, { description: "Legal Name", field: "legalName", - flex: 1.5, + flex: 2, headerName: "Legal Name", }, - ...hiddenColumns.map((field) => ({ - description: field, - field, - flex: 1.5, - headerName: capitalize(field), - hide: true, - })), { description: "Country", field: "country", - flex: 1.5, + flex: 1.4, headerName: "Country", }, { description: "City", field: "city", - flex: 1.5, + flex: 1.4, headerName: "City", }, { description: "Score", field: "score", headerName: "Score", - flex: 1.5, + flex: 1.2, cellClassName: (params) => clsx("super-app", { minColor: params.value < ranges[1][0], @@ -105,7 +98,7 @@ export const columns = (ranges, onDetailClick, roles) => { { description: "Customer", field: "customer", - flex: 1.5, + flex: 1.6, headerName: "Customer", hide: !hasReadCustomersRole, renderCell: (params) => diff --git a/frontend/src/components/dashboard/DatePicker/DatePicker.js b/frontend/src/components/dashboard/DatePicker/DatePicker.js index 7b57a64b..7360a6f5 100644 --- a/frontend/src/components/dashboard/DatePicker/DatePicker.js +++ b/frontend/src/components/dashboard/DatePicker/DatePicker.js @@ -77,8 +77,8 @@ const DatePicker = ({ passYearSelected }) => { return ( - - Select a Year + Select a Year + {AllGates && Array.isArray(AllGates) ? AllGates.map((item) => { diff --git a/frontend/src/components/dashboard/LeftMap/LeftMap.js b/frontend/src/components/dashboard/LeftMap/LeftMap.js index 64103943..420a9a18 100644 --- a/frontend/src/components/dashboard/LeftMap/LeftMap.js +++ b/frontend/src/components/dashboard/LeftMap/LeftMap.js @@ -24,7 +24,7 @@ import { IconButton, Button, DialogHeader, -} from "cx-portal-shared-components"; +} from "@catena-x/portal-shared-components"; import "./styles.scss"; import CustomWorldMap from "../CustomWorld/CustomWorldMap"; import OpenWithIcon from "@mui/icons-material/ZoomIn"; @@ -119,7 +119,7 @@ const LeftMap = (ratings) => { minMapWidth={0} maxMapWidth={800} minMapHeight={0} - maxMapHeight={600} + maxMapHeight={700} >
diff --git a/frontend/src/components/dashboard/LeftMap/styles.scss b/frontend/src/components/dashboard/LeftMap/styles.scss index 514e5946..4b89aa54 100644 --- a/frontend/src/components/dashboard/LeftMap/styles.scss +++ b/frontend/src/components/dashboard/LeftMap/styles.scss @@ -19,7 +19,7 @@ ********************************************************************************/ .left-map-container { height: 15%; - width: 100%; + width: 98%; display: flex; align-items: center; justify-content: space-between; @@ -60,6 +60,7 @@ text-align: center; align-items: center; margin-top: -8%; + overflow: hidden; .buttons { display: flex; diff --git a/frontend/src/components/dashboard/NavigationBar/DialogContent/DialogHelpContent.js b/frontend/src/components/dashboard/NavigationBar/DialogContent/DialogHelpContent.js index f84070e7..81d3c56c 100644 --- a/frontend/src/components/dashboard/NavigationBar/DialogContent/DialogHelpContent.js +++ b/frontend/src/components/dashboard/NavigationBar/DialogContent/DialogHelpContent.js @@ -22,122 +22,124 @@ import { DialogContent, CardHorizontal, DialogHeader, -} from "cx-portal-shared-components"; +} from "@catena-x/portal-shared-components"; import IconButton from "@mui/material/IconButton"; import CloseIcon from "@mui/icons-material/Close"; const DialogHelpContent = ({ openDialog }) => { - -return ( -
-
- - - + return ( +
+
+ + + +
+ + + +
- - - - -
- -)}; + ); +}; export default DialogHelpContent; diff --git a/frontend/src/components/dashboard/NavigationBar/NavigationBar.js b/frontend/src/components/dashboard/NavigationBar/NavigationBar.js index c54b1d7e..dceae182 100644 --- a/frontend/src/components/dashboard/NavigationBar/NavigationBar.js +++ b/frontend/src/components/dashboard/NavigationBar/NavigationBar.js @@ -19,20 +19,16 @@ ********************************************************************************/ import { MainNavigation, - Logo, - DialogHeader, - DialogContent, - DialogActions, - CardHorizontal, -} from "cx-portal-shared-components"; + Button, + Dialog, +} from "@catena-x/portal-shared-components"; import React, { useContext } from "react"; import Box from "@mui/material/Box"; -import Button from "@mui/material/Button"; + import IconButton from "@mui/material/IconButton"; import LogoSVG from "../../../resources/cxlogo.svg"; import { CompanyUserContext } from "../../../contexts/companyuser"; import { getPortalLink } from "../../services/EnvironmentService"; -import Dialog from "@mui/material/Dialog"; import "./styles.scss"; import CloseIcon from "@mui/icons-material/Close"; import { UserInfo } from "./UserInformation/UserInfo"; diff --git a/frontend/src/components/dashboard/NavigationBar/UserInformation/UserInfo.js b/frontend/src/components/dashboard/NavigationBar/UserInformation/UserInfo.js index 2d530808..9d546042 100644 --- a/frontend/src/components/dashboard/NavigationBar/UserInformation/UserInfo.js +++ b/frontend/src/components/dashboard/NavigationBar/UserInformation/UserInfo.js @@ -18,23 +18,25 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -import { useRef, useState } from "react"; +import { useState, useRef, useContext } from "react"; import { UserAvatar, UserMenu, UserNav, LanguageSwitch, -} from "cx-portal-shared-components"; +} from "@catena-x/portal-shared-components"; import UserService from "../../../services/UserService"; import "./UserInfo.scss"; import { getLogoutLink, - getAboutLink, + getNegotiationLink, } from "../../../services/EnvironmentService"; +import { CompanyUserContext } from "../../../../contexts/companyuser"; export const UserInfo = () => { const [menuOpen, setMenuOpen] = useState(false); const wrapperRef = useRef(null); + const { companyUser } = useContext(CompanyUserContext); const openCloseMenu = () => setMenuOpen((prevVal) => !prevVal); @@ -46,7 +48,27 @@ export const UserInfo = () => { const logoutHref = getLogoutLink(); - const aboutHref = getAboutLink(); + // Dynamically construct menu items based on user roles + let menuItems = [ + { + href: logoutHref, + title: "Logout", + }, + ]; + + // Add negotiation link for users with Negotiator or Admin roles + if ( + companyUser.roles.includes("Negotiator") || + companyUser.roles.includes("Admin") + ) { + menuItems = [ + { + href: getNegotiationLink(), + title: "Negotiation", + }, + ...menuItems, + ]; + } return (
@@ -60,27 +82,10 @@ export const UserInfo = () => { userRole={UserService.getCompany()} onClickAway={onClickAway} > - - - {/**/} +
); }; + +export default UserInfo; diff --git a/frontend/src/components/dashboard/NavigationBar/UserInformation/UserInfo.scss b/frontend/src/components/dashboard/NavigationBar/UserInformation/UserInfo.scss index 8c978584..985cad65 100644 --- a/frontend/src/components/dashboard/NavigationBar/UserInformation/UserInfo.scss +++ b/frontend/src/components/dashboard/NavigationBar/UserInformation/UserInfo.scss @@ -1,4 +1,4 @@ .UserInfo { - position: relative; - z-index: 100; - } \ No newline at end of file + position: relative; + z-index: 100; +} diff --git a/frontend/src/components/dashboard/NavigationBar/styles.scss b/frontend/src/components/dashboard/NavigationBar/styles.scss index 89274caf..a639b2bb 100644 --- a/frontend/src/components/dashboard/NavigationBar/styles.scss +++ b/frontend/src/components/dashboard/NavigationBar/styles.scss @@ -28,14 +28,13 @@ flex-direction: row; align-items: center; - .btnHelp{ + .btnHelp { margin-right: 20%; } } .Dialog-Help { height: 100% !important; - width: auto; text-align: center; margin-left: auto; margin-right: auto; @@ -48,6 +47,7 @@ } .BoxHelp { + width: 100% !important; margin: 4%; display: flex; margin-left: 15%; @@ -56,12 +56,13 @@ .Hyperlink { text-decoration: none; + width: 100%; } } .Dialog-Help-Expand-Div { text-align: center; - background-color: #FFFFFF; + background-color: #ffffff; border-radius: 39px !important; .header { diff --git a/frontend/src/components/dashboard/NegotiationPage/NegotiationPage.js b/frontend/src/components/dashboard/NegotiationPage/NegotiationPage.js new file mode 100644 index 00000000..37caf010 --- /dev/null +++ b/frontend/src/components/dashboard/NegotiationPage/NegotiationPage.js @@ -0,0 +1,215 @@ +/******************************************************************************** + * Copyright (c) 2022,2024 BMW Group AG + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +import React, { useContext, useState, useEffect } from "react"; + +import { CompanyUserContext } from "../../../contexts/companyuser"; +import "./NegotiationPage.scss"; // Assuming you'll have specific styles +import { Table } from "@catena-x/portal-shared-components"; +import { ErrorPage } from "@catena-x/portal-shared-components"; +import UserService from "../../services/UserService"; +import { useNavigate } from "react-router-dom"; +import { + fetchCatalogItems, + triggerNegotiation, +} from "../../services/negotiation"; +import CheckCircleIcon from "@mui/icons-material/CheckCircle"; +import CancelIcon from "@mui/icons-material/Cancel"; + +const NegotiationPage = () => { + const { companyUser } = useContext(CompanyUserContext); + const navigate = useNavigate(); + const [catalogItems, setCatalogItems] = useState([]); + const [selectedItems, setSelectedItems] = useState([]); + + useEffect(() => { + // Fetch catalog items from the API + const loadCatalogItems = async () => { + try { + const items = await fetchCatalogItems(UserService.getToken()); + setCatalogItems(items); + } catch (error) { + console.error("Error fetching catalog items:", error); + } + }; + + loadCatalogItems(); + }, []); + + const columns = [ + { + field: "id", + headerName: "ID", + flex: 2.2, + }, + { + field: "provider", + headerName: "Provider", + flex: 1, + }, + { + field: "subject", + headerName: "Subject", + flex: 2, + }, + { + field: "description", + headerName: "Description", + flex: 2.5, + }, + { + field: "status", + headerName: "Status", + flex: 1, + renderCell: (params) => { + switch (params.value) { + case "Error": + return ; + case "Success": + return ; + case "Pending": + // Optionally, return a spinner or a transparent placeholder + return null; // For now, do nothing for pending state + default: + return null; // For initial state or any unrecognized status + } + }, + }, + ]; + + const handleInitiateNegotiation = async () => { + if (selectedItems.length === 0) { + alert("Please select at least one item to negotiate."); + return; + } + + // Reset the status of selected items to "Pending" before negotiation + const resetItems = catalogItems.map((item) => { + if (selectedItems.find((selectedItem) => selectedItem.id === item.id)) { + return { ...item, status: "Pending" }; // Assuming "Pending" means no icon displayed + } + return item; + }); + setCatalogItems(resetItems); // Update state to reflect the reset statuses + + const negotiationRequest = selectedItems.map((item) => ({ + id: item.id, + offerId: item.offerId, + })); + + try { + const response = await triggerNegotiation( + negotiationRequest, + UserService.getToken() + ); + // Update the status of catalog items based on negotiation response + updateItemStatuses(response); + } catch (error) { + console.error("Error initiating negotiation:", error); + alert("Failed to initiate negotiation."); + } + }; + + // Utility function to update the status of catalog items based on negotiation response + const updateItemStatuses = (negotiationResults) => { + const updatedItems = catalogItems.map((item) => { + const negotiationResult = negotiationResults.find( + (result) => result.id === item.id + ); + if (negotiationResult) { + return { + ...item, + status: negotiationResult.status === "Success" ? "Success" : "Error", + }; + } + return item; // Return item unchanged if no negotiation result is found + }); + + setCatalogItems(updatedItems); // Update state with the new items including their statuses + }; + + // Check if the user has permission to initiate negotiations + const userCanNegotiate = + companyUser.roles.includes("Negotiator") || + companyUser.roles.includes("Admin"); // Adjust the role check as necessary + + return ( +
+ {userCanNegotiate ? ( + <> +

Catalog Items Available for Negotiation

+
+ = 5 ? 5 : catalogItems.length} + autoHeight={true} + initialState={{ + pagination: { + paginationModel: { + pageSize: 5, + }, + }, + }} + pageSizeOptions={[5]} + checkboxSelection + disableColumnMenu={true} + columnHeadersBackgroundColor="rgb(233, 233, 233)" + onRowSelectionModelChange={(ids) => { + // Assuming ids are the indexes in the catalogItems array + const selectedIDs = new Set(ids); // If ids are directly the item IDs, you may not need mapping + const selectedCatalogItems = catalogItems.filter( + (item) => selectedIDs.has(item.id.toString()) // Ensure the comparison works by matching types + ); + setSelectedItems(selectedCatalogItems); + }} + title="Available Items" + toolbarVariant="basic" + buttonLabel="Start Negotiation" + onButtonClick={handleInitiateNegotiation} + experimentalFeatures={{ newEditingApi: true }} + hideFooter={catalogItems.length <= 5} + /> + + + ) : ( + { + window.location.href = navigate("/"); + }} + onReloadClick={() => { + navigate("/"); + }} + reloadButtonTitle="Reload Page" + title="Oops, Something went wrong." + /> + )} + + ); +}; + +export default NegotiationPage; diff --git a/frontend/src/components/dashboard/NegotiationPage/NegotiationPage.scss b/frontend/src/components/dashboard/NegotiationPage/NegotiationPage.scss new file mode 100644 index 00000000..39f9e900 --- /dev/null +++ b/frontend/src/components/dashboard/NegotiationPage/NegotiationPage.scss @@ -0,0 +1,54 @@ +/******************************************************************************** +* Copyright (c) 2022,2024 BMW Group AG +* Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +* +* See the NOTICE file(s) distributed with this work for additional +* information regarding copyright ownership. +* +* This program and the accompanying materials are made available under the +* terms of the Apache License, Version 2.0 which is available at +* https://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. +* +* SPDX-License-Identifier: Apache-2.0 +********************************************************************************/ +.negotiation-page { + padding: 2% 5%; + background-color: #f5f5f5; // Light grey background for slight contrast + min-height: 100vh; // Ensures it takes up at least the full height of the viewport + .table { + background-color: white; + font-size: 10px !important; + } + .description-cell { + max-width: 250px; // Adjust based on your layout + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .table-style { + padding-top: 2%; + max-width: 85%; // Reducing the maximum width of the table + width: 100%; // Ensures the table width scales with the container + margin: 0 auto; // Centers the table horizontally + } + + h1 { + color: #333; + text-align: center; + margin-bottom: 20px; + } + + // Styles for the error page layout + .error-page-container { + text-align: center; + padding: 50px; + color: #dc3545; // Example using Bootstrap's danger color + } +} diff --git a/frontend/src/components/dashboard/ProgressBar/styles.scss b/frontend/src/components/dashboard/ProgressBar/styles.scss index 292dda98..f5fbfdc0 100644 --- a/frontend/src/components/dashboard/ProgressBar/styles.scss +++ b/frontend/src/components/dashboard/ProgressBar/styles.scss @@ -20,14 +20,18 @@ .bar { margin-bottom: 4%; width: 10%; + .textValueScore { + display: flex; text-align: center; font-size: 15px; margin-left: 110px; } + .progress-bar { display: flex; align-items: center; + .textValue { width: 45px; text-align: center; @@ -35,17 +39,20 @@ margin-right: 2%; margin-left: 2%; } + .barContainer { flex: 1; height: 8px; background: #dfdfe7; border-radius: 12px; overflow: hidden; /* Crucial part */ + .filler { transition: "width 2s ease-i-out"; height: inherit; border-radius: inherit; overflow: hidden; + .fillerBackground { height: inherit; transition: "width 2s ease-i-out"; diff --git a/frontend/src/components/dashboard/RangeSlider/RangeSlider.js b/frontend/src/components/dashboard/RangeSlider/RangeSlider.js index 25941c7c..5549f953 100644 --- a/frontend/src/components/dashboard/RangeSlider/RangeSlider.js +++ b/frontend/src/components/dashboard/RangeSlider/RangeSlider.js @@ -1,22 +1,22 @@ /******************************************************************************** -* Copyright (c) 2022,2024 BMW Group AG -* Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License, Version 2.0 which is available at -* https://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. -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ + * Copyright (c) 2022,2024 BMW Group AG + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ import React, { useState, useEffect, useContext } from "react"; import "./styles.scss"; import Slider from "@mui/material/Slider"; @@ -25,7 +25,7 @@ import Grid from "@mui/material/Grid"; import UserService from "../../services/UserService"; import { getAllRanges } from "../../services/ranges-api"; import { RangesContext } from "../../../contexts/ranges"; -import { Button, IconButton } from "cx-portal-shared-components"; +import { Button, IconButton } from "@catena-x/portal-shared-components"; import { sendValues } from "../../services/ranges-api"; import { CompanyUserContext } from "../../../contexts/companyuser"; import { ReportContext } from "../../../contexts/reports"; diff --git a/frontend/src/components/dashboard/Ratings/Ratings.js b/frontend/src/components/dashboard/Ratings/Ratings.js index a632efa3..fb71a590 100644 --- a/frontend/src/components/dashboard/Ratings/Ratings.js +++ b/frontend/src/components/dashboard/Ratings/Ratings.js @@ -19,7 +19,7 @@ ********************************************************************************/ import React, { useState, useContext, useEffect, useRef } from "react"; import "./styles.scss"; -import Dialog from "@mui/material/Dialog"; + import { Table, Button, @@ -27,7 +27,10 @@ import { DialogHeader, DialogContent, DialogActions, -} from "cx-portal-shared-components"; + Dialog, + PageSnackbar, +} from "@catena-x/portal-shared-components"; + import Alert from "@mui/material/Alert"; import { RatesContext } from "../../../contexts/rates"; import { @@ -62,8 +65,10 @@ const Ratings = ({ const [sumTotalEffect, setSumTotalEffect] = useState(-1); const [severity, setSeverity] = useState(""); - const [severityMessage, setSeverityMessage] = useState(""); - + const [setSeverityMessage] = useState(""); + const [snackBarMessage, setSnackBarMessage] = useState(""); + const [snackBarMessageTitle, setSnackBarMessageTitle] = useState(""); + const [openSnackBar, setOpenSnackBar] = useState(false); //Delete Warning const [severityDelete, setSeverityDelete] = useState(""); const [severityMessageDelete, setSeverityMessageDelete] = useState(""); @@ -193,29 +198,31 @@ const Ratings = ({ const closeDialogsAndDelete = () => { deleteRating(UserService.getToken(), companyUser, deleteID) .then((code) => { + setOpenSnackBar(true); updateReload(!reload); if (code.status === 204) { - setOpenAlert(true); - setSeverityDelete("success"); - setSeverityMessageDelete("Rating delete sucessfully!"); + setSnackBarMessageTitle("Success"); + setSnackBarMessage("Rating delete sucessfully!"); + setSeverity("success"); } }) .catch((err) => { + setOpenSnackBar(true); if (err.response.data.status === 401) { - setOpenAlert(true); - setSeverityDelete("error"); - setSeverityMessageDelete( + setSnackBarMessageTitle("Error"); + setSnackBarMessage( "You do not have the permission to deleted this rating!" ); + setSeverity("error"); } if (err.response.data.status === 500) { - setOpenAlert(true); - setSeverityDelete("error"); - setSeverityMessageDelete("Wrong Request Type!"); + setSnackBarMessageTitle("Error"); + setSnackBarMessage("Wrong Request Type!"); + setSeverity("error"); } }); + setOpenSnackBar(false); setOpenWarning(!openWarning); - timerFunction(); }; const hideAlert = () => { @@ -265,44 +272,44 @@ const Ratings = ({
r.id)} - experimentalFeatures={{ newEditingApi: true }} - isCellEditable={handleEdit} // this works - onEditCellPropsChange={onEditCellPropsChange} // this works - onCellEditCommit={validateInput} - columnBuffer={columnsUser().length} - onSelectionModelChange={(ids) => { + onRowSelectionModelChange={(ids) => { + // Updated selection model change handler const selectedIds = new Set(ids); const selectedRows = tableRatings.filter((row) => selectedIds.has(row.id) ); - //pass ratings selected to top component + selectedRows.open = prefixIds.open; setRatings(selectedRows); updatePrefixIds(selectedRows); }} - toolbar={{ - buttonLabel: "Show More Ratings", - onButtonClick: ExpandTable, - title: "Ratings", - }} - hideFooter={tableRatings.length > 5 ? false : true} - >
- - {severityMessage} - + buttonLabel="Show More Ratings" + title="Ratings" + toolbarVariant="basic" + experimentalFeatures={{ newEditingApi: true }} + isCellEditable={handleEdit} + onEditCellPropsChange={onEditCellPropsChange} + onCellEditCommit={validateInput} + hideFooter={tableRatings.length <= 5} + />
@@ -364,27 +372,35 @@ const Ratings = ({ rowHeight={50} headerHeight={40} autoHeight={true} + initialState={{ + pagination: { + paginationModel: { + pageSize: 10, + }, + }, + }} + pageSizeOptions={[10]} checkboxSelection disableColumnMenu={true} - selectionModel={prefixIds.map((r) => r.id)} - experimentalFeatures={{ newEditingApi: true }} - isCellEditable={handleEdit} // this works - onEditCellPropsChange={onEditCellPropsChange} // this works - onSelectionModelChange={(ids) => { + columnHeadersBackgroundColor="rgb(233, 233, 233)" + onRowSelectionModelChange={(ids) => { + // Updated to the latest selection model event handler name const selectedIds = new Set(ids); const selectedRows = tableRatings.filter((row) => selectedIds.has(row.id) ); - //pass ratings selected to top component selectedRows.open = prefixIds.open; setRatings(selectedRows); updatePrefixIds(selectedRows); }} - toolbar={{ - title: "Ratings", - }} - hideFooter={tableRatings.length > 5 ? false : true} - > + title="Ratings" + toolbarVariant="basic" + experimentalFeatures={{ newEditingApi: true }} + isCellEditable={handleEdit} + onEditCellPropsChange={onEditCellPropsChange} + hideFooter={tableRatings.length <= 5} + /> +
+
); }; diff --git a/frontend/src/components/dashboard/Ratings/ratingUserColumns.js b/frontend/src/components/dashboard/Ratings/ratingUserColumns.js index 7e1cd4b9..fe37aed0 100644 --- a/frontend/src/components/dashboard/Ratings/ratingUserColumns.js +++ b/frontend/src/components/dashboard/Ratings/ratingUserColumns.js @@ -1,32 +1,28 @@ /******************************************************************************** -* Copyright (c) 2022,2024 BMW Group AG -* Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* This program and the accompanying materials are made available under the -* terms of the Apache License, Version 2.0 which is available at -* https://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. -* -* SPDX-License-Identifier: Apache-2.0 -********************************************************************************/ -import { IconButton } from "cx-portal-shared-components"; + * Copyright (c) 2022,2024 BMW Group AG + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +import { IconButton } from "@catena-x/portal-shared-components"; import DeleteIcon from "@mui/icons-material/DeleteOutlineOutlined"; import { GridActionsCellItem } from "@mui/x-data-grid"; import { useCallback } from "react"; export const columnsUser = (rates, onClickDelete) => [ - { - field: "id", - hide: true, - }, { description: "Rating", field: "dataSourceName", diff --git a/frontend/src/components/dashboard/Ratings/styles.scss b/frontend/src/components/dashboard/Ratings/styles.scss index 55ff5073..cbd0067e 100644 --- a/frontend/src/components/dashboard/Ratings/styles.scss +++ b/frontend/src/components/dashboard/Ratings/styles.scss @@ -26,6 +26,7 @@ .rating-table-content { margin-top: 2%; + margin-bottom: 2%; height: 80%; //border: 1px solid #000; //border-radius: 0; @@ -35,7 +36,8 @@ } .dialog-table-expand-style { - height: 100% !important; + border-radius: 15px !important; + //height: 100% !important; .closeButton { text-align: right; @@ -47,12 +49,13 @@ text-align: center; margin-top: -7%; } - .rating-div-table-expand-style { -ms-overflow-style: none; //height: 1200px; + border-radius: 15px !important; .table-expand-style { + border-radius: 15px !important; display: flex; width: 95%; margin-left: auto; @@ -63,16 +66,15 @@ font-size: 12px; } - .closeBtnDialog{ + .closeBtnDialog { margin-top: 3%; text-align: center; - background-color: #EDF0F4; + background-color: #edf0f4; - .btn-close-dialog{ + .btn-close-dialog { margin: 1%; } } - } } @@ -86,14 +88,14 @@ .Dialog-Expand-Div { text-align: center; - background-color: #FFFFFF; + background-color: #ffffff; border-radius: 39px !important; .warning-header { margin-left: auto; margin-right: auto; - .btn-no{ + .btn-no { margin-right: 5%; } } diff --git a/frontend/src/components/dashboard/Reports/Reports.js b/frontend/src/components/dashboard/Reports/Reports.js index dc6b8783..bdd47d03 100644 --- a/frontend/src/components/dashboard/Reports/Reports.js +++ b/frontend/src/components/dashboard/Reports/Reports.js @@ -19,24 +19,25 @@ ********************************************************************************/ import React, { useState, useEffect, useContext } from "react"; import "./styles.scss"; -import Dialog from "@mui/material/Dialog"; + import FormLabel from "@mui/material/FormLabel"; import TextField from "@mui/material/TextField"; import FormControlLabel from "@mui/material/FormControlLabel"; -import { Alert, DialogContent } from "@catena-x/portal-shared-components"; +import Tooltip from "@mui/material/Tooltip"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; import { + Alert, + Button, DialogActions, - Dropzone, DialogHeader, - Button, Input, -} from "cx-portal-shared-components"; + PageSnackbar, + Dialog, +} from "@catena-x/portal-shared-components"; import { getReportsByCompanyUser, saveReports, - deleteReport, - updateReports, } from "../../services/reports-api"; import UserService from "../../services/UserService"; import { DataGrid, GridActionsCellItem } from "@mui/x-data-grid"; @@ -48,18 +49,12 @@ import { CountryContext } from "../../../contexts/country"; import { CompanyUserContext } from "../../../contexts/companyuser"; import { ReportContext } from "../../../contexts/reports"; import { Report } from "../../model/Report"; - import { ReloadContext } from "../../../contexts/refresh"; -import CloseIcon from "@mui/icons-material/Close"; -import Collapse from "@mui/material/Collapse"; - -import { IconButton } from "cx-portal-shared-components"; import DeleteIcon from "@mui/icons-material/DeleteOutlineOutlined"; import ShareOutlinedIcon from "@mui/icons-material/ShareOutlined"; import SaveOutlinedIcon from "@mui/icons-material/SaveOutlined"; import ShareReport from "../ShareReport/ShareReport"; import DeleteUpdateComponent from "../DeleteUpdateComponent/DeleteUpdateComponent"; - import { DeleteOrUpdate } from "../../model/DeleteOrUpdate"; const Reports = () => { @@ -100,7 +95,6 @@ const Reports = () => { //Alert trigger consts Delete/Save const [severityAlert, setSeverityAlert] = useState(""); - const [severityMessageAlert, setSeverityMessageAlert] = useState(""); //Gets Current Roles for the User const role = companyUser.roles; @@ -109,6 +103,8 @@ const Reports = () => { const [severityMessage, setSeverityMessage] = useState(""); const [reportType, setReportType] = useState(false); const [editDeleteShareActive, setEditDeleteShareActive] = useState(true); + const [snackBarMessage, setSnackBarMessage] = useState(""); + const [snackBarMessageTitle, setSnackBarMessageTitle] = useState(""); //Open Error/Sucess Dialog const [openAlert, setOpenAlert] = React.useState(false); @@ -189,7 +185,9 @@ const Reports = () => { if (res.status === 200) { setOpenAlert(true); setSeverityAlert("success"); - setSeverityMessageAlert("Report saved sucessfully!"); + setSeverity("success"); + setSnackBarMessageTitle("Success"); + setSnackBarMessage("Report Saved Successfully"); } }) .catch((response) => { @@ -210,6 +208,7 @@ const Reports = () => { setSeverity("warning"); setSeverityMessage("Custom Rating Selected"); }; + const openDialog = () => { setSeverity(""); setSeverityMessage(""); @@ -294,30 +293,32 @@ const Reports = () => { successMessage, errorMessage ) => { + setSnackBarMessage(); + if (code.status === 204) { setOpenAlert(true); setSeverityAlert("success"); - setSeverityMessageAlert(successMessage); timerFunction(); + setSnackBarMessage(successMessage); + setSeverity("success"); + setSnackBarMessageTitle("Success"); } else if (code === 401) { setOpenAlert(true); setSeverityAlert("error"); - setSeverityMessageAlert(errorMessage); timerFunction(); + setSnackBarMessage(errorMessage); + setSeverity("error"); + setSnackBarMessageTitle("Error"); } else if (code === 500 || code === 400) { setOpenAlert(true); setSeverityAlert("error"); - setSeverityMessageAlert("Wrong Request Type!"); + setSnackBarMessage(errorMessage); + setSeverity("error"); + setSnackBarMessageTitle("Error"); timerFunction(); } }; - const hideAlert = () => { - setSeverityAlert(""); - setSeverityMessageAlert(""); - setOpenAlert(!openAlert); - }; - const columnsUser = [ { field: "radiobutton", @@ -361,7 +362,11 @@ const Reports = () => { width: 50, getActions: (params) => [ } + icon={ + + } label="Save" onClick={onClickActionDeleteUpdate( params.id, @@ -370,6 +375,7 @@ const Reports = () => { )} disabled={editDeleteShareActive} data-testid={"saveIcon"} + color="primary" />, ], }, @@ -379,7 +385,11 @@ const Reports = () => { width: 50, getActions: (params) => [ } + icon={ + + } label="Delete" onClick={onClickActionDeleteUpdate( params.id, @@ -397,7 +407,11 @@ const Reports = () => { width: 50, getActions: (params) => [ } + icon={ + + } label="Share" onClick={onClickShare(params.id)} disabled={editDeleteShareActive} @@ -411,11 +425,9 @@ const Reports = () => { if (timer) { clearTimeout(timer); } - setTimer( setTimeout(() => { setSeverityAlert(""); - setSeverityMessageAlert(""); setOpenAlert(false); }, 4000) ); @@ -423,25 +435,6 @@ const Reports = () => { return (
-
- - - - - } - severity={severityAlert} - > - {severityMessageAlert} - - -
{
{
Select availability + + + +
{ closeDialogsDeleteAndUpdate={closeDialogsDeleteAndUpdate} >
+ ); }; diff --git a/frontend/src/components/dashboard/Reports/styles.scss b/frontend/src/components/dashboard/Reports/styles.scss index 302f18db..1f2eb03d 100644 --- a/frontend/src/components/dashboard/Reports/styles.scss +++ b/frontend/src/components/dashboard/Reports/styles.scss @@ -50,19 +50,27 @@ height: 100% !important; display: flex; width: 100%; - //border: 3px solid #000; font-size: 12px; text-align: center; background-color: white; + border-radius: 10px; /* Example: rounded corners with a radius of 10px */ + .css-yrdy0g-MuiDataGrid-columnHeaderRow { + background-color: rgb(233, 233, 233); + } } } -.warning-header { - margin: 2%; +.warning { + width: fit-content !important; +} - .btn-no { - margin-right: 5%; - } +.share-dialog-expand { + height: 100%; + text-align: center; + margin-left: auto; + margin-right: auto; + min-width: 250px; + width: fit-content !important; } .Dialog-Expand { @@ -107,13 +115,4 @@ margin-bottom: 5%; } } - - .share-dialog-expand { - height: 100%; - width: 50%; - text-align: center; - margin-left: auto; - margin-right: auto; - min-width: 250px; - } } diff --git a/frontend/src/components/dashboard/RightMap/RightMap.js b/frontend/src/components/dashboard/RightMap/RightMap.js index b0f780ee..4d31e548 100644 --- a/frontend/src/components/dashboard/RightMap/RightMap.js +++ b/frontend/src/components/dashboard/RightMap/RightMap.js @@ -24,7 +24,7 @@ import { IconButton, Button, DialogHeader, -} from "cx-portal-shared-components"; +} from "@catena-x/portal-shared-components"; import "./styles.scss"; import OpenWithIcon from "@mui/icons-material/ZoomIn"; import { Box } from "@mui/material"; diff --git a/frontend/src/components/dashboard/RightMap/styles.scss b/frontend/src/components/dashboard/RightMap/styles.scss index 1caf6111..7f8ff681 100644 --- a/frontend/src/components/dashboard/RightMap/styles.scss +++ b/frontend/src/components/dashboard/RightMap/styles.scss @@ -19,7 +19,7 @@ ********************************************************************************/ .right-map-container { height: 15%; - width: 100%; + width: 98%; display: flex; align-items: center; justify-content: space-between; @@ -60,7 +60,8 @@ text-align: center; align-items: center; margin-top: -8%; - + overflow: hidden; + .buttons { display: flex; justify-content: space-evenly; diff --git a/frontend/src/components/dashboard/ShareReport/ShareReport.js b/frontend/src/components/dashboard/ShareReport/ShareReport.js index a7fd0f35..9dc59bd0 100644 --- a/frontend/src/components/dashboard/ShareReport/ShareReport.js +++ b/frontend/src/components/dashboard/ShareReport/ShareReport.js @@ -25,13 +25,12 @@ import { DialogActions, DialogContent, DialogHeader, -} from "cx-portal-shared-components"; + Button, + Dialog, +} from "@catena-x/portal-shared-components"; import { getUserFromCompany } from "../../services/company-api"; import { CompanyUserContext } from "../../../contexts/companyuser"; -import { Button } from "cx-portal-shared-components"; import UserService from "../../services/UserService"; - -import { Dialog } from "cx-portal-shared-components"; import DeleteUpdateComponent from "../DeleteUpdateComponent/DeleteUpdateComponent"; const ShareReport = ({ closeDialogs, closeDialogsDeleteAndUpdate }) => { @@ -54,7 +53,6 @@ const ShareReport = ({ closeDialogs, closeDialogsDeleteAndUpdate }) => { return eachEmail; } }); - setEmailsData(filterEmailData); }); }, []); @@ -78,26 +76,24 @@ const ShareReport = ({ closeDialogs, closeDialogsDeleteAndUpdate }) => {
+ className="dialogHeader" + title="Share a Report" + intro="Select here the persons which to share the reports" + /> @@ -114,12 +110,13 @@ const ShareReport = ({ closeDialogs, closeDialogsDeleteAndUpdate }) => { -
+
{" "} { + const [dropped, setDropped] = useState([]); + + const currentFiles = files || dropped; + const isSingleUpload = maxFilesToUpload === 1; + const isDisabled = currentFiles.length === maxFilesToUpload; + + const onDropAccepted = useCallback( + (droppedFiles) => { + const nextFiles = isSingleUpload + ? droppedFiles + : [...dropped, ...droppedFiles]; + setDropped(nextFiles); + onChange(nextFiles, droppedFiles, undefined); + }, + [dropped, isSingleUpload, onChange] + ); + + const handleFEDelete = useCallback( + (deleteIndex, documentId) => { + const nextFiles = [...currentFiles]; + const deletedFiles = nextFiles.splice(deleteIndex, 1); + setDropped(nextFiles); + onChange(nextFiles, undefined, deletedFiles); + if (handleDelete) { + handleDelete(documentId); + } + }, + [currentFiles, onChange, handleDelete] + ); + + const { + getRootProps, + getInputProps, + fileRejections, + isDragReject, + isDragActive, + } = useDropzone({ + onDropAccepted, + disabled: isDisabled, + maxFiles: isSingleUpload ? 0 : maxFilesToUpload, + accept: acceptFormat, + multiple: !isSingleUpload, + maxSize: maxFileSize, + }); + + let DropAreaComponent = DefaultDropArea; + if (DropArea === false) { + DropAreaComponent = () => null; + } + + let DropPreviewComponent = DefaultDropPreview; + if (DropPreview === false) { + DropPreviewComponent = () => null; + } + + const errorObj = fileRejections?.[0]?.errors?.[0]; + const fileTypeError = + errorObj && fileRejections?.[0]?.errors?.[0].code === "file-invalid-type"; + const errorMessage = + !isDragActive && errorObj && !fileTypeError && errorText + ? errorText + : errorObj?.message; + + const uploadFiles = currentFiles.map((file) => ({ + id: file.id, + name: file.name, + size: file.size, + status: file.status || UploadStatus.NEW, + progressPercent: file.progressPercent, + })); + + return ( +
+
+ + + +
+ + +
+ ); +}; + +export default DropZone; diff --git a/frontend/src/components/dashboard/UploadDownloadZone/UploadDownloadZone.js b/frontend/src/components/dashboard/UploadDownloadZone/UploadDownloadZone.js index f749937a..27fd9614 100644 --- a/frontend/src/components/dashboard/UploadDownloadZone/UploadDownloadZone.js +++ b/frontend/src/components/dashboard/UploadDownloadZone/UploadDownloadZone.js @@ -21,19 +21,18 @@ import React, { useState, useContext, useEffect } from "react"; import "./dialog-upload.scss"; import { - Alert, DialogHeader, DialogContent, -} from "@catena-x/portal-shared-components"; - -import { - DialogActions, - Dropzone, - Button, Input, -} from "cx-portal-shared-components"; + Button, + Dialog, + DialogActions, + DropArea, + PageSnackbar, +} from "@catena-x/portal-shared-components"; +import Tooltip from "@mui/material/Tooltip"; -import Dialog from "@mui/material/Dialog"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; import UserService from "../../services/UserService"; import FormLabel from "@mui/material/FormLabel"; import Radio from "@mui/material/Radio"; @@ -47,7 +46,9 @@ import MenuItem from "@mui/material/MenuItem"; import { downloadSampleCsvFile } from "../../services/files-api"; import { CompanyUserContext } from "../../../contexts/companyuser"; import { ReloadContext } from "../../../contexts/refresh"; -import { getCountryRiskApi } from "../../services/EnvironmentService"; +import DropZone from "./DropZoneComponent/DropZone"; + +import { uploadCsvFile } from "../../services/upload-api"; const UploadDownloadZone = () => { //Upload Button Handlers @@ -56,7 +57,9 @@ const UploadDownloadZone = () => { const [autoUp, setAutoUp] = useState(false); const [severity, setSeverity] = useState(""); - const [severityMessage, setSeverityMessage] = useState(""); + const [snackBarMessage, setSnackBarMessage] = useState(""); + const [snackBarMessageTitle, setSnackBarMessageTitle] = useState(""); + const [openSnackBar, setOpenSnackBar] = useState(false); const { companyUser } = useContext(CompanyUserContext); const { reload, updateReload } = useContext(ReloadContext); @@ -102,10 +105,12 @@ const UploadDownloadZone = () => { }; const closeDialogs = () => { + setOpenSnackBar(false); setOpen(false); setAutoUp(false); setValidateSave(true); - setSeverityMessage(""); + setSnackBarMessage(""); + setSnackBarMessageTitle(""); setSeverity(""); }; const openDialog = () => { @@ -116,7 +121,7 @@ const UploadDownloadZone = () => { const saveRatingName = (event) => { setSeverity(""); - setSeverityMessage(""); + if (event.target.value.length > 32 || event.target.value.length === 0) { setErrorTrigger(true); setOpenRatingName(null); @@ -133,60 +138,6 @@ const UploadDownloadZone = () => { setType(event.target.value); }; - const dropzoneProps = { - title: "userUpload.title", - subtitle: "userUpload.subtitle", - accept: "text/csv,application/vnd.ms-excel", - getUploadParams: () => ({ - url: getCountryRiskApi() + process.env.REACT_APP_UPLOAD_FILE, - - fields: { - name: companyUser.name, - email: companyUser.email, - companyName: companyUser.companyName, - }, - headers: { - ratingName: openRatingName || "defaultName", - Authorization: `Bearer ${UserService.getToken()}`, - year: date, - type: valueType, - }, - }), - - onChangeStatus: ({ meta }, file, status, allFiles) => { - if (status[0].xhr) { - if (status[0].xhr.status === 200) { - setSeverity("info"); - setSeverityMessage("Your rating has been uploaded"); - updateReload(!reload); - } else if (meta.status === "error_upload") { - if (status[0].xhr.status === 400) { - setSeverity("error"); - setSeverityMessage( - "Rating name already exists. Please chose a different name" - ); - } else if (status[0].xhr.status === 406) { - setSeverity("error"); - setSeverityMessage("Invalid Rating please check all the fields"); - } else { - setSeverity("error"); - setSeverityMessage("Unexpected error"); - } - } else if (meta.status === "exception_upload") { - setSeverity("error"); - setSeverityMessage("Unexpected error"); - } - } - }, - errorStatus: [ - "error_upload_params", - "exception_upload", - "error_upload", - "aborted", - "ready", - ], - }; - const downloadTemplate = () => { setDisable(true); @@ -205,18 +156,72 @@ const UploadDownloadZone = () => { }); }; + //Upload CSV + const triggerUploadCsv = (file) => { + if (file[0]) { + uploadCsvFile( + file[0], + openRatingName || "defaultName", + date, + valueType, + companyUser + ) + .then((res) => { + if (res.status === 200) { + setOpenSnackBar(true); + setSeverity("success"); + updateReload(!reload); + setSnackBarMessage("Your rating has been uploaded"); + setSnackBarMessageTitle("Success"); + } + }) + .catch((response) => { + if (response.response.status === 400) { + setOpenSnackBar(true); + setSeverity("error"); + setSnackBarMessage( + "Rating name already exists. Please chose a different name" + ); + setSnackBarMessageTitle("Error"); + } else if (response.response.status === 406) { + setOpenSnackBar(true); + setSeverity("error"); + setSnackBarMessage("Invalid Rating please check all the fields"); + setSnackBarMessageTitle("Error"); + } else { + setOpenSnackBar(true); + setSeverity("error"); + setSnackBarMessage("Error inserting the file"); + setSnackBarMessageTitle("Error"); + } + }); + } + }; + return (
- +
Select availability + + +
{ />
- - {severityMessage} - - - @@ -340,6 +340,15 @@ const UploadDownloadZone = () => { > Download Template + +
); }; diff --git a/frontend/src/components/dashboard/UploadDownloadZone/dialog-upload.scss b/frontend/src/components/dashboard/UploadDownloadZone/dialog-upload.scss index fa173c19..7867e466 100644 --- a/frontend/src/components/dashboard/UploadDownloadZone/dialog-upload.scss +++ b/frontend/src/components/dashboard/UploadDownloadZone/dialog-upload.scss @@ -33,7 +33,7 @@ margin-left: auto; margin-right: auto; min-width: 250px; - overflow-y: auto; + //overflow-y: auto; .css-1sep8xo-MuiDialog-container { height: fit-content; diff --git a/frontend/src/components/dashboard/styles.scss b/frontend/src/components/dashboard/styles.scss index a8c6c875..e0d31286 100644 --- a/frontend/src/components/dashboard/styles.scss +++ b/frontend/src/components/dashboard/styles.scss @@ -43,9 +43,9 @@ padding: 10px; .left-map { + flex-direction: column; align-items: center; display: flex; - flex-direction: column; border-radius: 20px; margin-right: auto; margin-left: auto; @@ -53,6 +53,8 @@ background-color: rgba(20, 177, 245, 0.132); } .right-map { + flex-direction: column; + align-items: center; border-radius: 20px; margin-right: auto; margin-left: auto; diff --git a/frontend/src/components/services/EnvironmentService.js b/frontend/src/components/services/EnvironmentService.js index 5200098e..1e7058ff 100644 --- a/frontend/src/components/services/EnvironmentService.js +++ b/frontend/src/components/services/EnvironmentService.js @@ -50,7 +50,11 @@ export const getCountryRiskApi = () => { }; export const getLogoutLink = () => { - return LOCAL_SERVICES_FRONTEND + "/logout"; + return document.location.origin + "/logout"; +}; + +export const getNegotiationLink = () => { + return document.location.origin + "/negotiation"; }; export const getAboutLink = () => { diff --git a/frontend/src/components/services/UserService.js b/frontend/src/components/services/UserService.js index d5a7fe79..cfe4f0b8 100644 --- a/frontend/src/components/services/UserService.js +++ b/frontend/src/components/services/UserService.js @@ -24,9 +24,6 @@ import { ROLES } from "../../types/Constants"; import { getCentralIdp, getClientId, - getClientIdSemantic, - getClientIdDigitalTwin, - getCountryRiskClientId, getBpdmId, getCountryRiskAppId, } from "./EnvironmentService"; diff --git a/frontend/src/components/services/negotiation.js b/frontend/src/components/services/negotiation.js new file mode 100644 index 00000000..91459265 --- /dev/null +++ b/frontend/src/components/services/negotiation.js @@ -0,0 +1,62 @@ +/******************************************************************************** + * Copyright (c) 2022,2024 BMW Group AG + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +import axios from "axios"; +import { getCountryRiskApi } from "./EnvironmentService"; + +const API_BASE_URL = getCountryRiskApi(); // Update with your actual base URL + +// Function to fetch catalog items +export const fetchCatalogItems = async (authToken) => { + try { + const response = await axios.get( + `${API_BASE_URL}` + process.env.REACT_APP_GET_QUERY_CATALOG, + { + headers: { + Authorization: `Bearer ${authToken}`, // Assuming bearer token is used for auth + "Content-Type": "application/json", + }, + } + ); + return response.data; + } catch (error) { + console.error("Failed to fetch catalog items:", error); + throw error; + } +}; + +// Function to trigger negotiation with selected items +export const triggerNegotiation = async (selectedItems, authToken) => { + try { + const response = await axios.post( + `${API_BASE_URL}` + process.env.REACT_APP_POST_TRIGGER_NEGOTIATION, + selectedItems, + { + headers: { + Authorization: `Bearer ${authToken}`, // Assuming bearer token is used for auth + "Content-Type": "application/json", + }, + } + ); + return response.data; + } catch (error) { + console.error("Failed to trigger negotiation:", error); + throw error; + } +}; diff --git a/frontend/src/components/services/upload-api.js b/frontend/src/components/services/upload-api.js new file mode 100644 index 00000000..66fb1e1b --- /dev/null +++ b/frontend/src/components/services/upload-api.js @@ -0,0 +1,45 @@ +/******************************************************************************** + * Copyright (c) 2022,2024 BMW Group AG + * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +import axios from "axios"; +import { getCountryRiskApi } from "./EnvironmentService"; +import UserService from "./UserService"; + +// Uploads a CSV file to the server. +export function uploadCsvFile(file, ratingName, year, type, customerUser) { + const url = getCountryRiskApi() + process.env.REACT_APP_UPLOAD_FILE; + const formData = new FormData(); + formData.append("file", file); + + return axios.post(url, formData, { + params: { + name: customerUser.name, + email: customerUser.email, + companyName: customerUser.companyName, + }, + headers: { + "Content-Type": "multipart/form-data", + Authorization: `Bearer ${UserService.getToken()}`, + ratingName: ratingName, + year: year, + type: type, + }, + }); +} diff --git a/frontend/src/index.js b/frontend/src/index.js index f7fae170..774a314d 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -23,7 +23,8 @@ import ReactDOM from "react-dom/client"; import { SharedThemeProvider, SharedCssBaseline, -} from "cx-portal-shared-components"; +} from "@catena-x/portal-shared-components"; + import UserService from "./components/services/UserService"; import { getHostname } from "./components/services/EnvironmentService"; @@ -42,7 +43,6 @@ UserService.init((user) => { root.render( {" "} - {" "} {" "} From e5298d095c666b3f313d3fd0a1d467d94e89c2b5 Mon Sep 17 00:00:00 2001 From: "fabio.d.mota" Date: Tue, 7 May 2024 17:13:04 +0100 Subject: [PATCH 2/2] fix(frontend): Fix codeQL finding --- frontend/src/components/dashboard/Ratings/ratingUserColumns.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/components/dashboard/Ratings/ratingUserColumns.js b/frontend/src/components/dashboard/Ratings/ratingUserColumns.js index fe37aed0..62b81e04 100644 --- a/frontend/src/components/dashboard/Ratings/ratingUserColumns.js +++ b/frontend/src/components/dashboard/Ratings/ratingUserColumns.js @@ -17,10 +17,9 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -import { IconButton } from "@catena-x/portal-shared-components"; + import DeleteIcon from "@mui/icons-material/DeleteOutlineOutlined"; import { GridActionsCellItem } from "@mui/x-data-grid"; -import { useCallback } from "react"; export const columnsUser = (rates, onClickDelete) => [ {