diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx index 2d8e49dfdf..ee19148adb 100644 --- a/frontend/src/app/App.tsx +++ b/frontend/src/app/App.tsx @@ -13,6 +13,7 @@ import { } from '@patternfly/react-core'; import ErrorBoundary from '~/components/error/ErrorBoundary'; import ToastNotifications from '~/components/ToastNotifications'; +import GlobalToastNotifications from '~/components/GlobalToastNotifications'; import { useWatchBuildStatus } from '~/utilities/useWatchBuildStatus'; import { useUser } from '~/redux/selectors'; import { DASHBOARD_MAIN_CONTAINER_ID } from '~/utilities/const'; @@ -23,6 +24,7 @@ import AppRoutes from './AppRoutes'; import NavSidebar from './NavSidebar'; import AppNotificationDrawer from './AppNotificationDrawer'; import { AppContext } from './AppContext'; +import NotificationsContextProvider from './NotificationsContext'; import { useApplicationSettings } from './useApplicationSettings'; import TelemetrySetup from './TelemetrySetup'; import { logout } from './appUtils'; @@ -89,25 +91,28 @@ const App: React.FC = () => { dashboardConfig, }} > - setNotificationsOpen(!notificationsOpen)} />} - sidebar={isAllowed ? : undefined} - notificationDrawer={ setNotificationsOpen(false)} />} - isNotificationDrawerExpanded={notificationsOpen} - mainContainerId={DASHBOARD_MAIN_CONTAINER_ID} - > - - - - - - - - - - + + setNotificationsOpen(!notificationsOpen)} />} + sidebar={isAllowed ? : undefined} + notificationDrawer={ setNotificationsOpen(false)} />} + isNotificationDrawerExpanded={notificationsOpen} + mainContainerId={DASHBOARD_MAIN_CONTAINER_ID} + > + + + + + + + + + + + + ); }; diff --git a/frontend/src/app/NotificationsContext.tsx b/frontend/src/app/NotificationsContext.tsx new file mode 100644 index 0000000000..f2e6043cdc --- /dev/null +++ b/frontend/src/app/NotificationsContext.tsx @@ -0,0 +1,46 @@ +import * as React from 'react'; +import { AppNotification } from '~/redux/types'; + +type NotificationsContext = { + notifications: AppNotification[]; + addNotification: (status: AppNotification['status'], title: string, message: string) => void; +}; + +export const NotificationsContext = React.createContext({ + notifications: [], + addNotification: () => undefined, +}); + +type NotificationsProviderProps = { + children: React.ReactNode; +}; + +const NotificationsContextProvider: React.FC = ({ children }) => { + const [notifications, setNotifications] = React.useState([]); + + const addNotification = React.useCallback( + (status: AppNotification['status'], title: string, message: string) => { + const newNotification = { + status, + title, + message, + timestamp: new Date(), + }; + + setNotifications([...notifications, newNotification]); + }, + [notifications], + ); + + return ( + + {children} + + ); +}; +export default NotificationsContextProvider; diff --git a/frontend/src/components/GlobalToastNotifications.tsx b/frontend/src/components/GlobalToastNotifications.tsx new file mode 100644 index 0000000000..7a51dc3f41 --- /dev/null +++ b/frontend/src/components/GlobalToastNotifications.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { AlertGroup } from '@patternfly/react-core'; +import { NotificationsContext } from '~/app/NotificationsContext'; +import ToastNotification from './ToastNotification'; + +const GlobalToastNotifications: React.FC = () => { + const { notifications } = React.useContext(NotificationsContext); + + if (!notifications) { + return null; + } + + return ( + + {notifications.map((notification) => ( + + ))} + + ); +}; + +export default GlobalToastNotifications;