From 1b8a9b352a8a726ecb4d758519a27f994c6718d5 Mon Sep 17 00:00:00 2001 From: Tristan Chuine Date: Thu, 19 Dec 2024 19:33:51 +0100 Subject: [PATCH] Migrate to new NotificationProvider --- package-lock.json | 11 ++++---- package.json | 3 +-- src/components/App/app-wrapper.tsx | 7 ++++- src/components/App/app.tsx | 36 ++++++++++---------------- src/services/config-notification.ts | 23 ----------------- src/services/index.ts | 3 --- src/utils/notifications-provider.ts | 40 +++++++++++++++++++++++++++++ 7 files changed, 65 insertions(+), 58 deletions(-) delete mode 100644 src/services/config-notification.ts create mode 100644 src/utils/notifications-provider.ts diff --git a/package-lock.json b/package-lock.json index 72932d1..ac2160a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", - "@gridsuite/commons-ui": "0.67.0", + "@gridsuite/commons-ui": "0.75.0", "@hookform/resolvers": "^3.3.4", "@mui/icons-material": "^5.15.14", "@mui/lab": "5.0.0-alpha.169", @@ -31,7 +31,6 @@ "react-redux": "^9.1.0", "react-router-dom": "^6.22.3", "react-window": "^1.8.10", - "reconnecting-websocket": "^4.4.0", "redux": "^5.0.1", "type-fest": "^4.14.0", "typeface-roboto": "^1.1.13", @@ -2954,10 +2953,9 @@ } }, "node_modules/@gridsuite/commons-ui": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/@gridsuite/commons-ui/-/commons-ui-0.67.0.tgz", - "integrity": "sha512-gfUOBXIIlEKjNgEV2TVgTx31fApMB7x9rlPYgZr8Um65GBeRzVyRSYkoc3cWEipjJYbh3FE7KOh/CEZAus3tiQ==", - "license": "MPL-2.0", + "version": "0.75.0", + "resolved": "https://registry.npmjs.org/@gridsuite/commons-ui/-/commons-ui-0.75.0.tgz", + "integrity": "sha512-yjBjVZZkftRUCV3ZWWYNyfL5uu0a0+PstberxcC7QUulrwGbZuSzYh3F5Nr29qHgNTWxGi/jaz+E+ANkpOGWdw==", "dependencies": { "@react-querybuilder/dnd": "^7.2.0", "@react-querybuilder/material": "^7.2.0", @@ -2974,6 +2972,7 @@ "react-dnd-html5-backend": "^16.0.1", "react-querybuilder": "^7.2.0", "react-virtualized": "^9.22.5", + "reconnecting-websocket": "^4.4.0", "uuid": "^9.0.1" }, "engines": { diff --git a/package.json b/package.json index eab4f6d..7c5b1f1 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", - "@gridsuite/commons-ui": "0.67.0", + "@gridsuite/commons-ui": "0.75.0", "@hookform/resolvers": "^3.3.4", "@mui/icons-material": "^5.15.14", "@mui/lab": "5.0.0-alpha.169", @@ -36,7 +36,6 @@ "react-redux": "^9.1.0", "react-router-dom": "^6.22.3", "react-window": "^1.8.10", - "reconnecting-websocket": "^4.4.0", "redux": "^5.0.1", "type-fest": "^4.14.0", "typeface-roboto": "^1.1.13", diff --git a/src/components/App/app-wrapper.tsx b/src/components/App/app-wrapper.tsx index 316af81..84b729b 100644 --- a/src/components/App/app-wrapper.tsx +++ b/src/components/App/app-wrapper.tsx @@ -24,6 +24,7 @@ import { SnackbarProvider, topBarEn, topBarFr, + NotificationsProvider, } from '@gridsuite/commons-ui'; import { IntlConfig, IntlProvider } from 'react-intl'; import { Provider, useSelector } from 'react-redux'; @@ -33,6 +34,7 @@ import { store } from '../../redux/store'; import { PARAM_THEME } from '../../utils/config-params'; import { AppState } from '../../redux/reducer'; import { AppWithAuthRouter } from '../../routes'; +import { useNotificationsUrlGenerator } from '../../utils/notifications-provider'; const lightTheme: ThemeOptions = { palette: { @@ -119,6 +121,7 @@ const AppWrapperRouterLayout: typeof App = (props, context) => { const computedLanguage = useSelector((state: AppState) => state.computedLanguage); const theme = useSelector((state: AppState) => state[PARAM_THEME]); const themeCompiled = useMemo(() => getMuiTheme(theme, computedLanguage), [computedLanguage, theme]); + const urlMapper = useNotificationsUrlGenerator(); return ( @@ -126,7 +129,9 @@ const AppWrapperRouterLayout: typeof App = (props, context) => { - {props.children} + + {props.children} + diff --git a/src/components/App/app.tsx b/src/components/App/app.tsx index e4a85e4..e08d06e 100644 --- a/src/components/App/app.tsx +++ b/src/components/App/app.tsx @@ -8,16 +8,16 @@ import { FunctionComponent, PropsWithChildren, useCallback, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Grid } from '@mui/material'; -import { CardErrorBoundary, useSnackMessage } from '@gridsuite/commons-ui'; +import { CardErrorBoundary, useNotificationsListener, useSnackMessage } from '@gridsuite/commons-ui'; import { selectComputedLanguage, selectLanguage, selectTheme } from '../../redux/actions'; import { AppState } from '../../redux/reducer'; -import { ConfigNotif, ConfigParameters, ConfigSrv } from '../../services'; +import { ConfigParameters, ConfigSrv } from '../../services'; import { APP_NAME, COMMON_APP_NAME, PARAM_LANGUAGE, PARAM_THEME } from '../../utils/config-params'; import { getComputedLanguage } from '../../utils/language'; import AppTopBar from './app-top-bar'; -import ReconnectingWebSocket from 'reconnecting-websocket'; import { useDebugRender } from '../../utils/hooks'; import { AppDispatch } from '../../redux/store'; +import { NOTIFICATIONS_URL_KEYS } from '../../utils/notifications-provider'; const App: FunctionComponent> = (props, context) => { useDebugRender('app'); @@ -47,26 +47,19 @@ const App: FunctionComponent> = (props, context) => { [dispatch] ); - const connectNotificationsUpdateConfig = useCallback((): ReconnectingWebSocket => { - const ws = ConfigNotif.connectNotificationsWsUpdateConfig(); - ws.onmessage = function (event) { - let eventData = JSON.parse(event.data); + const updateConfig = useCallback( + (event: MessageEvent) => { + const eventData = JSON.parse(event.data); if (eventData?.headers?.parameterName) { ConfigSrv.fetchConfigParameter(eventData.headers.parameterName) .then((param) => updateParams([param])) - .catch((error) => - snackError({ - messageTxt: error.message, - headerId: 'paramsRetrievingError', - }) - ); + .catch((error) => snackError({ messageTxt: error.message, headerId: 'paramsRetrievingError' })); } - }; - ws.onerror = function (event) { - console.error('Unexpected Notification WebSocket error', event); - }; - return ws; - }, [updateParams, snackError]); + }, + [updateParams, snackError] + ); + + useNotificationsListener(NOTIFICATIONS_URL_KEYS.CONFIG, { listenerCallbackMessage: updateConfig }); useEffect(() => { if (user !== null) { @@ -87,11 +80,8 @@ const App: FunctionComponent> = (props, context) => { headerId: 'paramsRetrievingError', }) ); - - const ws = connectNotificationsUpdateConfig(); - return () => ws.close(); } - }, [user, dispatch, updateParams, snackError, connectNotificationsUpdateConfig]); + }, [user, dispatch, updateParams, snackError]); return ( getUrlWithToken(webSocketUrl), undefined, { - debug: import.meta.env.VITE_DEBUG_REQUESTS === 'true', - }); - reconnectingWebSocket.onopen = function (event: Event) { - console.info(`Connected Websocket update config ui: ${webSocketUrl}`); - }; - return reconnectingWebSocket; -} diff --git a/src/services/index.ts b/src/services/index.ts index 036f387..4f8a125 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -8,9 +8,6 @@ export * as ConfigSrv from './config'; export type * from './config'; -export * as ConfigNotif from './config-notification'; -export type * from './config-notification'; - export * as AppsMetadataSrv from './apps-metadata'; export type * from './apps-metadata'; diff --git a/src/utils/notifications-provider.ts b/src/utils/notifications-provider.ts new file mode 100644 index 0000000..fc883fc --- /dev/null +++ b/src/utils/notifications-provider.ts @@ -0,0 +1,40 @@ +/* + * Copyright © 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import type { AppState } from '../redux/reducer'; +import { getUrlWithToken, getWsBase } from './api-ws'; +import { APP_NAME } from './config-params'; + +export enum NOTIFICATIONS_URL_KEYS { + CONFIG = 'CONFIG', +} + +export const PREFIX_CONFIG_NOTIFICATION_WS = import.meta.env.VITE_WS_GATEWAY + '/config-notification'; + +export function useNotificationsUrlGenerator() { + // The websocket API doesn't allow relative urls + const wsBase = getWsBase(); + const tokenId = useSelector((state: AppState) => state.user?.id_token); + + // return a mapper with NOTIFICATIONS_URL_KEYS and undefined value if URL is not yet buildable (tokenId) + // it will be used to register listeners as soon as possible. + return useMemo( + () => + ({ + [NOTIFICATIONS_URL_KEYS.CONFIG]: tokenId + ? getUrlWithToken( + `${wsBase}${PREFIX_CONFIG_NOTIFICATION_WS}/notify?${new URLSearchParams({ + appName: APP_NAME, + })}` + ) + : undefined, + } satisfies Record), + [wsBase, tokenId] + ); +}