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;