From ef71b8b5e802bd60f6a296242256304f04387bae Mon Sep 17 00:00:00 2001 From: Tristan <135599584+Tristan-WorkGH@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:51:23 +0200 Subject: [PATCH] Remove old authentication flag and update fn call (#34) & Update commons-ui ts (#39) Co-authored-by: Joris Mancini --- jest.config.ts | 5 +- jest.setup.ts | 2 +- package-lock.json | 214 +++++++++++++++--- package.json | 4 +- src/components/App/app-top-bar.tsx | 9 +- src/components/App/app-wrapper.tsx | 10 +- src/components/App/app.tsx | 3 +- src/module-mui.d.ts | 6 + .../modification/custom-mui-dialog.tsx | 120 ---------- .../modification/parameter-selection.tsx | 12 +- .../profile-modification-dialog.tsx | 29 +-- src/redux/actions.ts | 13 +- src/redux/local-storage.ts | 27 ++- src/redux/reducer.ts | 56 +++-- src/redux/store.ts | 1 + src/routes/index.ts | 7 - src/routes/router.tsx | 40 ++-- src/services/apps-metadata.ts | 50 ++-- src/services/config.ts | 7 +- src/services/directory.ts | 50 +--- src/services/explore.ts | 43 ---- src/services/index.ts | 18 +- src/services/study.ts | 31 +-- src/services/user-admin.ts | 2 +- src/utils/api-rest.ts | 2 +- src/utils/api.ts | 6 +- src/utils/language.ts | 18 +- 27 files changed, 354 insertions(+), 431 deletions(-) delete mode 100644 src/pages/profiles/modification/custom-mui-dialog.tsx delete mode 100644 src/services/explore.ts diff --git a/jest.config.ts b/jest.config.ts index 2cc59da..1665132 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -13,9 +13,8 @@ const config: Config = { '^.+\\.svg\\?react$': 'jest-svg-transformer', '^.+\\.(css|less|scss)$': 'identity-obj-proxy', }, - // if need to test with AG Grid, see https://www.ag-grid.com/react-data-grid/testing/ - transformIgnorePatterns: ['node_modules/(?!@gridsuite/commons-ui)'], // transform from ESM - moduleDirectories: ['node_modules', 'src'], // to allow absolute path from ./src + // see https://github.com/react-dnd/react-dnd/issues/3443 + transformIgnorePatterns: ['node_modules/(?!react-dnd)/'], setupFiles: ['/jest.setup.ts'], }; diff --git a/jest.setup.ts b/jest.setup.ts index 996e17f..5f3db9c 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { TextEncoder, TextDecoder } from 'util'; +import { TextEncoder, TextDecoder } from 'node:util'; // fix for ReferenceError: TextDecoder / TextEncoder is not defined Object.assign(global, { TextDecoder, TextEncoder }); diff --git a/package-lock.json b/package-lock.json index 6b721d8..524aa4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", - "@gridsuite/commons-ui": "0.53.0", + "@gridsuite/commons-ui": "0.63.0", "@hookform/resolvers": "^3.3.4", "@mui/icons-material": "^5.15.14", "@mui/lab": "5.0.0-alpha.169", @@ -2952,18 +2952,23 @@ } }, "node_modules/@gridsuite/commons-ui": { - "version": "0.53.0", - "resolved": "https://registry.npmjs.org/@gridsuite/commons-ui/-/commons-ui-0.53.0.tgz", - "integrity": "sha512-//BB1tsBxtNHINgVc3Wp3GsElr4ne2OiqFwL1Ykuf8Oq3xNyVMdds28hAKcnDrcKri+B+bsniDa3UjVvbsemUA==", + "version": "0.63.0", + "resolved": "https://registry.npmjs.org/@gridsuite/commons-ui/-/commons-ui-0.63.0.tgz", + "integrity": "sha512-+hO2HUv2D/rd1UX5BBw7O/FDbpUXrjCm/fVSAeBT/Ml72CROhva458aBPczkjb9sg/lxV8U3L2tRAwhyuuI/iQ==", "dependencies": { + "@react-querybuilder/dnd": "^7.2.0", + "@react-querybuilder/material": "^7.2.0", "autosuggest-highlight": "^3.3.4", "clsx": "^2.1.0", "jwt-decode": "^4.0.0", + "localized-countries": "^2.0.0", "memoize-one": "^6.0.0", "oidc-client": "^1.11.5", "prop-types": "^15.8.1", "react-csv-downloader": "^3.1.0", - "react-request-fullscreen": "^1.1.2", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-querybuilder": "^7.2.0", "react-virtualized": "^9.22.5", "uuid": "^9.0.1" }, @@ -2978,11 +2983,17 @@ "@mui/icons-material": "^5.15.14", "@mui/lab": "5.0.0-alpha.169", "@mui/material": "^5.15.14", + "@mui/system": "^5.15.15", + "@mui/x-tree-view": "^6.17.0", + "ag-grid-community": "^31.0.0", + "ag-grid-react": "^31.2.0", "notistack": "^3.0.1", + "papaparse": "^5.4.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.51.2", "react-intl": "^6.6.4", + "react-papaparse": "^4.1.0", "react-router-dom": "^6.22.3", "yup": "^1.4.0" } @@ -4345,15 +4356,54 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "node_modules/@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" + }, + "node_modules/@react-querybuilder/dnd": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@react-querybuilder/dnd/-/dnd-7.5.2.tgz", + "integrity": "sha512-7rMeZ6gFQow2jpz0exMQSq/f3MZEL5OuiWW6YOkDuFfJWPR7ijXV6Cz0x7TiFS7jbTD5Axr44u7nFCWx06hZeg==", + "peerDependencies": { + "react": ">=18", + "react-dnd": ">=14.0.0", + "react-dnd-html5-backend": ">=14.0.0", + "react-querybuilder": "7.5.0" + } + }, + "node_modules/@react-querybuilder/material": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@react-querybuilder/material/-/material-7.5.2.tgz", + "integrity": "sha512-wWjwKjaD5LIX9Lta3QE/smd9lYEWzIAR7A93XyHHwv8BtP1EQoZgjKogNCSuQZhfkrTT5U1n9g4uORCUk7Z9ZQ==", + "peerDependencies": { + "@emotion/react": "^11", + "@emotion/styled": "^11", + "@mui/icons-material": ">=5", + "@mui/material": ">=5", + "react": ">=18", + "react-querybuilder": "7.5.0" + } + }, "node_modules/@reduxjs/toolkit": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.3.tgz", - "integrity": "sha512-76dll9EnJXg4EVcI5YNxZA/9hSAmZsFqzMmNRHvIlzw2WS/twfcVX3ysYrWGJMClwEmChQFC4yRq74tn6fdzRA==", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.6.tgz", + "integrity": "sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA==", "dependencies": { "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", - "reselect": "^5.0.1" + "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18", @@ -5059,11 +5109,19 @@ "version": "18.19.31", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", - "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, + "node_modules/@types/papaparse": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz", + "integrity": "sha512-LxJ4iEFcpqc6METwp9f6BV6VVc43m6MfH0VqFosHvrUgfXiFe6ww7R3itkOQ+TCK6Y+Iv/+RnnvtRZnkc5Kc9g==", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -6670,9 +6728,9 @@ } }, "node_modules/clsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "engines": { "node": ">=6" } @@ -7133,6 +7191,24 @@ "node": ">=8" } }, + "node_modules/dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "dependencies": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, + "node_modules/dnd-core/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -8730,8 +8806,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-diff": { "version": "1.3.0", @@ -9338,9 +9413,9 @@ } }, "node_modules/immer": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz", - "integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -12159,6 +12234,11 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/localized-countries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/localized-countries/-/localized-countries-2.0.0.tgz", + "integrity": "sha512-17CwJ/oetI5cB6KmPa+Cxw/8vunawUouVv5MFxYqsVzryXeR5u/MF32m3SBaHxP4EqYPOePV+3jx7xxYZnAJpQ==" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -12488,6 +12568,14 @@ "node": ">=8" } }, + "node_modules/numeric-quantity": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/numeric-quantity/-/numeric-quantity-2.0.1.tgz", + "integrity": "sha512-+Bt2X6YxM5bg8XIBl76NVeG2eL0Y5VQRoyz6GLYrZXW/TDh7We+tGeX4/WZWhaVGOg5ZjNBEOZt9a86slMhOJA==", + "engines": { + "node": ">=16" + } + }, "node_modules/nwsapi": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", @@ -12721,6 +12809,12 @@ "node": ">=6" } }, + "node_modules/papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==", + "peer": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -13144,6 +13238,43 @@ "react": "^16.6.3 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-dnd": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "dependencies": { + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + }, + "peerDependencies": { + "@types/hoist-non-react-statics": ">= 3.3.1", + "@types/node": ">= 12", + "@types/react": ">= 16", + "react": ">= 16.14" + }, + "peerDependenciesMeta": { + "@types/hoist-non-react-statics": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", + "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "dependencies": { + "dnd-core": "^16.0.1" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -13207,10 +13338,39 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "node_modules/react-papaparse": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/react-papaparse/-/react-papaparse-4.4.0.tgz", + "integrity": "sha512-xTEwHZYJ+1dh9mQDQjjwJXmWyX20DdZ52u+ddw75V+Xm5qsjXSvWmC7c8K82vRwMjKAOH2S9uFyGpHEyEztkUQ==", + "peer": true, + "dependencies": { + "@types/papaparse": "^5.3.9", + "papaparse": "^5.4.1" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/react-querybuilder": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/react-querybuilder/-/react-querybuilder-7.5.0.tgz", + "integrity": "sha512-tWrwLf2dPkI1TYluW6Oy/Tif/Z0X8OBoDXkh2C/oloAItPJEmKAcInuIYOlEKDVK6KM6lHJsGNBmApuMWY5c/g==", + "dependencies": { + "@reduxjs/toolkit": "^2.2.5", + "clsx": "^2.1.1", + "immer": "^10.1.1", + "numeric-quantity": "^2.0.1", + "react-redux": "^9.1.2" + }, + "peerDependencies": { + "react": ">=18" + } + }, "node_modules/react-redux": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.1.tgz", - "integrity": "sha512-5ynfGDzxxsoV73+4czQM56qF43vsmgJsO22rmAvU5tZT2z5Xow/A2uhhxwXuGTxgdReF3zcp7A80gma2onRs1A==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", "dependencies": { "@types/use-sync-external-store": "^0.0.3", "use-sync-external-store": "^1.0.0" @@ -13218,16 +13378,12 @@ "peerDependencies": { "@types/react": "^18.2.25", "react": "^18.0", - "react-native": ">=0.69", "redux": "^5.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true }, - "react-native": { - "optional": true - }, "redux": { "optional": true } @@ -13242,11 +13398,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-request-fullscreen": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/react-request-fullscreen/-/react-request-fullscreen-1.1.2.tgz", - "integrity": "sha512-WsQ/htbZag9qNfWPb2fEm0if+oUsRK3rTKKJ007n64Mk0PY82gAbLwVKZ+7OmzkHm6f/PSkxf8pdYlzBUmXR/Q==" - }, "node_modules/react-router": { "version": "6.22.3", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", @@ -14590,8 +14741,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", diff --git a/package.json b/package.json index e8616ca..a89def3 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", - "@gridsuite/commons-ui": "0.53.0", + "@gridsuite/commons-ui": "0.63.0", "@hookform/resolvers": "^3.3.4", "@mui/icons-material": "^5.15.14", "@mui/lab": "5.0.0-alpha.169", @@ -85,8 +85,8 @@ "jest-environment-jsdom": "^29.7.0", "jest-svg-transformer": "^1.0.0", "prettier": "^2.8.8", - "typescript": "5.1.6", "ts-node": "^10.9.2", + "typescript": "5.1.6", "vite": "^5.2.7", "vite-plugin-eslint": "^1.8.1", "vite-plugin-svgr": "^4.2.0", diff --git a/src/components/App/app-top-bar.tsx b/src/components/App/app-top-bar.tsx index c79403b..99d1f68 100644 --- a/src/components/App/app-top-bar.tsx +++ b/src/components/App/app-top-bar.tsx @@ -31,6 +31,7 @@ import GridAdminLogoDark from '../../images/GridAdmin_logo_dark.svg?react'; import AppPackage from '../../../package.json'; import { AppState } from '../../redux/reducer'; import { MainPaths } from '../../routes'; +import { AppDispatch } from '../../redux/store'; const tabs = new Map([ [ @@ -65,7 +66,7 @@ const tabs = new Map([ const AppTopBar: FunctionComponent = () => { const theme = useTheme(); - const dispatch = useDispatch(); + const dispatch = useDispatch(); const user = useSelector((state: AppState) => state.user); const userManagerInstance = useSelector( (state: AppState) => state.userManager?.instance @@ -110,10 +111,12 @@ const AppTopBar: FunctionComponent = () => { appLicense={AppPackage.license} onLogoutClick={() => logout(dispatch, userManagerInstance)} onLogoClick={() => navigate('/', { replace: true })} - user={user} + user={user ?? undefined} appsAndUrls={appsAndUrls} globalVersionPromise={() => - AppsMetadataSrv.fetchVersion().then((res) => res?.deployVersion) + AppsMetadataSrv.fetchVersion().then( + (res) => res?.deployVersion ?? 'unknown' + ) } additionalModulesPromise={StudySrv.getServersInfos} onThemeClick={handleChangeTheme} diff --git a/src/components/App/app-wrapper.tsx b/src/components/App/app-wrapper.tsx index 230a159..9e8f8c8 100644 --- a/src/components/App/app-wrapper.tsx +++ b/src/components/App/app-wrapper.tsx @@ -19,6 +19,8 @@ import { card_error_boundary_en, card_error_boundary_fr, CardErrorBoundary, + GsLangUser, + GsTheme, LANG_ENGLISH, LANG_FRENCH, LIGHT_THEME, @@ -28,14 +30,12 @@ import { top_bar_en, top_bar_fr, } from '@gridsuite/commons-ui'; -import { IntlProvider } from 'react-intl'; +import { IntlConfig, IntlProvider } from 'react-intl'; import { Provider, useSelector } from 'react-redux'; -import { SupportedLanguages } from '../../utils/language'; import messages_en from '../../translations/en.json'; import messages_fr from '../../translations/fr.json'; import { store } from '../../redux/store'; import { PARAM_THEME } from '../../utils/config-params'; -import { IntlConfig } from 'react-intl/src/types'; import { AppState } from '../../redux/reducer'; import { AppWithAuthRouter } from '../../routes'; @@ -91,7 +91,7 @@ const darkTheme: ThemeOptions = { agGridTheme: 'ag-theme-alpine-dark', }; -const getMuiTheme = (theme: unknown, locale: SupportedLanguages): Theme => { +const getMuiTheme = (theme: GsTheme, locale: GsLangUser): Theme => { return responsiveFontSizes( createTheme( theme === LIGHT_THEME ? lightTheme : darkTheme, @@ -100,7 +100,7 @@ const getMuiTheme = (theme: unknown, locale: SupportedLanguages): Theme => { ); }; -const messages: Record = { +const messages: Record = { en: { ...messages_en, ...login_en, diff --git a/src/components/App/app.tsx b/src/components/App/app.tsx index 220e633..64da484 100644 --- a/src/components/App/app.tsx +++ b/src/components/App/app.tsx @@ -31,11 +31,12 @@ import { getComputedLanguage } from '../../utils/language'; import AppTopBar from './app-top-bar'; import ReconnectingWebSocket from 'reconnecting-websocket'; import { useDebugRender } from '../../utils/hooks'; +import { AppDispatch } from '../../redux/store'; const App: FunctionComponent> = (props, context) => { useDebugRender('app'); const { snackError } = useSnackMessage(); - const dispatch = useDispatch(); + const dispatch = useDispatch(); const user = useSelector((state: AppState) => state.user); const updateParams = useCallback( diff --git a/src/module-mui.d.ts b/src/module-mui.d.ts index 9f55452..7d430b4 100644 --- a/src/module-mui.d.ts +++ b/src/module-mui.d.ts @@ -24,3 +24,9 @@ declare module '@mui/material/styles/createTheme' { extends MuiThemeOptions, Partial {} } + +declare module '@mui/utils/capitalize' { + export default function capitalize( + string: S + ): Capitalize; +} diff --git a/src/pages/profiles/modification/custom-mui-dialog.tsx b/src/pages/profiles/modification/custom-mui-dialog.tsx deleted file mode 100644 index 5a87cdc..0000000 --- a/src/pages/profiles/modification/custom-mui-dialog.tsx +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Copyright (c) 2024, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -// TODO: this file is going to be available soon in commons-ui - -import { FunctionComponent } from 'react'; -import { FieldErrors, FormProvider } from 'react-hook-form'; -import { FormattedMessage } from 'react-intl'; -import { - DialogActions, - DialogContent, - Grid, - LinearProgress, - Dialog, - DialogTitle, -} from '@mui/material'; -import { CancelButton, SubmitButton } from '@gridsuite/commons-ui'; - -interface ICustomMuiDialog { - open: boolean; - formSchema: any; - formMethods: any; - onClose: (event: React.MouseEvent) => void; - onSave: (data: any) => void; - onValidationError?: (errors: FieldErrors) => void; - titleId: string; - disabledSave?: boolean; - removeOptional?: boolean; - onCancel?: () => void; - children: React.ReactNode; - isDataFetching?: boolean; -} - -const styles = { - dialogPaper: { - '.MuiDialog-paper': { - width: 'auto', - minWidth: '800px', - margin: 'auto', - }, - }, -}; - -const CustomMuiDialog: FunctionComponent = ({ - open, - formSchema, - formMethods, - onClose, - onSave, - isDataFetching = false, - onValidationError, - titleId, - disabledSave, - removeOptional = false, - onCancel, - children, -}) => { - const { handleSubmit } = formMethods; - - const handleCancel = (event: React.MouseEvent) => { - onCancel && onCancel(); - onClose(event); - }; - - const handleClose = (event: React.MouseEvent, reason?: string) => { - if (reason === 'backdropClick' && onCancel) { - onCancel(); - } - onClose(event); - }; - - const handleValidate = (data: any) => { - onSave(data); - onClose(data); - }; - - const handleValidationError = (errors: FieldErrors) => { - onValidationError && onValidationError(errors); - }; - - return ( - - - {isDataFetching && } - - - - - - {children} - - - - - - - ); -}; - -export default CustomMuiDialog; diff --git a/src/pages/profiles/modification/parameter-selection.tsx b/src/pages/profiles/modification/parameter-selection.tsx index 688d3eb..bcf9f62 100644 --- a/src/pages/profiles/modification/parameter-selection.tsx +++ b/src/pages/profiles/modification/parameter-selection.tsx @@ -12,12 +12,7 @@ import { Grid, IconButton, Tooltip } from '@mui/material'; import { useIntl } from 'react-intl'; import { DirectoryItemSelector, ElementType } from '@gridsuite/commons-ui'; import { useController, useWatch } from 'react-hook-form'; -import { - fetchDirectoryContent, - fetchPath, - fetchRootFolders, -} from 'services/directory'; -import { fetchElementsInfos } from 'services/explore'; +import { DirectorySrv } from '../../../services'; import LinkedPathDisplay from './linked-path-display'; export interface ParameterSelectionProps { @@ -50,7 +45,7 @@ const ParameterSelection: FunctionComponent = ( setSelectedElementName(undefined); setParameterLinkValid(undefined); } else { - fetchPath(watchParamId) + DirectorySrv.fetchPath(watchParamId) .then((res: any) => { setParameterLinkValid(true); setSelectedElementName( @@ -140,9 +135,6 @@ const ParameterSelection: FunctionComponent = ( contentText={intl.formatMessage({ id: 'profiles.form.modification.parameterSelection.dialog.message', })} - fetchDirectoryContent={fetchDirectoryContent} - fetchRootFolders={fetchRootFolders} - fetchElementsInfos={fetchElementsInfos} /> ); diff --git a/src/pages/profiles/modification/profile-modification-dialog.tsx b/src/pages/profiles/modification/profile-modification-dialog.tsx index 9c7330f..e0f5db6 100644 --- a/src/pages/profiles/modification/profile-modification-dialog.tsx +++ b/src/pages/profiles/modification/profile-modification-dialog.tsx @@ -10,7 +10,7 @@ import ProfileModificationForm, { PROFILE_NAME, USER_QUOTAS, } from './profile-modification-form'; -import yup from 'utils/yup-config'; +import yup from '../../../utils/yup-config'; import { yupResolver } from '@hookform/resolvers/yup'; import { useForm } from 'react-hook-form'; import { @@ -20,18 +20,17 @@ import { useMemo, useState, } from 'react'; -import { useSnackMessage } from '@gridsuite/commons-ui'; -import { getProfile, modifyProfile, UserProfile } from 'services/user-admin'; -import CustomMuiDialog from './custom-mui-dialog'; +import { CustomMuiDialog, useSnackMessage } from '@gridsuite/commons-ui'; +import { UserAdminSrv, UserProfile } from '../../../services'; import { UUID } from 'crypto'; -// TODO remove FetchStatus when available in commons-ui (available soon) -export const FetchStatus = { - IDLE: 'IDLE', - FETCHING: 'FETCHING', - FETCH_SUCCESS: 'FETCH_SUCCESS', - FETCH_ERROR: 'FETCH_ERROR', -}; +// TODO remove FetchStatus when exported in commons-ui (available soon) +export enum FetchStatus { + IDLE = 'IDLE', + FETCHING = 'FETCHING', + FETCH_SUCCESS = 'FETCH_SUCCESS', + FETCH_ERROR = 'FETCH_ERROR', +} export interface ProfileModificationDialogProps { profileId: UUID | undefined; @@ -44,7 +43,9 @@ const ProfileModificationDialog: FunctionComponent< ProfileModificationDialogProps > = ({ profileId, open, onClose, onUpdate }) => { const { snackError } = useSnackMessage(); - const [dataFetchStatus, setDataFetchStatus] = useState(FetchStatus.IDLE); + const [dataFetchStatus, setDataFetchStatus] = useState( + FetchStatus.IDLE + ); const formSchema = yup .object() @@ -73,7 +74,7 @@ const ProfileModificationDialog: FunctionComponent< loadFlowParameterId: profileFormData[LF_PARAM_ID], maxAllowedCases: profileFormData[USER_QUOTAS], }; - modifyProfile(profileData) + UserAdminSrv.modifyProfile(profileData) .catch((error) => { snackError({ messageTxt: error.message, @@ -96,7 +97,7 @@ const ProfileModificationDialog: FunctionComponent< useEffect(() => { if (profileId && open) { setDataFetchStatus(FetchStatus.FETCHING); - getProfile(profileId) + UserAdminSrv.getProfile(profileId) .then((response) => { setDataFetchStatus(FetchStatus.FETCH_SUCCESS); reset({ diff --git a/src/redux/actions.ts b/src/redux/actions.ts index 6860ecd..841435b 100644 --- a/src/redux/actions.ts +++ b/src/redux/actions.ts @@ -5,10 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { GsTheme, UserManagerState } from '@gridsuite/commons-ui'; import { PARAM_LANGUAGE } from '../utils/config-params'; import { Action } from 'redux'; import { AppState } from './reducer'; -import { UserManagerState } from '../routes'; export const UPDATE_USER_MANAGER_STATE = 'UPDATE_USER_MANAGER_STATE'; export type UserManagerAction = Readonly< @@ -16,11 +16,13 @@ export type UserManagerAction = Readonly< > & { userManager: UserManagerState; }; + export function updateUserManager( userManager: UserManagerState ): UserManagerAction { return { type: UPDATE_USER_MANAGER_STATE, userManager }; } + export function updateUserManagerDestructured( instance: UserManagerState['instance'], error: UserManagerState['error'] @@ -32,6 +34,7 @@ export const UPDATE_USER_MANAGER_INSTANCE = 'UPDATE_USER_MANAGER_INSTANCE'; export type UserManagerInstanceAction = Readonly< Action > & { instance: UserManagerState['instance'] }; + export function updateUserManagerInstance( instance: UserManagerState['instance'] ): UserManagerInstanceAction { @@ -42,6 +45,7 @@ export const UPDATE_USER_MANAGER_ERROR = 'UPDATE_USER_MANAGER_ERROR'; export type UserManagerErrorAction = Readonly< Action > & { error: UserManagerState['error'] }; + export function updateUserManagerError( error: UserManagerState['error'] ): UserManagerErrorAction { @@ -50,9 +54,10 @@ export function updateUserManagerError( export const SELECT_THEME = 'SELECT_THEME'; export type ThemeAction = Readonly> & { - theme: string; + theme: GsTheme; }; -export function selectTheme(theme: string): ThemeAction { + +export function selectTheme(theme: GsTheme): ThemeAction { return { type: SELECT_THEME, theme: theme }; } @@ -60,6 +65,7 @@ export const SELECT_LANGUAGE = 'SELECT_LANGUAGE'; export type LanguageAction = Readonly> & { [PARAM_LANGUAGE]: AppState['language']; }; + export function selectLanguage(language: AppState['language']): LanguageAction { return { type: SELECT_LANGUAGE, [PARAM_LANGUAGE]: language }; } @@ -70,6 +76,7 @@ export type ComputedLanguageAction = Readonly< > & { computedLanguage: AppState['computedLanguage']; }; + export function selectComputedLanguage( computedLanguage: AppState['computedLanguage'] ): ComputedLanguageAction { diff --git a/src/redux/local-storage.ts b/src/redux/local-storage.ts index 2d21268..f567b52 100644 --- a/src/redux/local-storage.ts +++ b/src/redux/local-storage.ts @@ -5,30 +5,39 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { DARK_THEME, LANG_SYSTEM } from '@gridsuite/commons-ui'; +import { + DARK_THEME, + GsLang, + GsTheme, + LANG_SYSTEM, +} from '@gridsuite/commons-ui'; import { getComputedLanguage } from '../utils/language'; import { APP_NAME } from '../utils/config-params'; -import { AppState } from './reducer'; const LOCAL_STORAGE_THEME_KEY = (APP_NAME + '_THEME').toUpperCase(); const LOCAL_STORAGE_LANGUAGE_KEY = (APP_NAME + '_LANGUAGE').toUpperCase(); -export function getLocalStorageTheme(): string { - return localStorage.getItem(LOCAL_STORAGE_THEME_KEY) || DARK_THEME; +export function getLocalStorageTheme() { + return ( + (localStorage.getItem(LOCAL_STORAGE_THEME_KEY) as GsTheme) || DARK_THEME + ); } -export function saveLocalStorageTheme(theme: string): void { +export function saveLocalStorageTheme(theme: GsTheme): void { localStorage.setItem(LOCAL_STORAGE_THEME_KEY, theme); } -export function getLocalStorageLanguage(): AppState['language'] { - return localStorage.getItem(LOCAL_STORAGE_LANGUAGE_KEY) || LANG_SYSTEM; +export function getLocalStorageLanguage() { + return ( + (localStorage.getItem(LOCAL_STORAGE_LANGUAGE_KEY) as GsLang) || + LANG_SYSTEM + ); } -export function saveLocalStorageLanguage(language: AppState['language']): void { +export function saveLocalStorageLanguage(language: GsLang): void { localStorage.setItem(LOCAL_STORAGE_LANGUAGE_KEY, language); } -export function getLocalStorageComputedLanguage(): AppState['computedLanguage'] { +export function getLocalStorageComputedLanguage() { return getComputedLanguage(getLocalStorageLanguage()); } diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index 02fead2..db8844e 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -5,8 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { AnyAction, createReducer, Draft } from '@reduxjs/toolkit'; - +import { createReducer, Draft } from '@reduxjs/toolkit'; import { getLocalStorageComputedLanguage, getLocalStorageLanguage, @@ -27,31 +26,40 @@ import { UserManagerErrorAction, UserManagerInstanceAction, } from './actions'; - import { + AuthenticationActions, + AuthenticationRouterErrorAction, + AuthenticationRouterErrorState, + CommonStoreState, + GsLang, + GsLangUser, + GsTheme, LOGOUT_ERROR, + LogoutErrorAction, RESET_AUTHENTICATION_ROUTER_ERROR, SHOW_AUTH_INFO_LOGIN, + ShowAuthenticationRouterLoginAction, SIGNIN_CALLBACK_ERROR, + SignInCallbackErrorAction, UNAUTHORIZED_USER_INFO, + UnauthorizedUserAction, USER, USER_VALIDATION_ERROR, + UserAction, + UserManagerState, + UserValidationErrorAction, } from '@gridsuite/commons-ui'; import { PARAM_LANGUAGE, PARAM_THEME } from '../utils/config-params'; import { ReducerWithInitialState } from '@reduxjs/toolkit/dist/createReducer'; -import { LanguageParameters, SupportedLanguages } from '../utils/language'; -import { User } from '../utils/auth'; -import { UserManagerState } from '../routes'; -export type AppState = { - computedLanguage: SupportedLanguages; - [PARAM_THEME]: string; - [PARAM_LANGUAGE]: LanguageParameters; +export type AppState = CommonStoreState & { + computedLanguage: GsLangUser; + [PARAM_THEME]: GsTheme; + [PARAM_LANGUAGE]: GsLang; userManager: UserManagerState; - user: User | null; //TODO delete when migrated into commons-ui - signInCallbackError: unknown; - authenticationRouterError: unknown; + signInCallbackError: Error | null; + authenticationRouterError: AuthenticationRouterErrorState | null; showAuthenticationRouterLogin: boolean; }; @@ -73,7 +81,7 @@ const initialState: AppState = { }; export type Actions = - | AnyAction + | AuthenticationActions | UserManagerAction | UserManagerInstanceAction | UserManagerErrorAction @@ -115,20 +123,20 @@ export const reducer: ReducerWithInitialState = createReducer( } ); - builder.addCase(USER, (state: Draft, action: AnyAction) => { + builder.addCase(USER, (state: Draft, action: UserAction) => { state.user = action.user; }); builder.addCase( SIGNIN_CALLBACK_ERROR, - (state: Draft, action: AnyAction) => { + (state: Draft, action: SignInCallbackErrorAction) => { state.signInCallbackError = action.signInCallbackError; } ); builder.addCase( UNAUTHORIZED_USER_INFO, - (state: Draft, action: AnyAction) => { + (state: Draft, action: UnauthorizedUserAction) => { state.authenticationRouterError = action.authenticationRouterError; } @@ -136,7 +144,7 @@ export const reducer: ReducerWithInitialState = createReducer( builder.addCase( LOGOUT_ERROR, - (state: Draft, action: AnyAction) => { + (state: Draft, action: LogoutErrorAction) => { state.authenticationRouterError = action.authenticationRouterError; } @@ -144,7 +152,7 @@ export const reducer: ReducerWithInitialState = createReducer( builder.addCase( USER_VALIDATION_ERROR, - (state: Draft, action: AnyAction) => { + (state: Draft, action: UserValidationErrorAction) => { state.authenticationRouterError = action.authenticationRouterError; } @@ -152,14 +160,20 @@ export const reducer: ReducerWithInitialState = createReducer( builder.addCase( RESET_AUTHENTICATION_ROUTER_ERROR, - (state: Draft, action: AnyAction) => { + ( + state: Draft, + action: AuthenticationRouterErrorAction + ) => { state.authenticationRouterError = null; } ); builder.addCase( SHOW_AUTH_INFO_LOGIN, - (state: Draft, action: AnyAction) => { + ( + state: Draft, + action: ShowAuthenticationRouterLoginAction + ) => { state.showAuthenticationRouterLogin = action.showAuthenticationRouterLogin; } diff --git a/src/redux/store.ts b/src/redux/store.ts index 5142786..7783850 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -9,6 +9,7 @@ import { createStore, Store } from 'redux'; import { Actions, AppState, reducer } from './reducer'; export const store: Store = createStore(reducer); +export type AppDispatch = typeof store.dispatch; // to avoid to reset the state with HMR // https://redux.js.org/usage/configuring-your-store#hot-reloading diff --git a/src/routes/index.ts b/src/routes/index.ts index 6aba229..30825e5 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -5,11 +5,4 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { UserManager } from 'oidc-client'; - export * from './router'; - -export type UserManagerState = { - instance: UserManager | null; - error: string | null; -}; diff --git a/src/routes/router.tsx b/src/routes/router.tsx index 3695585..20de342 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -28,16 +28,16 @@ import { useMatch, useNavigate, } from 'react-router-dom'; -import { UserManager } from 'oidc-client'; import { useDispatch, useSelector } from 'react-redux'; import { AppState } from '../redux/reducer'; import { AppsMetadataSrv, UserAdminSrv } from '../services'; import { App } from '../components/App'; -import { Users, Profiles } from '../pages'; +import { Profiles, Users } from '../pages'; import ErrorPage from './ErrorPage'; import { updateUserManagerDestructured } from '../redux/actions'; import HomePage from './HomePage'; import { getErrorMessage } from '../utils/error'; +import { AppDispatch } from '../redux/store'; export enum MainPaths { users = 'users', @@ -98,7 +98,7 @@ const AuthRouter: FunctionComponent<{ const showAuthenticationRouterLogin = useSelector( (state: AppState) => state.showAuthenticationRouterLogin ); - const dispatch = useDispatch(); + const dispatch = useDispatch(); const navigate = useNavigate(); const location = useLocation(); @@ -123,7 +123,7 @@ const AppAuthStateWithRouterLayer: FunctionComponent< PropsWithChildren<{ layout: App }> > = (props, context) => { const AppRouterLayout = props.layout; - const dispatch = useDispatch(); + const dispatch = useDispatch(); // Can't use lazy initializer because useMatch is a hook const [initialMatchSilentRenewCallbackUrl] = useState( @@ -138,27 +138,27 @@ const AppAuthStateWithRouterLayer: FunctionComponent< ); useEffect(() => { - AppsMetadataSrv.fetchAuthorizationCodeFlowFeatureFlag() - .then((authorizationCodeFlowEnabled) => - initializeAuthenticationProd( - dispatch, - initialMatchSilentRenewCallbackUrl != null, - fetch('idpSettings.json'), - UserAdminSrv.fetchValidateUser, - authorizationCodeFlowEnabled, - initialMatchSignInCallbackUrl != null - ) - ) - .then((userManager: UserManager | undefined) => { + // need subfunction when async as suggested by rule react-hooks/exhaustive-deps + (async function initializeAuthentication() { + try { dispatch( - updateUserManagerDestructured(userManager ?? null, null) + updateUserManagerDestructured( + (await initializeAuthenticationProd( + dispatch, + initialMatchSilentRenewCallbackUrl != null, + AppsMetadataSrv.fetchIdpSettings, + UserAdminSrv.fetchValidateUser, + initialMatchSignInCallbackUrl != null + )) ?? null, + null + ) ); - }) - .catch((error: any) => { + } catch (error: unknown) { dispatch( updateUserManagerDestructured(null, getErrorMessage(error)) ); - }); + } + })(); // Note: initialize and initialMatchSilentRenewCallbackUrl & initialMatchSignInCallbackUrl won't change }, [ dispatch, diff --git a/src/services/apps-metadata.ts b/src/services/apps-metadata.ts index 86ac4fe..c28fe21 100644 --- a/src/services/apps-metadata.ts +++ b/src/services/apps-metadata.ts @@ -5,51 +5,29 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { Env } from '@gridsuite/commons-ui'; import { getErrorMessage } from '../utils/error'; import { Url } from '../utils/api-rest'; -export type EnvJson = typeof import('../../public/env.json') & { - // https://github.com/gridsuite/deployment/blob/main/docker-compose/env.json - // https://github.com/gridsuite/deployment/blob/main/k8s/live/azure-dev/env.json - // https://github.com/gridsuite/deployment/blob/main/k8s/live/azure-integ/env.json - // https://github.com/gridsuite/deployment/blob/main/k8s/live/local/env.json - appsMetadataServerUrl?: Url; - mapBoxToken?: string; - //[key: string]: string; +// TODO remove when exported in commons-ui (src/utils/AuthService.ts) +type IdpSettings = { + authority: string; + client_id: string; + redirect_uri: string; + post_logout_redirect_uri: string; + silent_redirect_uri: string; + scope: string; + maxExpiresIn?: number; }; +export type EnvJson = Env & typeof import('../../public/env.json'); + function fetchEnv(): Promise { return fetch('env.json').then((res: Response) => res.json()); } -export function fetchAuthorizationCodeFlowFeatureFlag(): Promise { - console.debug('Fetching authorization code flow feature flag...'); - return fetchEnv() - .then((env: EnvJson) => - fetch(`${env.appsMetadataServerUrl}/authentication.json`) - ) - .then((res: Response) => res.json()) - .then((res: { authorizationCodeFlowFeatureFlag: boolean }) => { - console.info( - `Authorization code flow is ${ - res.authorizationCodeFlowFeatureFlag - ? 'enabled' - : 'disabled' - }` - ); - return res.authorizationCodeFlowFeatureFlag || false; - }) - .catch((error) => { - console.error( - `Error while fetching the authentication code flow: ${getErrorMessage( - error - )}` - ); - console.warn( - 'Something wrong happened when retrieving authentication.json: authorization code flow will be disabled' - ); - return false; - }); +export function fetchIdpSettings(): Promise { + return fetch('idpSettings.json').then((res) => res.json()); } export type VersionJson = { diff --git a/src/services/config.ts b/src/services/config.ts index 094969a..0152f02 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { GsLang, GsTheme } from '@gridsuite/commons-ui'; import { APP_NAME, getAppName, @@ -12,7 +13,6 @@ import { PARAM_THEME, } from '../utils/config-params'; import { backendFetch, backendFetchJson, getRestBase } from '../utils/api-rest'; -import { LanguageParameters } from '../utils/language'; const PREFIX_CONFIG_QUERIES = `${getRestBase()}/config`; @@ -20,13 +20,14 @@ const PREFIX_CONFIG_QUERIES = `${getRestBase()}/config`; export type ConfigParameter = | { readonly name: typeof PARAM_LANGUAGE; - value: LanguageParameters; + value: GsLang; } | { readonly name: typeof PARAM_THEME; - value: string; + value: GsTheme; }; export type ConfigParameters = ConfigParameter[]; + export function fetchConfigParameters( appName: string = APP_NAME ): Promise { diff --git a/src/services/directory.ts b/src/services/directory.ts index aa9ace8..a379812 100644 --- a/src/services/directory.ts +++ b/src/services/directory.ts @@ -7,15 +7,10 @@ import { backendFetchJson, getRestBase } from '../utils/api-rest'; import { UUID } from 'crypto'; +import { ElementAttributes } from '@gridsuite/commons-ui'; const DIRECTORY_URL = `${getRestBase()}/directory/v1`; -export type ElementAttributes = { - elementUuid: UUID; - elementName: string; - type: string; -}; - export function fetchPath(elementUuid: UUID): Promise { console.debug(`Fetching element and its parents info...`); return backendFetchJson(`${DIRECTORY_URL}/elements/${elementUuid}/path`, { @@ -28,46 +23,3 @@ export function fetchPath(elementUuid: UUID): Promise { throw reason; }) as Promise; } - -export function fetchRootFolders( - types: string[] // should be ElementType[] -): Promise { - console.info('Fetching Root Directories...'); - const urlSearchParams = new URLSearchParams( - types?.length ? types.map((param) => ['elementTypes', param]) : [] - ); - return backendFetchJson( - `${DIRECTORY_URL}/root-directories?${urlSearchParams}`, - { - headers: { - Accept: 'application/json', - }, - cache: 'default', - } - ).catch((reason) => { - console.error(`Error while fetching the servers data : ${reason}`); - throw reason; - }) as Promise; -} - -export function fetchDirectoryContent( - directoryUuid: UUID, - types: string[] // should be ElementType[] -): Promise { - console.info('Fetching Directory content...'); - const urlSearchParams = new URLSearchParams( - types?.length ? types.map((param) => ['elementTypes', param]) : [] - ); - return backendFetchJson( - `${DIRECTORY_URL}/directories/${directoryUuid}/elements?${urlSearchParams}`, - { - headers: { - Accept: 'application/json', - }, - cache: 'default', - } - ).catch((reason) => { - console.error(`Error while fetching the servers data : ${reason}`); - throw reason; - }) as Promise; -} diff --git a/src/services/explore.ts b/src/services/explore.ts deleted file mode 100644 index c9f5aa8..0000000 --- a/src/services/explore.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2024, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { backendFetchJson, getRestBase } from '../utils/api-rest'; -import { UUID } from 'crypto'; - -const EXPLORE_URL = `${getRestBase()}/explore/v1`; - -export type ElementAttributes = { - elementUuid: UUID; - elementName: string; - type: string; -}; - -export function fetchElementsInfos( - ids: UUID[], - elementTypes: string[] // should be ElementType[] -): Promise { - console.info('Fetching elements metadata...'); - const tmp = ids?.filter((id) => id); - const idsParams = tmp?.length ? tmp.map((id) => ['ids', id]) : []; - const elementTypesParams = elementTypes?.length - ? elementTypes.map((type) => ['elementTypes', type]) - : []; - const params = [...idsParams, ...elementTypesParams]; - const urlSearchParams = new URLSearchParams(params).toString(); - return backendFetchJson( - `${EXPLORE_URL}/explore/elements/metadata?${urlSearchParams}`, - { - headers: { - Accept: 'application/json', - }, - cache: 'default', - } - ).catch((reason) => { - console.error(`Error while fetching the servers data : ${reason}`); - throw reason; - }) as Promise; -} diff --git a/src/services/index.ts b/src/services/index.ts index c9ef2ba..78cb65a 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -1,18 +1,3 @@ -import * as Config from './config'; -import * as ConfigNotif from './config-notification'; -import * as AppsMetadata from './apps-metadata'; -import * as Study from './study'; -import * as UserAdmin from './user-admin'; - -const _ = { - ...Config, - ...ConfigNotif, - ...AppsMetadata, - ...Study, - ...UserAdmin, -}; -export default _; - export * as ConfigSrv from './config'; export type * from './config'; @@ -27,3 +12,6 @@ export type * from './study'; export * as UserAdminSrv from './user-admin'; export type * from './user-admin'; + +export * as DirectorySrv from './directory'; +export type * from './directory'; diff --git a/src/services/study.ts b/src/services/study.ts index 072844b..42712c4 100644 --- a/src/services/study.ts +++ b/src/services/study.ts @@ -5,35 +5,24 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { backendFetchJson, getRestBase, Token } from '../utils/api-rest'; +import { GridSuiteModule } from '@gridsuite/commons-ui'; +import { backendFetchJson, getRestBase } from '../utils/api-rest'; import { getErrorMessage } from '../utils/error'; import { APP_NAME } from '../utils/config-params'; const STUDY_URL = `${getRestBase()}/study/v1`; -//TODO delete when migrated into commons-ui -export type ServerAbout = { - type?: 'app' | 'server' | 'other'; - name?: string; - version?: string; - gitTag?: string; -}; - -export function getServersInfos(token: Token): Promise { - return backendFetchJson( - `${STUDY_URL}/servers/about?view=${APP_NAME}`, - { - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - cache: 'default', +export function getServersInfos() { + return backendFetchJson(`${STUDY_URL}/servers/about?view=${APP_NAME}`, { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', }, - token - ).catch((error) => { + cache: 'default', + }).catch((error) => { console.error( `Error while fetching the servers infos: ${getErrorMessage(error)}` ); throw error; - }) as Promise; + }) as Promise; } diff --git a/src/services/user-admin.ts b/src/services/user-admin.ts index 61ef52c..cb6b6da 100644 --- a/src/services/user-admin.ts +++ b/src/services/user-admin.ts @@ -5,9 +5,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { User } from 'oidc-client'; import { backendFetch, backendFetchJson, getRestBase } from '../utils/api-rest'; import { extractUserSub, getToken, getUser } from '../utils/api'; -import { User } from '../utils/auth'; import { UUID } from 'crypto'; const USER_ADMIN_URL = `${getRestBase()}/user-admin/v1`; diff --git a/src/utils/api-rest.ts b/src/utils/api-rest.ts index 4981318..7989c0d 100644 --- a/src/utils/api-rest.ts +++ b/src/utils/api-rest.ts @@ -7,7 +7,7 @@ import { getToken, parseError, Token } from './api'; -export type { Token, User } from './api'; +export type { Token } from './api'; export interface ErrorWithStatus extends Error { status?: number; diff --git a/src/utils/api.ts b/src/utils/api.ts index 606f628..6f9e7a5 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -5,22 +5,22 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { User } from 'oidc-client'; import { AppState } from '../redux/reducer'; import { store } from '../redux/store'; -export type User = AppState['user']; export type Token = string; export function getToken(user?: User): Token | null { return (user ?? getUser())?.id_token ?? null; } -export function getUser(): User { +export function getUser(): User | null { const state: AppState = store.getState(); return state.user; } -export function extractUserSub(user: User): Promise { +export function extractUserSub(user: User | null): Promise { return new Promise((resolve, reject) => { const sub = user?.profile?.sub; if (!sub) { diff --git a/src/utils/language.ts b/src/utils/language.ts index e1b4dbd..48f3ac3 100644 --- a/src/utils/language.ts +++ b/src/utils/language.ts @@ -5,21 +5,23 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { LANG_ENGLISH, LANG_FRENCH, LANG_SYSTEM } from '@gridsuite/commons-ui'; +import { + GsLang, + GsLangUser, + LANG_ENGLISH, + LANG_FRENCH, + LANG_SYSTEM, +} from '@gridsuite/commons-ui'; const supportedLanguages: string[] = [LANG_FRENCH, LANG_ENGLISH]; -export type SupportedLanguages = (typeof supportedLanguages)[number]; -export type LanguageParameters = SupportedLanguages | typeof LANG_SYSTEM; -export function getSystemLanguage(): SupportedLanguages { +export function getSystemLanguage(): GsLangUser { const systemLanguage = navigator.language.split(/[-_]/)[0]; return supportedLanguages.includes(systemLanguage) - ? systemLanguage + ? (systemLanguage as GsLangUser) : LANG_ENGLISH; } -export function getComputedLanguage( - language: LanguageParameters -): SupportedLanguages { +export function getComputedLanguage(language: GsLang): GsLangUser { return language === LANG_SYSTEM ? getSystemLanguage() : language; }