From 8915ae1cb996f57dde250301073452a95888eea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Dombya?= <135591453+hervedombya@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:23:05 +0100 Subject: [PATCH] ARTESCA-13969 // Migration to React 18 ARTESCA-13969 // Migration to React 18 refactor: update NotificationCenter styles and improve test assertions refactor: migrate to React 18's createRoot for rendering refactor: implement external store for WebFingers context and update related hooks refactor: remove console logs and simplify state update logic in WebFingersStore refactor: update dependencies to React 18 and related packages Add ShellHooksProvider and integrate shell hooks into FederableApp Add shell hooks integration and update useAlerts function to accept optional filters Pass shellHooks and shellAlerts as props to FederatedComponent in ProtectedFederatedRoute Add @types/react-router-dom to package.json Refactor to useShellHooks for improved context integration across components Refactor context creation to eliminate reliance on window.shellContexts Update module-federation dependency and enhance shell hooks integration in FederatedApp Update @scality/module-federation dependency to latest version --- shell-ui/package-lock.json | 367 +++++-------- shell-ui/package.json | 25 +- shell-ui/src/FederatedApp.tsx | 148 +----- shell-ui/src/NotificationCenterProvider.tsx | 20 +- shell-ui/src/alerts/alertContext.ts | 14 +- shell-ui/src/alerts/alertHooks.ts | 2 +- shell-ui/src/auth/useFirstTimeLogin.spec.tsx | 12 +- shell-ui/src/hooks/useShellHooks.ts | 102 ++++ shell-ui/src/index.tsx | 18 +- .../initFederation/ConfigurationProviders.tsx | 109 +++- .../initFederation/ShellConfigProvider.tsx | 36 +- .../initFederation/ShellHistoryProvider.tsx | 16 +- .../ShellThemeSelectorProvider.tsx | 22 +- .../src/initFederation/UIListProvider.tsx | 40 +- .../navbar/__TESTS__/testMultipleHooks.tsx | 2 +- shell-ui/src/navbar/index.spec.tsx | 73 ++- shell-ui/src/navbar/lang.tsx | 22 +- shell-ui/src/navbar/navbarContext.ts | 14 +- ui/package-lock.json | 482 ++++++++++-------- ui/package.json | 21 +- ui/src/FederableApp.tsx | 29 +- ui/src/ShellHooksContext.tsx | 99 ++++ ui/src/components/DashboardInventory.tsx | 5 +- ui/src/containers/AlertProvider.tsx | 21 +- ui/src/containers/ConfigProvider.tsx | 8 +- ui/src/containers/IntlProvider.tsx | 4 +- ui/src/containers/NodePage.tsx | 1 - ui/src/containers/PrivateRoute.tsx | 10 +- ui/src/hooks.tsx | 1 - 29 files changed, 878 insertions(+), 845 deletions(-) create mode 100644 shell-ui/src/hooks/useShellHooks.ts create mode 100644 ui/src/ShellHooksContext.tsx diff --git a/shell-ui/package-lock.json b/shell-ui/package-lock.json index 7c7a717d7d..a1821d87ef 100644 --- a/shell-ui/package-lock.json +++ b/shell-ui/package-lock.json @@ -8,20 +8,20 @@ "name": "shell-ui", "version": "1.0.0", "dependencies": { - "@scality/core-ui": "0.151.0", - "@scality/module-federation": "^1.3.4", + "@scality/core-ui": "git+https://github.com/scality/core-ui#bf0c36da657737f47dabe310bb1a20c136877970", + "@scality/module-federation": "git+https://github.com/scality/module-federation#c571388783a2a51ae3bf5d36ae66753c8b014bb5", "downshift": "^8.0.0", "jest-environment-jsdom": "^29.7.0", "oidc-client-ts": "^3.0.1", "oidc-react": "^3.2.2", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-error-boundary": "^4.0.2", "react-intl": "^5.15.3", "react-query": "^3.34.0", "react-router": "5.2.0", "react-router-dom": "5.2.0", - "styled-components": "^5.2.1", + "styled-components": "^5.3.11", "typescript": "^5.6.3" }, "devDependencies": { @@ -35,14 +35,15 @@ "@rspack/core": "^0.7.5", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^5.11.9", - "@testing-library/react": "^11.2.5", - "@testing-library/react-hooks": "^5.1.1", + "@testing-library/react": "^15.0.7", + "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^13.0.10", - "@types/react": "^17.0.39", - "@types/react-dom": "^17.0.13", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@types/react-router": "^5.1.20", - "@types/react-router-dom": "^5.2.0", - "@types/styled-components": "^5.1.26", + "@types/react-router-dom": "^5.3.3", + "@types/react-test-renderer": "^18.3.0", + "@types/styled-components": "^5.1.34", "babel-jest": "^26.6.3", "babel-loader": "^8.2.2", "fs-extra": "^10.0.0", @@ -52,7 +53,7 @@ "jest-preview": "^0.3.1", "msw": "0.36.8", "node-fetch": "^2.6.1", - "react-test-renderer": "^17.0.2", + "react-test-renderer": "^18.3.1", "ts-node": "^10.9.2" } }, @@ -1864,19 +1865,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz", - "integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==", - "dev": true, - "dependencies": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", @@ -2043,8 +2031,7 @@ }, "node_modules/@emotion/is-prop-valid": { "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "license": "MIT", "optional": true, "dependencies": { "@emotion/memoize": "0.7.4" @@ -2052,8 +2039,7 @@ }, "node_modules/@emotion/memoize": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "license": "MIT", "optional": true }, "node_modules/@emotion/react": { @@ -4175,8 +4161,9 @@ }, "node_modules/@scality/core-ui": { "version": "0.151.0", - "resolved": "https://registry.npmjs.org/@scality/core-ui/-/core-ui-0.151.0.tgz", - "integrity": "sha512-OeAhs+uiOOBDSGqzZGpIka1iCtRrGJkjNhzdRJhJtLwxKDFU7iyPUPA3MbJ8DoGJQN0do8k3PTyei1fZEiMXJA==", + "resolved": "git+ssh://git@github.com/scality/core-ui.git#bf0c36da657737f47dabe310bb1a20c136877970", + "integrity": "sha512-dC/zNxvxU7DVgxhbyKHgwwVyM2CwWACrwyVbh1VP0/7KTcgTmoYR2hO9qAMi9t8yyNWidOi9AVVzKupes13wRw==", + "license": "SEE LICENSE IN LICENSE", "dependencies": { "@floating-ui/dom": "^1.6.3", "@fortawesome/fontawesome-free": "^5.10.2", @@ -4190,9 +4177,9 @@ "framer-motion": "^4.1.17", "polished": "3.4.1", "pretty-bytes": "^5.6.0", - "react": "^17.0.2", + "react": "^18.3.1", "react-debounce-input": "3.2.2", - "react-dom": "^17.0.2", + "react-dom": "^18.3.1", "react-dropzone": "^14.2.3", "react-hook-form": "^7.49.2", "react-query": "^3.34.0", @@ -4200,6 +4187,7 @@ "react-router-dom": "5.2.0", "react-select": "4.3.1", "react-table": "^7.7.0", + "react-test-renderer": "^18.3.1", "react-virtualized": "9.22.3", "react-virtualized-auto-sizer": "^1.0.24", "react-window": "^1.8.6", @@ -4238,11 +4226,12 @@ }, "node_modules/@scality/module-federation": { "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@scality/module-federation/-/module-federation-1.3.4.tgz", - "integrity": "sha512-Okmgh+s9UTM6ropLt5QIJhswaN3m0hGNjGI2w/al+a4H+fQs5x/rAYngzWhFnHxdox0RUSRwA7aOZH1fBAvnmA==", + "resolved": "git+ssh://git@github.com/scality/module-federation.git#c571388783a2a51ae3bf5d36ae66753c8b014bb5", + "integrity": "sha512-lrpXm7Skkq/CtGQRI563pSelewbeNaBBbs3J4zzCiheb0H2fSs6JF6lqQHQjL9A0HRVjfnArotXlF8E8JzVtnw==", + "license": "SEE LICENSE IN LICENSE", "peerDependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.3.1", + "react-dom": "^18.3.1" } }, "node_modules/@sinclair/typebox": { @@ -4290,9 +4279,9 @@ "dev": true }, "node_modules/@storybook/preview-api": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.4.5.tgz", - "integrity": "sha512-MKIZ2jQO/3cUdsT57eq8jRgB6inALo9BxrQ88f7mqzltOkMvADvTAY6y8JZqTUoDzWTH/ny/8SGGdtpqlxRuiQ==", + "version": "8.4.4", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.4.4.tgz", + "integrity": "sha512-iZrWQcjRBqBHFdDXVxGpw6mHBZMCMYqhWXdyJ0d1S2y3PwcfOjkcXlQ1UiAenFHlA6dKrcYw8luKUQTL9bKReA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" @@ -4698,41 +4687,51 @@ } }, "node_modules/@testing-library/react": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", - "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", + "version": "15.0.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.7.tgz", + "integrity": "sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^7.28.1" + "@testing-library/dom": "^10.0.0", + "@types/react-dom": "^18.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "@types/react": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@testing-library/react-hooks": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-5.1.3.tgz", - "integrity": "sha512-UdEUtlQapQ579NEcXDAUE275u+KUsPtxW7NmFrNt0bE6lW8lqNCyxDK0RSuECmNZ/S0/fgP00W9RWRhVKO/hRg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz", + "integrity": "sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", - "@types/react": ">=16.9.0", - "@types/react-dom": ">=16.9.0", - "@types/react-test-renderer": ">=16.9.0", - "filter-console": "^0.1.1", "react-error-boundary": "^3.1.0" }, + "engines": { + "node": ">=12" + }, "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0", - "react-test-renderer": ">=16.9.0" + "@types/react": "^16.9.0 || ^17.0.0", + "react": "^16.9.0 || ^17.0.0", + "react-dom": "^16.9.0 || ^17.0.0", + "react-test-renderer": "^16.9.0 || ^17.0.0" }, "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, "react-dom": { "optional": true }, @@ -4757,81 +4756,6 @@ "react": ">=16.13.1" } }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@testing-library/react/node_modules/@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", - "dev": true - }, - "node_modules/@testing-library/react/node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/@testing-library/react/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@testing-library/react/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@testing-library/react/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, "node_modules/@testing-library/user-event": { "version": "13.5.0", "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", @@ -4900,37 +4824,34 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "version": "7.6.2", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "version": "7.4.0", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "version": "7.11.0", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } }, "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "dev": true, "dependencies": { "@types/connect": "*", @@ -5011,9 +4932,9 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -5023,9 +4944,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", - "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", "dev": true, "dependencies": { "@types/node": "*", @@ -5188,12 +5109,6 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, "node_modules/@types/node": { "version": "22.9.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz", @@ -5222,34 +5137,33 @@ "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, "node_modules/@types/qs": { - "version": "6.9.17", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", - "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, "node_modules/@types/react": { - "version": "17.0.83", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.83.tgz", - "integrity": "sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw==", + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "^0.16", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "17.0.25", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", - "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", "dev": true, "dependencies": { - "@types/react": "^17" + "@types/react": "*" } }, "node_modules/@types/react-router": { @@ -5288,11 +5202,6 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" - }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -5303,6 +5212,12 @@ "@types/node": "*" } }, + "node_modules/@types/send/node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, "node_modules/@types/serve-index": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", @@ -5313,9 +5228,9 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", "dev": true, "dependencies": { "@types/http-errors": "*", @@ -7174,17 +7089,6 @@ "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-pure": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.39.0.tgz", - "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -8789,15 +8693,6 @@ "node": ">=8" } }, - "node_modules/filter-console": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/filter-console/-/filter-console-0.1.1.tgz", - "integrity": "sha512-zrXoV1Uaz52DqPs+qEwNJWJFAWZpYJ47UNmpN9q4j+/EYsz85uV0DC9k8tRND5kYmoVzL0W+Y75q4Rg8sRJCdg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -9361,9 +9256,8 @@ }, "node_modules/harmony-reflect": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", - "dev": true + "dev": true, + "license": "(Apache-2.0 OR MPL-1.1)" }, "node_modules/has-flag": { "version": "4.0.0", @@ -12898,9 +12792,8 @@ }, "node_modules/jsonfile": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -14670,12 +14563,11 @@ } }, "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" @@ -14694,16 +14586,15 @@ } }, "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "17.0.2" + "react": "^18.3.1" } }, "node_modules/react-dropzone": { @@ -14897,7 +14788,6 @@ "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", - "dev": true, "dependencies": { "object-assign": "^4.1.1", "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" @@ -14919,26 +14809,18 @@ } }, "node_modules/react-test-renderer": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", - "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", - "dev": true, + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.3.1.tgz", + "integrity": "sha512-KkAgygexHUkQqtvvx/otwxtuFu5cVjfzTCtjXLH9boS19/Nbtg84zS7wIQn39G8IlrhThBpQsMKkq5ZHZIYFXA==", "dependencies": { - "object-assign": "^4.1.1", - "react-is": "^17.0.2", - "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.2" + "react-is": "^18.3.1", + "react-shallow-renderer": "^16.15.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "17.0.2" + "react": "^18.3.1" } }, - "node_modules/react-test-renderer/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -15729,12 +15611,11 @@ } }, "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "node_modules/schema-utils": { @@ -16036,9 +15917,9 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, "dependencies": { "call-bind": "^1.0.7", @@ -17247,10 +17128,9 @@ } }, "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "version": "2.0.0", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -17465,9 +17345,8 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", diff --git a/shell-ui/package.json b/shell-ui/package.json index d871b5156a..fef007e7f3 100644 --- a/shell-ui/package.json +++ b/shell-ui/package.json @@ -22,14 +22,15 @@ "@rspack/core": "^0.7.5", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^5.11.9", - "@testing-library/react": "^11.2.5", - "@testing-library/react-hooks": "^5.1.1", + "@testing-library/react": "^15.0.7", + "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^13.0.10", - "@types/react": "^17.0.39", - "@types/react-dom": "^17.0.13", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@types/react-router": "^5.1.20", - "@types/react-router-dom": "^5.2.0", - "@types/styled-components": "^5.1.26", + "@types/react-router-dom": "^5.3.3", + "@types/react-test-renderer": "^18.3.0", + "@types/styled-components": "^5.1.34", "babel-jest": "^26.6.3", "babel-loader": "^8.2.2", "fs-extra": "^10.0.0", @@ -39,24 +40,24 @@ "jest-preview": "^0.3.1", "msw": "0.36.8", "node-fetch": "^2.6.1", - "react-test-renderer": "^17.0.2", + "react-test-renderer": "^18.3.1", "ts-node": "^10.9.2" }, "dependencies": { - "@scality/core-ui": "0.151.0", - "@scality/module-federation": "^1.3.4", + "@scality/core-ui": "git+https://github.com/scality/core-ui#bf0c36da657737f47dabe310bb1a20c136877970", + "@scality/module-federation": "git+https://github.com/scality/module-federation#c571388783a2a51ae3bf5d36ae66753c8b014bb5", "downshift": "^8.0.0", "jest-environment-jsdom": "^29.7.0", "oidc-client-ts": "^3.0.1", "oidc-react": "^3.2.2", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-error-boundary": "^4.0.2", "react-intl": "^5.15.3", "react-query": "^3.34.0", "react-router": "5.2.0", "react-router-dom": "5.2.0", - "styled-components": "^5.2.1", + "styled-components": "^5.3.11", "typescript": "^5.6.3" } } diff --git a/shell-ui/src/FederatedApp.tsx b/shell-ui/src/FederatedApp.tsx index cae930c6ab..60c7619353 100644 --- a/shell-ui/src/FederatedApp.tsx +++ b/shell-ui/src/FederatedApp.tsx @@ -1,5 +1,6 @@ import { CoreUiThemeProvider } from '@scality/core-ui/dist/components/coreuithemeprovider/CoreUiThemeProvider'; import { ErrorPage500 } from '@scality/core-ui/dist/components/error-pages/ErrorPage500.component'; +import { Loader } from '@scality/core-ui/dist/components/loader/Loader.component'; import { ScrollbarWrapper } from '@scality/core-ui/dist/components/scrollbarwrapper/ScrollbarWrapper.component'; import { ToastProvider } from '@scality/core-ui/dist/components/toast/ToastProvider'; import { @@ -12,61 +13,35 @@ import React, { useEffect, useMemo } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { QueryClient, QueryClientProvider } from 'react-query'; import { Route, Router, Switch } from 'react-router-dom'; -import { Loader } from '@scality/core-ui/dist/components/loader/Loader.component'; -import NotificationCenterProvider, { - NotificationCenterContextType, -} from './NotificationCenterProvider'; +import { loadShare } from '@module-federation/enhanced/runtime'; +import { useQuery } from 'react-query'; +import NotificationCenterProvider from './NotificationCenterProvider'; import { AuthConfigProvider, useAuthConfig } from './auth/AuthConfigProvider'; import { AuthProvider, useAuth } from './auth/AuthProvider'; import { FirstTimeLoginProvider } from './auth/FirstTimeLoginProvider'; +import { + ShellAlerts, + shellAlerts, + ShellHooks, + shellHooks, +} from './hooks/useShellHooks'; import './index.css'; import { ConfigurationProvider, FederatedView, useConfigRetriever, - useConfig, useDiscoveredViews, - useLinkOpener, - BuildtimeWebFinger, - RuntimeWebFinger, } from './initFederation/ConfigurationProviders'; import { ShellConfigProvider, useShellConfig, } from './initFederation/ShellConfigProvider'; import { ShellHistoryProvider } from './initFederation/ShellHistoryProvider'; -import { - ShellThemeSelectorProvider, - useShellThemeSelector, -} from './initFederation/ShellThemeSelectorProvider'; -import { - UIListProvider, - useDeployedApps, -} from './initFederation/UIListProvider'; +import { ShellThemeSelectorProvider } from './initFederation/ShellThemeSelectorProvider'; +import { UIListProvider } from './initFederation/UIListProvider'; import { SolutionsNavbar } from './navbar'; import { LanguageProvider, useLanguage } from './navbar/lang'; -import AlertProvider from './alerts/AlertProvider'; -import { - getAlertingAlertSelectors, - getAuthenticationAlertSelectors, - getBootstrapAlertSelectors, - getDashboardingAlertSelectors, - getIngressControllerAlertSelectors, - getK8SMasterAlertSelectors, - getLoggingAlertSelectors, - getMonitoringAlertSelectors, - getNetworksAlertSelectors, - getNodesAlertSelectors, - getPlatformAlertSelectors, - getServicesAlertSelectors, - getVolumesAlertSelectors, - useAlerts, - useHighestSeverityAlerts, -} from './alerts'; -import { useHistory } from 'react-router'; -import { useQuery, UseQueryResult } from 'react-query'; -import { loadShare } from '@module-federation/enhanced/runtime'; /** * This is a mock function to replace the real loadShare function when running tests. @@ -86,95 +61,9 @@ const loadShareModule = export const queryClient = new QueryClient(); -export type ShellTypes = { - shellHooks: { - useAuthConfig: typeof useAuthConfig; - useAuth: typeof useAuth; - useConfigRetriever: typeof useConfigRetriever; - useDiscoveredViews: typeof useDiscoveredViews; - useShellConfig: typeof useShellConfig; - useLanguage: typeof useLanguage; - useConfig: typeof useConfig; - useLinkOpener: typeof useLinkOpener; - useDeployedApps: typeof useDeployedApps; - useShellThemeSelector: typeof useShellThemeSelector; - }; - shellAlerts: { - AlertsProvider: typeof AlertProvider; - hooks: { - useAlerts: typeof useAlerts; - useHighestSeverityAlerts: typeof useHighestSeverityAlerts; - }; - alertSelectors: { - getPlatformAlertSelectors: typeof getPlatformAlertSelectors; - getNodesAlertSelectors: typeof getNodesAlertSelectors; - getVolumesAlertSelectors: typeof getVolumesAlertSelectors; - getNetworksAlertSelectors: typeof getNetworksAlertSelectors; - getServicesAlertSelectors: typeof getServicesAlertSelectors; - getK8SMasterAlertSelectors: typeof getK8SMasterAlertSelectors; - getBootstrapAlertSelectors: typeof getBootstrapAlertSelectors; - getMonitoringAlertSelectors: typeof getMonitoringAlertSelectors; - getAlertingAlertSelectors: typeof getAlertingAlertSelectors; - getLoggingAlertSelectors: typeof getLoggingAlertSelectors; - getDashboardingAlertSelectors: typeof getDashboardingAlertSelectors; - getIngressControllerAlertSelectors: typeof getIngressControllerAlertSelectors; - getAuthenticationAlertSelectors: typeof getAuthenticationAlertSelectors; - }; - }; -}; - -declare global { - interface Window { - shellContexts: { - ShellHistoryContext: React.Context | null>; - NotificationContext: React.Context; - WebFingersContext: React.Context< - | null - | UseQueryResult< - BuildtimeWebFinger | RuntimeWebFinger>, - unknown - >[] - >; - }; - shellHooks: ShellTypes['shellHooks']; - shellAlerts: ShellTypes['shellAlerts']; - } -} - -window.shellHooks = { - useAuthConfig, - useAuth, - useConfigRetriever, - useDiscoveredViews, - useShellConfig, - useLanguage, - useConfig, - useLinkOpener: useLinkOpener, - useDeployedApps: useDeployedApps, - useShellThemeSelector: useShellThemeSelector, -}; - -window.shellAlerts = { - AlertsProvider: AlertProvider, - hooks: { - useAlerts: useAlerts, - useHighestSeverityAlerts: useHighestSeverityAlerts, - }, - alertSelectors: { - getPlatformAlertSelectors: getPlatformAlertSelectors, - getNodesAlertSelectors: getNodesAlertSelectors, - getVolumesAlertSelectors: getVolumesAlertSelectors, - getNetworksAlertSelectors: getNetworksAlertSelectors, - getServicesAlertSelectors: getServicesAlertSelectors, - getK8SMasterAlertSelectors: getK8SMasterAlertSelectors, - getBootstrapAlertSelectors: getBootstrapAlertSelectors, - getMonitoringAlertSelectors: getMonitoringAlertSelectors, - getAlertingAlertSelectors: getAlertingAlertSelectors, - getLoggingAlertSelectors: getLoggingAlertSelectors, - getDashboardingAlertSelectors: getDashboardingAlertSelectors, - getIngressControllerAlertSelectors: getIngressControllerAlertSelectors, - getAuthenticationAlertSelectors: getAuthenticationAlertSelectors, - }, +export type FederatedAppProps = { + shellHooks: ShellHooks; + shellAlerts: ShellAlerts; }; function FederatedRoute({ @@ -230,6 +119,11 @@ function ProtectedFederatedRoute({ const { userData } = useAuth(); const { retrieveConfiguration } = useConfigRetriever(); + const federatedAppProps: FederatedAppProps = { + shellHooks, + shellAlerts, + }; + if ( userData && (groups?.some((group) => userData.groups.includes(group)) ?? true) @@ -242,7 +136,7 @@ function ProtectedFederatedRoute({ diff --git a/shell-ui/src/NotificationCenterProvider.tsx b/shell-ui/src/NotificationCenterProvider.tsx index d1cd131136..63ed86ad38 100644 --- a/shell-ui/src/NotificationCenterProvider.tsx +++ b/shell-ui/src/NotificationCenterProvider.tsx @@ -1,4 +1,4 @@ -import React, { Dispatch, createContext, useReducer } from 'react'; +import { Dispatch, FC, ReactNode, createContext, useReducer } from 'react'; export type Notification = { id: string; @@ -18,16 +18,12 @@ export type NotificationCenterContextType = { dispatch: Dispatch; }; -if (!window.shellContexts) { - //@ts-ignore - window.shellContexts = {}; -} -if (!window.shellContexts.NotificationContext) { - window.shellContexts.NotificationContext = - createContext(null); -} export const NotificationCenterContext = - window.shellContexts.NotificationContext; + createContext(null); + +type NotificationCenterProviderProps = { + children: ReactNode; +}; export enum NotificationActionType { PUBLISH, @@ -50,7 +46,9 @@ export type NotificationCenterActions = const LOCAL_STORAGE_NOTIFICATION_PREFIX = 'notification-center__'; -const NotificationCenterProvider = ({ children }) => { +const NotificationCenterProvider: FC = ({ + children, +}) => { const notificationReducer = ( state: InternalNotification[], action: NotificationCenterActions, diff --git a/shell-ui/src/alerts/alertContext.ts b/shell-ui/src/alerts/alertContext.ts index fe8b222bf4..a1647e6fc4 100644 --- a/shell-ui/src/alerts/alertContext.ts +++ b/shell-ui/src/alerts/alertContext.ts @@ -1,15 +1,3 @@ import { createContext } from 'react'; -if (!window.shellContexts) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts = {}; -} - -// @ts-expect-error - FIXME when you are working on it -if (!window.shellContexts.AlertContext) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts.AlertContext = createContext(null); -} - -// @ts-expect-error - FIXME when you are working on it -export const AlertContext = window.shellContexts.AlertContext; +export const AlertContext = createContext(null); diff --git a/shell-ui/src/alerts/alertHooks.ts b/shell-ui/src/alerts/alertHooks.ts index 8393d6dd4d..6107f67d8a 100644 --- a/shell-ui/src/alerts/alertHooks.ts +++ b/shell-ui/src/alerts/alertHooks.ts @@ -90,7 +90,7 @@ export const useHighestSeverityAlerts = (filters: FilterLabels): Alert[] => { * * @returns react query result */ -export function useAlerts(filters: FilterLabels) { +export function useAlerts(filters?: FilterLabels) { const query = useContext(AlertContext); if (!query) { diff --git a/shell-ui/src/auth/useFirstTimeLogin.spec.tsx b/shell-ui/src/auth/useFirstTimeLogin.spec.tsx index f918b33d18..9eb73076ff 100644 --- a/shell-ui/src/auth/useFirstTimeLogin.spec.tsx +++ b/shell-ui/src/auth/useFirstTimeLogin.spec.tsx @@ -3,6 +3,7 @@ import { useFirstTimeLogin } from './FirstTimeLoginProvider'; import { wrapper } from '../navbar/index.spec'; import { configurationHandlers } from '../FederatedApp.spec'; import { setupServer } from 'msw/node'; +import { waitFor } from '@testing-library/react'; const server = setupServer(...configurationHandlers); @@ -28,14 +29,11 @@ describe('useFirstTimeLogin hook', () => { it('should return firstTimeLogin as true if the user is logging in for the first time', async () => { //S - const { result, waitForNextUpdate } = renderHook( - () => useFirstTimeLogin(), - { wrapper }, - ); - //E - await waitForNextUpdate(); + const { result } = renderHook(() => useFirstTimeLogin(), { wrapper }); //V - expect(result.current.firstTimeLogin).toEqual(true); + await waitFor(() => { + expect(result.current.firstTimeLogin).toEqual(true); + }); }); it('should return firstTimeLogin as false if the user is NOT logging in for the first time', async () => { diff --git a/shell-ui/src/hooks/useShellHooks.ts b/shell-ui/src/hooks/useShellHooks.ts new file mode 100644 index 0000000000..fc2643f590 --- /dev/null +++ b/shell-ui/src/hooks/useShellHooks.ts @@ -0,0 +1,102 @@ +import { + useAlerts, + getPlatformAlertSelectors, + getNodesAlertSelectors, + getVolumesAlertSelectors, + getNetworksAlertSelectors, + getServicesAlertSelectors, + getK8SMasterAlertSelectors, + getBootstrapAlertSelectors, + getMonitoringAlertSelectors, + getAlertingAlertSelectors, + getLoggingAlertSelectors, + getDashboardingAlertSelectors, + getIngressControllerAlertSelectors, + getAuthenticationAlertSelectors, + useHighestSeverityAlerts, +} from '../alerts'; +import AlertProvider from '../alerts/AlertProvider'; +import { useAuthConfig } from '../auth/AuthConfigProvider'; +import { useAuth } from '../auth/AuthProvider'; +import { + useConfig, + useConfigRetriever, + useDiscoveredViews, + useLinkOpener, +} from '../initFederation/ConfigurationProviders'; +import { useShellConfig } from '../initFederation/ShellConfigProvider'; +import { useShellThemeSelector } from '../initFederation/ShellThemeSelectorProvider'; +import { useDeployedApps } from '../initFederation/UIListProvider'; +import { useLanguage } from '../navbar/lang'; + +export type ShellHooks = { + useAuthConfig: typeof useAuthConfig; + useAuth: typeof useAuth; + useConfigRetriever: typeof useConfigRetriever; + useDiscoveredViews: typeof useDiscoveredViews; + useShellConfig: typeof useShellConfig; + useLanguage: typeof useLanguage; + useConfig: typeof useConfig; + useLinkOpener: typeof useLinkOpener; + useDeployedApps: typeof useDeployedApps; + useShellThemeSelector: typeof useShellThemeSelector; +}; + +export type ShellAlerts = { + AlertsProvider: typeof AlertProvider; + alertHooks: { + useAlerts: typeof useAlerts; + useHighestSeverityAlerts: typeof useHighestSeverityAlerts; + }; + alertSelectors: { + getPlatformAlertSelectors: typeof getPlatformAlertSelectors; + getNodesAlertSelectors: typeof getNodesAlertSelectors; + getVolumesAlertSelectors: typeof getVolumesAlertSelectors; + getNetworksAlertSelectors: typeof getNetworksAlertSelectors; + getServicesAlertSelectors: typeof getServicesAlertSelectors; + getK8SMasterAlertSelectors: typeof getK8SMasterAlertSelectors; + getBootstrapAlertSelectors: typeof getBootstrapAlertSelectors; + getMonitoringAlertSelectors: typeof getMonitoringAlertSelectors; + getAlertingAlertSelectors: typeof getAlertingAlertSelectors; + getLoggingAlertSelectors: typeof getLoggingAlertSelectors; + getDashboardingAlertSelectors: typeof getDashboardingAlertSelectors; + getIngressControllerAlertSelectors: typeof getIngressControllerAlertSelectors; + getAuthenticationAlertSelectors: typeof getAuthenticationAlertSelectors; + }; +}; + +export const shellHooks: ShellHooks = { + useAuthConfig, + useAuth, + useConfigRetriever, + useDiscoveredViews, + useShellConfig, + useLanguage, + useConfig, + useLinkOpener, + useDeployedApps, + useShellThemeSelector, +}; + +export const shellAlerts: ShellAlerts = { + AlertsProvider: AlertProvider, + alertHooks: { + useAlerts, + useHighestSeverityAlerts, + }, + alertSelectors: { + getPlatformAlertSelectors, + getNodesAlertSelectors, + getVolumesAlertSelectors, + getNetworksAlertSelectors, + getServicesAlertSelectors, + getK8SMasterAlertSelectors, + getBootstrapAlertSelectors, + getMonitoringAlertSelectors, + getAlertingAlertSelectors, + getLoggingAlertSelectors, + getDashboardingAlertSelectors, + getIngressControllerAlertSelectors, + getAuthenticationAlertSelectors, + }, +}; diff --git a/shell-ui/src/index.tsx b/shell-ui/src/index.tsx index fc4c4670b4..82892eb7bd 100644 --- a/shell-ui/src/index.tsx +++ b/shell-ui/src/index.tsx @@ -1,11 +1,9 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App, { ShellTypes } from './FederatedApp'; -import { NotificationCenterContextType } from './NotificationCenterProvider'; -import { History } from 'history'; -import { - BuildtimeWebFinger, - RuntimeWebFinger, -} from './initFederation/ConfigurationProviders'; +import { createRoot } from 'react-dom/client'; +import App from './FederatedApp'; -ReactDOM.render(, document.getElementById('app')); +const rootElement = document.getElementById('app'); + +if (rootElement) { + const root = createRoot(rootElement); + root.render(); +} diff --git a/shell-ui/src/initFederation/ConfigurationProviders.tsx b/shell-ui/src/initFederation/ConfigurationProviders.tsx index 33d1093b0f..ea8f0c0f87 100644 --- a/shell-ui/src/initFederation/ConfigurationProviders.tsx +++ b/shell-ui/src/initFederation/ConfigurationProviders.tsx @@ -2,27 +2,12 @@ import { ErrorPage500 } from '@scality/core-ui/dist/components/error-pages/Error import { IconName } from '@scality/core-ui/dist/components/icon/Icon.component'; import { Loader } from '@scality/core-ui/dist/components/loader/Loader.component'; import { SolutionUI } from '@scality/module-federation'; -import React, { createContext, useContext } from 'react'; +import React, { useMemo, useSyncExternalStore } from 'react'; import { useQueries, UseQueryResult } from 'react-query'; import { useShellConfig } from './ShellConfigProvider'; import { useShellHistory } from './ShellHistoryProvider'; import { useDeployedApps, useDeployedAppsRetriever } from './UIListProvider'; -if (!window.shellContexts) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts = {}; -} - -if (!window.shellContexts.WebFingersContext) { - window.shellContexts.WebFingersContext = createContext< - | null - | UseQueryResult< - BuildtimeWebFinger | RuntimeWebFinger>, - unknown - >[] - >(null); -} - export type OAuth2ProxyConfig = { kind: 'OAuth2Proxy'; //todo : add other entries }; @@ -85,10 +70,8 @@ export function useConfigRetriever(): { name: string; }) => (T extends 'build' ? BuildtimeWebFinger : RuntimeWebFinger) | null; } { + const { state: webFingerContextValue } = useWebFingersStore(); const { retrieveDeployedApps } = useDeployedAppsRetriever(); - const webFingerContextValue = useContext( - window.shellContexts.WebFingersContext, - ); if (!webFingerContextValue) { throw new Error( @@ -142,15 +125,18 @@ export function useConfig>({ configType: T extends 'build' ? 'build' : 'run'; name: string; }): null | T extends 'build' ? BuildtimeWebFinger : RuntimeWebFinger { + // Utiliser le nouveau hook useWebFingersStore + const { state: webFingerContextValue } = useWebFingersStore(); + + // Utiliser le retrieveConfiguration du hook useConfigRetriever const { retrieveConfiguration } = useConfigRetriever(); - const webFingerContextValue = useContext( - window.shellContexts.WebFingersContext, - ); - if (!webFingerContextValue) { + // Vérifier que le contexte est disponible + if (!webFingerContextValue || webFingerContextValue.length === 0) { throw new Error("Can't use useConfig outside of ConfigurationProvider"); } + // Récupérer et retourner la configuration return retrieveConfiguration({ configType, name, @@ -179,6 +165,72 @@ export type NonFederatedView = { icon?: IconName; }; export type ViewDefinition = FederatedView | NonFederatedView; + +// External store implementation +class WebFingersStore { + private listeners: Set<() => void> = new Set(); + private _state: UseQueryResult< + BuildtimeWebFinger | RuntimeWebFinger>, + unknown + >[] = []; + + subscribe = (listener: () => void) => { + this.listeners.add(listener); + return () => { + this.listeners.delete(listener); + }; + }; + + getState = () => { + return this._state; + }; + + private isStateEqual( + currentState: UseQueryResult< + BuildtimeWebFinger | RuntimeWebFinger>, + unknown + >[], + newState: UseQueryResult< + BuildtimeWebFinger | RuntimeWebFinger>, + unknown + >[], + ) { + return ( + currentState.length === newState.length && + currentState.every( + (item, index) => + JSON.stringify(item) === JSON.stringify(newState[index]), + ) + ); + } + + updateState = ( + newState: UseQueryResult< + BuildtimeWebFinger | RuntimeWebFinger>, + unknown + >[], + ) => { + if (!this.isStateEqual(this._state, newState)) { + this._state = newState; + this.listeners.forEach((listener) => listener()); + } + }; +} + +const webFingersStore = new WebFingersStore(); + +export function useWebFingersStore() { + const state = useSyncExternalStore( + webFingersStore.subscribe, + webFingersStore.getState, + ); + + return { + state, + updateWebFingersState: webFingersStore.updateState, + }; +} + export function useDiscoveredViews(): ViewDefinition[] { const { retrieveConfiguration } = useConfigRetriever(); const { retrieveDeployedApps } = useDeployedAppsRetriever(); @@ -286,6 +338,7 @@ export const ConfigurationProvider = ({ }: { children: React.ReactNode; }) => { + const { updateWebFingersState } = useWebFingersStore(); const deployedUIs = useDeployedApps(); const results = useQueries( deployedUIs.flatMap((ui) => [ @@ -323,6 +376,11 @@ export const ConfigurationProvider = ({ }, ]), ); + + useMemo(() => { + updateWebFingersState(results); + }, [results]); + const statuses = Array.from(new Set(results.map((result) => result.status))); const globalStatus = statuses.includes('error') ? 'error' @@ -333,13 +391,14 @@ export const ConfigurationProvider = ({ : statuses.includes('idle') && statuses.includes('success') ? 'loading' : 'success'; + return ( - + <> {(globalStatus === 'loading' || globalStatus === 'idle') && ( )} {globalStatus === 'error' && } {globalStatus === 'success' && children} - + ); }; diff --git a/shell-ui/src/initFederation/ShellConfigProvider.tsx b/shell-ui/src/initFederation/ShellConfigProvider.tsx index 486dcb9667..7d4b80546e 100644 --- a/shell-ui/src/initFederation/ShellConfigProvider.tsx +++ b/shell-ui/src/initFederation/ShellConfigProvider.tsx @@ -7,15 +7,7 @@ import { import React, { createContext, useContext } from 'react'; import { useQuery } from 'react-query'; -if (!window.shellContexts) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts = {}; -} -// @ts-expect-error - FIXME when you are working on it -if (!window.shellContexts.ShellConfigContext) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts.ShellConfigContext = createContext(null); -} +const ShellConfigContext = createContext(null); export type NavbarEntry = { groups?: string[]; @@ -78,10 +70,7 @@ export type ShellConfig = { }; export const useShellConfig = () => { - const contextValue = useContext( - // @ts-expect-error - FIXME when you are working on it - window.shellContexts.ShellConfigContext, - ); + const contextValue = useContext(ShellConfigContext); if (!contextValue) { throw new Error("useShellConfig can't be used outside ShellConfigProvider"); @@ -99,14 +88,13 @@ export const useShellConfig = () => { export const ShellConfigProvider = ({ shellConfigUrl, children }) => { const { data: config, status } = useQuery( 'getShellJSONConfigFile', - () => { - return fetch(shellConfigUrl).then((r) => { - if (r.ok) { - return r.json(); - } else { - return Promise.reject(); - } - }); + async () => { + const r = await fetch(shellConfigUrl); + if (r.ok) { + return r.json(); + } else { + return Promise.reject(); + } }, { refetchOnWindowFocus: false, @@ -114,8 +102,7 @@ export const ShellConfigProvider = ({ shellConfigUrl, children }) => { ); return ( - // @ts-expect-error - FIXME when you are working on it - { )} {status === 'error' && } {status === 'success' && children} - {/* @ts-expect-error - FIXME when you are working on it */} - + ); }; diff --git a/shell-ui/src/initFederation/ShellHistoryProvider.tsx b/shell-ui/src/initFederation/ShellHistoryProvider.tsx index 65ab8f9d9f..bbfb6f9e6a 100644 --- a/shell-ui/src/initFederation/ShellHistoryProvider.tsx +++ b/shell-ui/src/initFederation/ShellHistoryProvider.tsx @@ -4,19 +4,9 @@ import { useHistory } from 'react-router'; const ShellHistoryContext = createContext > | null>(null); -if (!window.shellContexts) { - window.shellContexts = { - ShellHistoryContext, - ...window.shellContexts, - }; -} - -if (!window.shellContexts.ShellHistoryContext) { - window.shellContexts.ShellHistoryContext = ShellHistoryContext; -} export const useShellHistory = () => { - const contextValue = useContext(window.shellContexts.ShellHistoryContext); + const contextValue = useContext(ShellHistoryContext); if (!contextValue) { throw new Error( @@ -29,8 +19,8 @@ export const useShellHistory = () => { export const ShellHistoryProvider = ({ children }) => { const history = useHistory(); return ( - + {children} - + ); }; diff --git a/shell-ui/src/initFederation/ShellThemeSelectorProvider.tsx b/shell-ui/src/initFederation/ShellThemeSelectorProvider.tsx index b69b9be5e9..e1e095677c 100644 --- a/shell-ui/src/initFederation/ShellThemeSelectorProvider.tsx +++ b/shell-ui/src/initFederation/ShellThemeSelectorProvider.tsx @@ -13,22 +13,10 @@ type ThemeContextValues = { assets: { logoPath: string }; }; -if (!window.shellContexts) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts = {}; -} -// @ts-expect-error - FIXME when you are working on it -if (!window.shellContexts.ShellThemeContext) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts.ShellThemeContext = - React.createContext(null); -} +const ShellThemeContext = React.createContext(null); export function useShellThemeSelector(): ThemeContextValues { - const themeContext: ThemeContextValues = useContext( - // @ts-expect-error - FIXME when you are working on it - window.shellContexts.ShellThemeContext, - ); + const themeContext: ThemeContextValues = useContext(ShellThemeContext); if (themeContext === null) { throw new Error( @@ -97,8 +85,7 @@ export function ShellThemeSelectorProvider({ }; return ( - // @ts-expect-error - FIXME when you are working on it - {children(selectedTheme, themeMode)} - {/* @ts-expect-error - FIXME when you are working on it */} - + ); } diff --git a/shell-ui/src/initFederation/UIListProvider.tsx b/shell-ui/src/initFederation/UIListProvider.tsx index 7b7839a885..28e1d45053 100644 --- a/shell-ui/src/initFederation/UIListProvider.tsx +++ b/shell-ui/src/initFederation/UIListProvider.tsx @@ -5,15 +5,7 @@ import { Loader } from '@scality/core-ui/dist/components/loader/Loader.component import { ErrorPage500 } from '@scality/core-ui/dist/components/error-pages/ErrorPage500.component'; import type { SolutionUI } from '@scality/module-federation'; -if (!window.shellContexts) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts = {}; -} -// @ts-expect-error - FIXME when you are working on it -if (!window.shellContexts.UIListContext) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts.UIListContext = createContext(null); -} +const UIListContext = createContext(null); export function useDeployedAppsRetriever(): { retrieveDeployedApps: (selectors?: { @@ -21,8 +13,7 @@ export function useDeployedAppsRetriever(): { name?: string; }) => SolutionUI[]; } { - // @ts-expect-error - FIXME when you are working on it - const uiListContext = useContext(window.shellContexts.UIListContext); + const uiListContext = useContext(UIListContext); if (!uiListContext) { throw new Error( @@ -32,9 +23,7 @@ export function useDeployedAppsRetriever(): { return { retrieveDeployedApps: (selectors) => { - // @ts-expect-error - FIXME when you are working on it if (selectors && uiListContext.uis) { - // @ts-expect-error - FIXME when you are working on it return uiListContext.uis.filter((ui) => { return ( ((selectors.kind && selectors.kind === ui.kind) || @@ -43,7 +32,6 @@ export function useDeployedAppsRetriever(): { ); }); } - // @ts-expect-error - FIXME when you are working on it return uiListContext.uis || []; }, }; @@ -52,8 +40,7 @@ export const useDeployedApps = (selectors?: { kind?: string; name?: string; }): SolutionUI[] => { - // @ts-expect-error - FIXME when you are working on it - const uiListContext = useContext(window.shellContexts.UIListContext); + const uiListContext = useContext(UIListContext); if (!uiListContext) { throw new Error("Can't use useDeployedApps outside of UIListProvider"); @@ -71,22 +58,20 @@ export const UIListProvider = ({ }) => { const { status, data } = useQuery( 'discoveredUIs', - () => { - return fetch(discoveryURL, { cache: 'no-cache' }).then((r) => { - if (r.ok) { - return r.json(); - } else { - return Promise.reject(); - } - }); + async () => { + const r = await fetch(discoveryURL, { cache: 'no-cache' }); + if (r.ok) { + return r.json(); + } else { + return Promise.reject(); + } }, { refetchOnWindowFocus: false, }, ); return ( - // @ts-expect-error - FIXME when you are working on it - } {status === 'success' && children} - {/* @ts-expect-error - FIXME when you are working on it */} - + ); }; diff --git a/shell-ui/src/navbar/__TESTS__/testMultipleHooks.tsx b/shell-ui/src/navbar/__TESTS__/testMultipleHooks.tsx index 2c68a5161d..b66220b6fb 100644 --- a/shell-ui/src/navbar/__TESTS__/testMultipleHooks.tsx +++ b/shell-ui/src/navbar/__TESTS__/testMultipleHooks.tsx @@ -24,7 +24,7 @@ export type RenderAdditionalHook = ( }; export function prepareRenderMultipleHooks(options: { - wrapper: FunctionComponent>>; + wrapper: FunctionComponent>>>; }): { renderAdditionalHook: RenderAdditionalHook; waitForWrapperToBeReady: () => Promise; diff --git a/shell-ui/src/navbar/index.spec.tsx b/shell-ui/src/navbar/index.spec.tsx index 812fead4ca..f25e4d74da 100644 --- a/shell-ui/src/navbar/index.spec.tsx +++ b/shell-ui/src/navbar/index.spec.tsx @@ -5,9 +5,8 @@ import React from 'react'; import { QueryClient, QueryClientProvider } from 'react-query'; import { MemoryRouter } from 'react-router'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor, act } from '@testing-library/react'; import { useAuth } from 'oidc-react'; -import { act } from 'react-test-renderer'; import { SolutionsNavbar } from '.'; import { WithInitFederationProviders } from '../FederatedApp'; import { configurationHandlers } from '../FederatedApp.spec'; @@ -128,77 +127,99 @@ describe('useNavbar', () => { }; it('should retrieve navbar configuration', async () => { //E - const { result, waitForNextUpdate } = renderHook(() => useNavbar(), { + const { result } = renderHook(() => useNavbar(), { wrapper, }); - await waitForNextUpdate(); - //V - expect(result.current.getLinks()).toStrictEqual(expectedDefaultNavbarLinks); + await waitFor(() => { + expect(result.current.getLinks()).toStrictEqual( + expectedDefaultNavbarLinks, + ); + }); }); it('should set main navbar links', async () => { //S - const { result, waitForNextUpdate } = renderHook(() => useNavbar(), { + const { result } = renderHook(() => useNavbar(), { wrapper, }); - await act(() => waitForNextUpdate()); + await waitFor(() => { + expect(result.current.setMainLinks).toBeDefined(); + }); + //E act(() => // @ts-expect-error - FIXME when you are working on it result.current.setMainLinks([expectedDefaultNavbarLinks.main[0]]), ); + //V - expect(result.current.getLinks()).toStrictEqual({ - ...expectedDefaultNavbarLinks, - main: [expectedDefaultNavbarLinks.main[0]], + await waitFor(() => { + expect(result.current.getLinks()).toStrictEqual({ + ...expectedDefaultNavbarLinks, + main: [expectedDefaultNavbarLinks.main[0]], + }); }); }); it('should set secondary navbar links', async () => { //S - const { result, waitForNextUpdate } = renderHook(() => useNavbar(), { + const { result } = renderHook(() => useNavbar(), { wrapper, }); - await waitForNextUpdate(); + + await waitFor(() => { + expect(result.current.setSecondaryLinks).toBeDefined(); + }); //E act(() => // @ts-expect-error - FIXME when you are working on it result.current.setSecondaryLinks([expectedDefaultNavbarLinks.main[0]]), ); //V - expect(result.current.getLinks()).toStrictEqual({ - ...expectedDefaultNavbarLinks, - secondary: [expectedDefaultNavbarLinks.main[0]], + await waitFor(() => { + expect(result.current.getLinks()).toStrictEqual({ + ...expectedDefaultNavbarLinks, + secondary: [expectedDefaultNavbarLinks.main[0]], + }); }); }); it('should set user dropdown links', async () => { //S - const { result, waitForNextUpdate } = renderHook(() => useNavbar(), { + const { result } = renderHook(() => useNavbar(), { wrapper, }); - await waitForNextUpdate(); //E + await waitFor(() => { + expect(result.current.setUserDropdownLinks).toBeDefined(); + }); act(() => // @ts-expect-error - FIXME when you are working on it result.current.setUserDropdownLinks([expectedDefaultNavbarLinks.main[0]]), ); //V - expect(result.current.getLinks()).toStrictEqual({ - ...expectedDefaultNavbarLinks, - userDropdown: [expectedDefaultNavbarLinks.main[0]], + await waitFor(() => { + expect(result.current.getLinks()).toStrictEqual({ + ...expectedDefaultNavbarLinks, + userDropdown: [expectedDefaultNavbarLinks.main[0]], + }); }); }); it('should set logo link', async () => { //S - const { result, waitForNextUpdate } = renderHook(() => useNavbar(), { + const { result } = renderHook(() => useNavbar(), { wrapper, }); - await waitForNextUpdate(); //E + await waitFor(() => { + expect(result.current.setLogoLink).toBeDefined(); + }); + act(() => result.current.setLogoLink('http://localhost:3000')); //V - expect(result.current.getLinks()).toStrictEqual({ - ...expectedDefaultNavbarLinks, - logoHref: 'http://localhost:3000', + await waitFor(() => { + expect(result.current.getLinks()).toStrictEqual({ + ...expectedDefaultNavbarLinks, + logoHref: 'http://localhost:3000', + }); }); }); it('should display the Notification Center for Platform Admin', async () => { diff --git a/shell-ui/src/navbar/lang.tsx b/shell-ui/src/navbar/lang.tsx index b51cea7f53..5da8ab569b 100644 --- a/shell-ui/src/navbar/lang.tsx +++ b/shell-ui/src/navbar/lang.tsx @@ -9,15 +9,7 @@ import translations_en from './translations/en.json'; import translations_fr from './translations/fr.json'; import { LANGUAGE_CHANGED_EVENT } from './events'; -if (!window.shellContexts) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts = {}; -} -// @ts-expect-error - FIXME when you are working on it -if (!window.shellContexts.LanguageContext) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts.LanguageContext = createContext(null); -} +const LanguageContext = createContext(null); type Language = 'en' | 'fr'; export const languages: Language[] = ['en', 'fr']; @@ -30,8 +22,7 @@ export function useLanguage(): { setLanguage: (language: Language) => void; unSelectedLanguages: Language[]; } { - // @ts-expect-error - FIXME when you are working on it - const languageContext = useContext(window.shellContexts.LanguageContext); + const languageContext = useContext(LanguageContext); if (languageContext === null) { throw new Error( @@ -40,12 +31,9 @@ export function useLanguage(): { } return { - // @ts-expect-error - FIXME when you are working on it language: languageContext.language, - // @ts-expect-error - FIXME when you are working on it setLanguage: languageContext.setLanguage, unSelectedLanguages: languages.filter( - // @ts-expect-error - FIXME when you are working on it (lang) => lang !== languageContext.language, ), }; @@ -81,8 +69,7 @@ export function LanguageProvider({ }; return ( - // @ts-expect-error - FIXME when you are working on it - {children} - {/* @ts-expect-error - FIXME when you are working on it */} - + ); } diff --git a/shell-ui/src/navbar/navbarContext.ts b/shell-ui/src/navbar/navbarContext.ts index 74865b34e9..018b9f1782 100644 --- a/shell-ui/src/navbar/navbarContext.ts +++ b/shell-ui/src/navbar/navbarContext.ts @@ -2,16 +2,4 @@ import { createContext } from 'react'; import type { Navbar } from './navbarHooks'; import './navbarHooks'; -if (!window.shellContexts) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts = {}; -} - -// @ts-expect-error - FIXME when you are working on it -if (!window.shellContexts.NavbarContext) { - // @ts-expect-error - FIXME when you are working on it - window.shellContexts.NavbarContext = createContext(null); -} - -// @ts-expect-error - FIXME when you are working on it -export const NavbarContext = window.shellContexts.NavbarContext; +export const NavbarContext = createContext(null); diff --git a/ui/package-lock.json b/ui/package-lock.json index 88fb780ef1..bd499a5475 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -12,8 +12,8 @@ "@hookform/resolvers": "^3.1.0", "@js-temporal/polyfill": "^0.4.4", "@kubernetes/client-node": "github:scality/kubernetes-client-javascript.git#browser-0.10.4-64-ge7c6721", - "@scality/core-ui": "0.151.0", - "@scality/module-federation": "^1.3.4", + "@scality/core-ui": "git+https://github.com/scality/core-ui#bf0c36da657737f47dabe310bb1a20c136877970", + "@scality/module-federation": "git+https://github.com/scality/module-federation#c571388783a2a51ae3bf5d36ae66753c8b014bb5", "axios": "^0.21.1", "formik": "2.2.5", "jsonpath": "^1.1.1", @@ -21,9 +21,9 @@ "lodash.isequal": "^4.5.0", "lodash.sortby": "^4.7.0", "luxon": "^2.1.1", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "react-error-boundary": "^3.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-error-boundary": "^4.1.2", "react-hook-form": "^7.44.3", "react-intl": "^5.15.3", "react-json-view": "^1.21.3", @@ -34,7 +34,7 @@ "redux": "^4.0.1", "redux-saga": "^1.0.2", "reselect": "^2.5.4", - "styled-components": "^5.0.1", + "styled-components": "^5.3.11", "uuid": "3.3.2", "yup": "^0.32.9" }, @@ -50,7 +50,7 @@ "@rspack/core": "^0.7.5", "@testing-library/dom": "^9.3.1", "@testing-library/jest-dom": "^5.11.9", - "@testing-library/react": "^11.2.3", + "@testing-library/react": "^15.0.7", "@testing-library/react-hooks": "^3.4.2", "@testing-library/user-event": "^14.4.3", "@types/hapi__joi": "^17.1.9", @@ -58,10 +58,13 @@ "@types/lodash.isempty": "^4.4.7", "@types/lodash.isequal": "^4.5.6", "@types/lodash.sortby": "^4.7.7", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@types/react-redux": "^7.1.25", "@types/react-router": "^5.1.20", "@types/react-router-dom": "^5.3.3", - "@types/styled-components": "^5.1.26", + "@types/react-test-renderer": "^18.3.0", + "@types/styled-components": "^5.1.34", "@typescript-eslint/eslint-plugin": "^5.62.0", "babel-eslint": "^10.1.0", "babel-jest": "^26.6.3", @@ -84,7 +87,7 @@ "jest-preview": "^0.3.1", "msw": "0.36.8", "oidc-client": "^1.8.0", - "react-test-renderer": "^17.0.1", + "react-test-renderer": "^18.3.1", "ts-node": "^10.9.2", "typescript": "^5.3.3" }, @@ -2637,13 +2640,15 @@ "node_modules/@emotion/is-prop-valid": { "version": "0.8.8", "license": "MIT", + "optional": true, "dependencies": { "@emotion/memoize": "0.7.4" } }, "node_modules/@emotion/memoize": { "version": "0.7.4", - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/@emotion/react": { "version": "11.11.3", @@ -5532,8 +5537,9 @@ }, "node_modules/@scality/core-ui": { "version": "0.151.0", - "resolved": "https://registry.npmjs.org/@scality/core-ui/-/core-ui-0.151.0.tgz", - "integrity": "sha512-OeAhs+uiOOBDSGqzZGpIka1iCtRrGJkjNhzdRJhJtLwxKDFU7iyPUPA3MbJ8DoGJQN0do8k3PTyei1fZEiMXJA==", + "resolved": "git+ssh://git@github.com/scality/core-ui.git#bf0c36da657737f47dabe310bb1a20c136877970", + "integrity": "sha512-dC/zNxvxU7DVgxhbyKHgwwVyM2CwWACrwyVbh1VP0/7KTcgTmoYR2hO9qAMi9t8yyNWidOi9AVVzKupes13wRw==", + "license": "SEE LICENSE IN LICENSE", "dependencies": { "@floating-ui/dom": "^1.6.3", "@fortawesome/fontawesome-free": "^5.10.2", @@ -5547,9 +5553,9 @@ "framer-motion": "^4.1.17", "polished": "3.4.1", "pretty-bytes": "^5.6.0", - "react": "^17.0.2", + "react": "^18.3.1", "react-debounce-input": "3.2.2", - "react-dom": "^17.0.2", + "react-dom": "^18.3.1", "react-dropzone": "^14.2.3", "react-hook-form": "^7.49.2", "react-query": "^3.34.0", @@ -5557,6 +5563,7 @@ "react-router-dom": "5.2.0", "react-select": "4.3.1", "react-table": "^7.7.0", + "react-test-renderer": "^18.3.1", "react-virtualized": "9.22.3", "react-virtualized-auto-sizer": "^1.0.24", "react-window": "^1.8.6", @@ -5587,11 +5594,12 @@ }, "node_modules/@scality/module-federation": { "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@scality/module-federation/-/module-federation-1.3.4.tgz", - "integrity": "sha512-Okmgh+s9UTM6ropLt5QIJhswaN3m0hGNjGI2w/al+a4H+fQs5x/rAYngzWhFnHxdox0RUSRwA7aOZH1fBAvnmA==", + "resolved": "git+ssh://git@github.com/scality/module-federation.git#c571388783a2a51ae3bf5d36ae66753c8b014bb5", + "integrity": "sha512-lrpXm7Skkq/CtGQRI563pSelewbeNaBBbs3J4zzCiheb0H2fSs6JF6lqQHQjL9A0HRVjfnArotXlF8E8JzVtnw==", + "license": "SEE LICENSE IN LICENSE", "peerDependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.3.1", + "react-dom": "^18.3.1" } }, "node_modules/@sinclair/typebox": { @@ -5628,9 +5636,9 @@ } }, "node_modules/@storybook/preview-api": { - "version": "8.4.4", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.4.4.tgz", - "integrity": "sha512-iZrWQcjRBqBHFdDXVxGpw6mHBZMCMYqhWXdyJ0d1S2y3PwcfOjkcXlQ1UiAenFHlA6dKrcYw8luKUQTL9bKReA==", + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.4.5.tgz", + "integrity": "sha512-MKIZ2jQO/3cUdsT57eq8jRgB6inALo9BxrQ88f7mqzltOkMvADvTAY6y8JZqTUoDzWTH/ny/8SGGdtpqlxRuiQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/storybook" @@ -6196,19 +6204,27 @@ } }, "node_modules/@testing-library/react": { - "version": "11.2.5", + "version": "15.0.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.7.tgz", + "integrity": "sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^7.28.1" + "@testing-library/dom": "^10.0.0", + "@types/react-dom": "^18.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "@types/react": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@testing-library/react-hooks": { @@ -6224,54 +6240,32 @@ "react-test-renderer": ">=16.9.0" } }, - "node_modules/@testing-library/react/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" }, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@testing-library/react/node_modules/@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", - "dev": true - }, - "node_modules/@testing-library/react/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "node_modules/@testing-library/react/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "dependencies": { - "@types/istanbul-lib-report": "*" + "dequal": "^2.0.3" } }, "node_modules/@testing-library/react/node_modules/chalk": { @@ -6291,18 +6285,29 @@ } }, "node_modules/@testing-library/react/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", "react-is": "^17.0.1" }, "engines": { - "node": ">= 10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/react/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/@testing-library/react/node_modules/react-is": { @@ -6739,14 +6744,23 @@ "dev": true }, "node_modules/@types/react": { - "version": "17.0.3", - "license": "MIT", + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-redux": { "version": "7.1.25", "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz", @@ -6781,9 +6795,10 @@ } }, "node_modules/@types/react-test-renderer": { - "version": "17.0.1", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.3.0.tgz", + "integrity": "sha512-HW4MuEYxfDbOHQsVlY/XtOvNHftCVEPhJF2pQXXwcUiUF+Oyb0usgp48HSgpK5rt8m9KZb22yqOeZm+rrVG8gw==", "dev": true, - "license": "MIT", "dependencies": { "@types/react": "*" } @@ -6804,10 +6819,6 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, - "node_modules/@types/scheduler": { - "version": "0.16.1", - "license": "MIT" - }, "node_modules/@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", @@ -6861,9 +6872,9 @@ } }, "node_modules/@types/styled-components": { - "version": "5.1.26", - "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.26.tgz", - "integrity": "sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw==", + "version": "5.1.34", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.34.tgz", + "integrity": "sha512-mmiVvwpYklFIv9E8qfxuPyIt/OuyIrn6gMOAMOFUO3WJfSrSE+sGUoa4PiZj77Ut7bKZpaa6o1fBKS/4TOEvnA==", "dev": true, "dependencies": { "@types/hoist-non-react-statics": "*", @@ -11968,6 +11979,15 @@ "deps-sort": "bin/cmd.js" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/des.js": { "version": "1.0.1", "license": "MIT", @@ -22939,12 +22959,11 @@ } }, "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" @@ -22973,16 +22992,15 @@ } }, "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "17.0.2" + "react": "^18.3.1" } }, "node_modules/react-dropzone": { @@ -23002,15 +23020,12 @@ } }, "node_modules/react-error-boundary": { - "version": "3.1.1", - "license": "MIT", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.1.2.tgz", + "integrity": "sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==", "dependencies": { "@babel/runtime": "^7.12.5" }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, "peerDependencies": { "react": ">=16.13.1" } @@ -23219,15 +23234,15 @@ } }, "node_modules/react-shallow-renderer": { - "version": "16.14.1", - "dev": true, - "license": "MIT", + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", "dependencies": { "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0" + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" }, "peerDependencies": { - "react": "^16.0.0 || ^17.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-table": { @@ -23243,23 +23258,22 @@ } }, "node_modules/react-test-renderer": { - "version": "17.0.1", - "dev": true, - "license": "MIT", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.3.1.tgz", + "integrity": "sha512-KkAgygexHUkQqtvvx/otwxtuFu5cVjfzTCtjXLH9boS19/Nbtg84zS7wIQn39G8IlrhThBpQsMKkq5ZHZIYFXA==", "dependencies": { - "object-assign": "^4.1.1", - "react-is": "^17.0.1", - "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.1" + "react-is": "^18.3.1", + "react-shallow-renderer": "^16.15.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "17.0.1" + "react": "^18.3.1" } }, "node_modules/react-test-renderer/node_modules/react-is": { - "version": "17.0.1", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/react-textarea-autosize": { "version": "8.3.2", @@ -24066,12 +24080,11 @@ } }, "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "node_modules/schema-utils": { @@ -25308,15 +25321,16 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/styled-components": { - "version": "5.2.1", - "license": "MIT", + "version": "5.3.11", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", + "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", "dependencies": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^0.8.8", + "@emotion/is-prop-valid": "^1.1.0", "@emotion/stylis": "^0.8.4", "@emotion/unitless": "^0.7.4", - "babel-plugin-styled-components": ">= 1", + "babel-plugin-styled-components": ">= 1.12.0", "css-to-react-native": "^3.0.0", "hoist-non-react-statics": "^3.0.0", "shallowequal": "^1.1.0", @@ -25335,6 +25349,19 @@ "react-is": ">= 16.8.0" } }, + "node_modules/styled-components/node_modules/@emotion/is-prop-valid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/styled-components/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, "node_modules/styled-components/node_modules/has-flag": { "version": "3.0.0", "license": "MIT", @@ -29891,12 +29918,14 @@ }, "@emotion/is-prop-valid": { "version": "0.8.8", + "optional": true, "requires": { "@emotion/memoize": "0.7.4" } }, "@emotion/memoize": { - "version": "0.7.4" + "version": "0.7.4", + "optional": true }, "@emotion/react": { "version": "11.11.3", @@ -32152,9 +32181,9 @@ } }, "@scality/core-ui": { - "version": "0.151.0", - "resolved": "https://registry.npmjs.org/@scality/core-ui/-/core-ui-0.151.0.tgz", - "integrity": "sha512-OeAhs+uiOOBDSGqzZGpIka1iCtRrGJkjNhzdRJhJtLwxKDFU7iyPUPA3MbJ8DoGJQN0do8k3PTyei1fZEiMXJA==", + "version": "git+ssh://git@github.com/scality/core-ui.git#bf0c36da657737f47dabe310bb1a20c136877970", + "integrity": "sha512-dC/zNxvxU7DVgxhbyKHgwwVyM2CwWACrwyVbh1VP0/7KTcgTmoYR2hO9qAMi9t8yyNWidOi9AVVzKupes13wRw==", + "from": "@scality/core-ui@git+https://github.com/scality/core-ui#bf0c36da657737f47dabe310bb1a20c136877970", "requires": { "@floating-ui/dom": "^1.6.3", "@fortawesome/fontawesome-free": "^5.10.2", @@ -32168,9 +32197,9 @@ "framer-motion": "^4.1.17", "polished": "3.4.1", "pretty-bytes": "^5.6.0", - "react": "^17.0.2", + "react": "^18.3.1", "react-debounce-input": "3.2.2", - "react-dom": "^17.0.2", + "react-dom": "^18.3.1", "react-dropzone": "^14.2.3", "react-hook-form": "^7.49.2", "react-query": "^3.34.0", @@ -32178,6 +32207,7 @@ "react-router-dom": "5.2.0", "react-select": "4.3.1", "react-table": "^7.7.0", + "react-test-renderer": "^18.3.1", "react-virtualized": "9.22.3", "react-virtualized-auto-sizer": "^1.0.24", "react-window": "^1.8.6", @@ -32209,9 +32239,9 @@ } }, "@scality/module-federation": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@scality/module-federation/-/module-federation-1.3.4.tgz", - "integrity": "sha512-Okmgh+s9UTM6ropLt5QIJhswaN3m0hGNjGI2w/al+a4H+fQs5x/rAYngzWhFnHxdox0RUSRwA7aOZH1fBAvnmA==" + "version": "git+ssh://git@github.com/scality/module-federation.git#c571388783a2a51ae3bf5d36ae66753c8b014bb5", + "integrity": "sha512-lrpXm7Skkq/CtGQRI563pSelewbeNaBBbs3J4zzCiheb0H2fSs6JF6lqQHQjL9A0HRVjfnArotXlF8E8JzVtnw==", + "from": "@scality/module-federation@git+https://github.com/scality/module-federation#c571388783a2a51ae3bf5d36ae66753c8b014bb5" }, "@sinclair/typebox": { "version": "0.27.8", @@ -32246,9 +32276,9 @@ } }, "@storybook/preview-api": { - "version": "8.4.4", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.4.4.tgz", - "integrity": "sha512-iZrWQcjRBqBHFdDXVxGpw6mHBZMCMYqhWXdyJ0d1S2y3PwcfOjkcXlQ1UiAenFHlA6dKrcYw8luKUQTL9bKReA==" + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.4.5.tgz", + "integrity": "sha512-MKIZ2jQO/3cUdsT57eq8jRgB6inALo9BxrQ88f7mqzltOkMvADvTAY6y8JZqTUoDzWTH/ny/8SGGdtpqlxRuiQ==" }, "@styled-system/background": { "version": "5.1.2", @@ -32628,55 +32658,39 @@ } }, "@testing-library/react": { - "version": "11.2.5", + "version": "15.0.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.7.tgz", + "integrity": "sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^7.28.1" + "@testing-library/dom": "^10.0.0", + "@types/react-dom": "^18.0.0" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" } }, - "@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", - "dev": true - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "requires": { - "@types/istanbul-lib-report": "*" + "dequal": "^2.0.3" } }, "chalk": { @@ -32690,15 +32704,22 @@ } }, "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } } }, "react-is": { @@ -33104,13 +33125,23 @@ "dev": true }, "@types/react": { - "version": "17.0.3", + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", "requires": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, + "@types/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-redux": { "version": "7.1.25", "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz", @@ -33145,7 +33176,9 @@ } }, "@types/react-test-renderer": { - "version": "17.0.1", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.3.0.tgz", + "integrity": "sha512-HW4MuEYxfDbOHQsVlY/XtOvNHftCVEPhJF2pQXXwcUiUF+Oyb0usgp48HSgpK5rt8m9KZb22yqOeZm+rrVG8gw==", "dev": true, "requires": { "@types/react": "*" @@ -33166,9 +33199,6 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, - "@types/scheduler": { - "version": "0.16.1" - }, "@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", @@ -33219,9 +33249,9 @@ } }, "@types/styled-components": { - "version": "5.1.26", - "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.26.tgz", - "integrity": "sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw==", + "version": "5.1.34", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.34.tgz", + "integrity": "sha512-mmiVvwpYklFIv9E8qfxuPyIt/OuyIrn6gMOAMOFUO3WJfSrSE+sGUoa4PiZj77Ut7bKZpaa6o1fBKS/4TOEvnA==", "dev": true, "requires": { "@types/hoist-non-react-statics": "*", @@ -36854,6 +36884,12 @@ "through2": "^2.0.0" } }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true + }, "des.js": { "version": "1.0.1", "optional": true, @@ -44850,12 +44886,11 @@ } }, "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "react-base16-styling": { @@ -44877,13 +44912,12 @@ } }, "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.23.2" } }, "react-dropzone": { @@ -44897,7 +44931,9 @@ } }, "react-error-boundary": { - "version": "3.1.1", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.1.2.tgz", + "integrity": "sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==", "requires": { "@babel/runtime": "^7.12.5" } @@ -45026,11 +45062,12 @@ } }, "react-shallow-renderer": { - "version": "16.14.1", - "dev": true, + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", "requires": { "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0" + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" } }, "react-table": { @@ -45039,18 +45076,19 @@ "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==" }, "react-test-renderer": { - "version": "17.0.1", - "dev": true, + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.3.1.tgz", + "integrity": "sha512-KkAgygexHUkQqtvvx/otwxtuFu5cVjfzTCtjXLH9boS19/Nbtg84zS7wIQn39G8IlrhThBpQsMKkq5ZHZIYFXA==", "requires": { - "object-assign": "^4.1.1", - "react-is": "^17.0.1", - "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.1" + "react-is": "^18.3.1", + "react-shallow-renderer": "^16.15.0", + "scheduler": "^0.23.2" }, "dependencies": { "react-is": { - "version": "17.0.1", - "dev": true + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" } } }, @@ -45629,12 +45667,11 @@ } }, "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "schema-utils": { @@ -46592,20 +46629,35 @@ } }, "styled-components": { - "version": "5.2.1", + "version": "5.3.11", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", + "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^0.8.8", + "@emotion/is-prop-valid": "^1.1.0", "@emotion/stylis": "^0.8.4", "@emotion/unitless": "^0.7.4", - "babel-plugin-styled-components": ">= 1", + "babel-plugin-styled-components": ">= 1.12.0", "css-to-react-native": "^3.0.0", "hoist-non-react-statics": "^3.0.0", "shallowequal": "^1.1.0", "supports-color": "^5.5.0" }, "dependencies": { + "@emotion/is-prop-valid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "requires": { + "@emotion/memoize": "^0.9.0" + } + }, + "@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, "has-flag": { "version": "3.0.0" }, diff --git a/ui/package.json b/ui/package.json index fcdc2e4949..052a091fec 100644 --- a/ui/package.json +++ b/ui/package.json @@ -7,8 +7,8 @@ "@hookform/resolvers": "^3.1.0", "@js-temporal/polyfill": "^0.4.4", "@kubernetes/client-node": "github:scality/kubernetes-client-javascript.git#browser-0.10.4-64-ge7c6721", - "@scality/core-ui": "0.151.0", - "@scality/module-federation": "^1.3.4", + "@scality/core-ui": "git+https://github.com/scality/core-ui#bf0c36da657737f47dabe310bb1a20c136877970", + "@scality/module-federation": "git+https://github.com/scality/module-federation#c571388783a2a51ae3bf5d36ae66753c8b014bb5", "axios": "^0.21.1", "formik": "2.2.5", "jsonpath": "^1.1.1", @@ -16,9 +16,9 @@ "lodash.isequal": "^4.5.0", "lodash.sortby": "^4.7.0", "luxon": "^2.1.1", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "react-error-boundary": "^3.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-error-boundary": "^4.1.2", "react-hook-form": "^7.44.3", "react-intl": "^5.15.3", "react-json-view": "^1.21.3", @@ -29,7 +29,7 @@ "redux": "^4.0.1", "redux-saga": "^1.0.2", "reselect": "^2.5.4", - "styled-components": "^5.0.1", + "styled-components": "^5.3.11", "uuid": "3.3.2", "yup": "^0.32.9" }, @@ -78,7 +78,7 @@ "@rspack/core": "^0.7.5", "@testing-library/dom": "^9.3.1", "@testing-library/jest-dom": "^5.11.9", - "@testing-library/react": "^11.2.3", + "@testing-library/react": "^15.0.7", "@testing-library/react-hooks": "^3.4.2", "@testing-library/user-event": "^14.4.3", "@types/hapi__joi": "^17.1.9", @@ -86,10 +86,13 @@ "@types/lodash.isempty": "^4.4.7", "@types/lodash.isequal": "^4.5.6", "@types/lodash.sortby": "^4.7.7", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@types/react-redux": "^7.1.25", "@types/react-router": "^5.1.20", "@types/react-router-dom": "^5.3.3", - "@types/styled-components": "^5.1.26", + "@types/react-test-renderer": "^18.3.0", + "@types/styled-components": "^5.1.34", "@typescript-eslint/eslint-plugin": "^5.62.0", "babel-eslint": "^10.1.0", "babel-jest": "^26.6.3", @@ -112,7 +115,7 @@ "jest-preview": "^0.3.1", "msw": "0.36.8", "oidc-client": "^1.8.0", - "react-test-renderer": "^17.0.1", + "react-test-renderer": "^18.3.1", "ts-node": "^10.9.2", "typescript": "^5.3.3" }, diff --git a/ui/src/FederableApp.tsx b/ui/src/FederableApp.tsx index 43a6b68b1c..60003f3fb9 100644 --- a/ui/src/FederableApp.tsx +++ b/ui/src/FederableApp.tsx @@ -16,6 +16,7 @@ import { setHistory as setReduxHistory } from './ducks/history'; import { setApiConfigAction } from './ducks/config'; import { authErrorAction } from './ducks/app/authError'; import { AuthError } from './services/errorhandler'; +import { ShellHooksProvider, useShellHooks } from './ShellHooksContext'; const composeEnhancers = // @ts-expect-error - FIXME when you are working on it typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ @@ -87,7 +88,8 @@ type Config = { }; export const useConfig = () => { const { name } = useCurrentApp(); - const runtimeConfiguration = window.shellHooks.useConfig({ + const { useConfig } = useShellHooks(); + const runtimeConfiguration = useConfig({ configType: 'run', name, }); @@ -131,16 +133,21 @@ export const AppConfigProvider = ({ ); }; -export default function FederableApp() { +export default function FederableApp(props) { return ( - - - - - - - - - + + + + + + + + + + + ); } diff --git a/ui/src/ShellHooksContext.tsx b/ui/src/ShellHooksContext.tsx new file mode 100644 index 0000000000..13e72f3f0e --- /dev/null +++ b/ui/src/ShellHooksContext.tsx @@ -0,0 +1,99 @@ +import { FC, ReactNode, useMemo, useSyncExternalStore } from 'react'; +import { ShellTypes } from '../@mf-types/shell/compiled-types/src/FederatedApp'; + +export type ShellHooks = ShellTypes['shellHooks']; +export type ShellAlerts = ShellTypes['shellAlerts']; + +type Listener = () => void; + +const createShellHooksStore = () => { + let shellHooks: ShellHooks | null = null; + + const listeners: Set = new Set(); + + return { + getShellHooks: () => shellHooks, + + subscribe: (listener: Listener) => { + listeners.add(listener); + return () => { + listeners.delete(listener); + }; + }, + + setShellHooks: (newHooks: ShellHooks) => { + if (shellHooks !== newHooks) { + shellHooks = newHooks; + listeners.forEach((listener) => listener()); + } + }, + }; +}; + +const createShellAlertsStore = () => { + let shellAlerts: ShellAlerts | null = null; + const listeners: Set = new Set(); + + return { + getShellAlerts: () => shellAlerts, + + subscribe: (listener: Listener) => { + listeners.add(listener); + return () => { + listeners.delete(listener); + }; + }, + + setShellAlerts: (newAlerts: ShellAlerts) => { + if (shellAlerts !== newAlerts) { + shellAlerts = newAlerts; + listeners.forEach((listener) => listener()); + } + }, + }; +}; + +export const shellHooksStore = createShellHooksStore(); +export const shellAlertsStore = createShellAlertsStore(); + +export const useShellHooks = (): ShellHooks => { + const hooks = useSyncExternalStore( + shellHooksStore.subscribe, + shellHooksStore.getShellHooks, + ); + + if (!hooks) { + throw new Error( + 'useShellHooks must be used within a ShellHooksProvider and initialized with valid hooks.', + ); + } + + return hooks; +}; + +export const useShellAlerts = (): ShellAlerts => { + const alerts = useSyncExternalStore( + shellAlertsStore.subscribe, + shellAlertsStore.getShellAlerts, + ); + + if (!alerts) { + throw new Error( + 'useShellAlerts must be used within a ShellHooksProvider and initialized with valid alerts.', + ); + } + + return alerts; +}; + +export const ShellHooksProvider: FC<{ + shellHooks: ShellHooks; + shellAlerts: ShellAlerts; + children: ReactNode; +}> = ({ shellHooks, shellAlerts, children }) => { + useMemo(() => { + shellHooksStore.setShellHooks(shellHooks); + shellAlertsStore.setShellAlerts(shellAlerts); + }, [shellHooks, shellAlerts]); + return <>{children}; +}; diff --git a/ui/src/components/DashboardInventory.tsx b/ui/src/components/DashboardInventory.tsx index 5b6a585053..d0e70a582f 100644 --- a/ui/src/components/DashboardInventory.tsx +++ b/ui/src/components/DashboardInventory.tsx @@ -73,6 +73,7 @@ const DashboardInventory = () => { getNodesCountQuery(config || '', getToken), ); const history = useHistory(); + return ( @@ -108,7 +109,7 @@ const DashboardInventory = () => { - {nodesCount} + {nodesCount as number} @@ -143,7 +144,7 @@ const DashboardInventory = () => { - {volumesCount} + {volumesCount as number} diff --git a/ui/src/containers/AlertProvider.tsx b/ui/src/containers/AlertProvider.tsx index 8893a8227d..940edabd2e 100644 --- a/ui/src/containers/AlertProvider.tsx +++ b/ui/src/containers/AlertProvider.tsx @@ -1,20 +1,24 @@ import React from 'react'; -import type { FilterLabels, Alert } from '../services/alertUtils'; +import { QueryObserverResult } from 'react-query'; import { STATUS_HEALTH } from '../constants'; import { useConfig } from '../FederableApp'; -import { QueryObserverResult } from 'react-query'; +import type { Alert, FilterLabels } from '../services/alertUtils'; +import { useShellAlerts } from '../ShellHooksContext'; export type Status = 'healthy' | 'warning' | 'critical'; export const useAlerts = ( - filters: FilterLabels, + filters?: FilterLabels, ): Omit, 'data'> & { alerts?: Alert[] } => { - return window.shellAlerts.hooks.useAlerts(filters); + const { hooks } = useShellAlerts(); + return hooks.useAlerts(filters); }; export const useHighestSeverityAlerts = (filters: FilterLabels) => { - return window.shellAlerts.hooks.useHighestSeverityAlerts(filters); + const { hooks } = useShellAlerts(); + return hooks.useHighestSeverityAlerts(filters); }; export const useAlertLibrary = () => { - return window.shellAlerts.alertSelectors; + const { alertSelectors } = useShellAlerts(); + return alertSelectors; }; export const highestAlertToStatus = (alerts?: Alert[]): Status => { @@ -34,10 +38,11 @@ export const highestAlertToStatus = (alerts?: Alert[]): Status => { const AlertProvider = ({ children }: { children: React.ReactNode }) => { const { url_alertmanager } = useConfig(); + const alerts = useShellAlerts(); return ( - + {children} - + ); }; diff --git a/ui/src/containers/ConfigProvider.tsx b/ui/src/containers/ConfigProvider.tsx index 919fbf24d4..9cdab20c42 100644 --- a/ui/src/containers/ConfigProvider.tsx +++ b/ui/src/containers/ConfigProvider.tsx @@ -1,6 +1,10 @@ +import { useShellHooks } from '../ShellHooksContext'; + export function useLinkOpener() { - return window.shellHooks.useLinkOpener(); + const { useLinkOpener } = useShellHooks(); + return useLinkOpener(); } export function useDiscoveredViews() { - return window.shellHooks.useDiscoveredViews(); + const { useDiscoveredViews } = useShellHooks(); + return useDiscoveredViews(); } diff --git a/ui/src/containers/IntlProvider.tsx b/ui/src/containers/IntlProvider.tsx index d682b801ef..0bb19af5b0 100644 --- a/ui/src/containers/IntlProvider.tsx +++ b/ui/src/containers/IntlProvider.tsx @@ -2,13 +2,15 @@ import React from 'react'; import { IntlProvider } from 'react-intl'; import translations_en from '../translations/en.json'; import translations_fr from '../translations/fr.json'; +import { useShellHooks } from '../ShellHooksContext'; const messages = { EN: translations_en, FR: translations_fr, }; const FederatedIntlProvider = ({ children }: { children: React.ReactNode }) => { - const { language } = window.shellHooks.useLanguage(); + const { useLanguage } = useShellHooks(); + const { language } = useLanguage(); return ( {children} diff --git a/ui/src/containers/NodePage.tsx b/ui/src/containers/NodePage.tsx index c4728a2d16..da7df13dab 100644 --- a/ui/src/containers/NodePage.tsx +++ b/ui/src/containers/NodePage.tsx @@ -10,7 +10,6 @@ import { useTypedSelector } from '../hooks'; const NodePage = (props) => { useRefreshEffect(refreshNodesAction, stopRefreshNodesAction); - // @ts-expect-error - FIXME when you are working on it const { alerts } = useAlerts(); const theme = useTheme(); const nodeTableData = useSelector( diff --git a/ui/src/containers/PrivateRoute.tsx b/ui/src/containers/PrivateRoute.tsx index 5bf1939d4e..03207264da 100644 --- a/ui/src/containers/PrivateRoute.tsx +++ b/ui/src/containers/PrivateRoute.tsx @@ -11,13 +11,16 @@ import { useUserAccessRight, useUserRoles, } from '../hooks'; +import { useShellHooks } from '../ShellHooksContext'; export const useAuth = () => { - return window.shellHooks.useAuth(); + const { useAuth } = useShellHooks(); + return useAuth(); }; export const useShellConfig = () => { - return window.shellHooks.useShellConfig(); + const { useShellConfig } = useShellHooks(); + return useShellConfig(); }; const AccessRouteGuard = ({ component, ...rest }) => { @@ -39,7 +42,8 @@ const PrivateRoute = ({ component, ...rest }: PrivateRouteProps) => { (left, right) => left.isAuthError === right.isAuthError, ); const url_support = api?.url_support; - const { userData } = window.shellHooks.useAuth(); + const { useAuth } = useShellHooks(); + const { userData } = useAuth(); const dispatch = useDispatch(); const history = useHistory(); diff --git a/ui/src/hooks.tsx b/ui/src/hooks.tsx index cb63d88e7e..c810c21681 100644 --- a/ui/src/hooks.tsx +++ b/ui/src/hooks.tsx @@ -115,7 +115,6 @@ export const MetricsTimeSpanProvider = ({ ); }; export const useVolumesWithAlerts = (nodeName?: string) => { - // @ts-expect-error - FIXME when you are working on it const { alerts } = useAlerts(); const volumeListData = useTypedSelector((state) => // @ts-expect-error - FIXME when you are working on it