diff --git a/clients/ui/frontend/src/index.tsx b/clients/ui/frontend/src/index.tsx
index 69cb0727..5a3c1e65 100644
--- a/clients/ui/frontend/src/index.tsx
+++ b/clients/ui/frontend/src/index.tsx
@@ -6,6 +6,7 @@ import App from './app/App';
import { BrowserStorageContextProvider } from './shared/components/browserStorage/BrowserStorageContext';
import { NotificationContextProvider } from './app/context/NotificationContext';
import { NamespaceSelectorContextProvider } from './shared/context/NamespaceSelectorContext';
+import DashboardScriptLoader from './shared/context/DashboardScriptLoader';
const theme = createTheme({ cssVariables: true });
const root = ReactDOM.createRoot(document.getElementById('root')!);
@@ -16,9 +17,11 @@ root.render(
-
-
-
+
+
+
+
+
diff --git a/clients/ui/frontend/src/shared/api/apiUtils.ts b/clients/ui/frontend/src/shared/api/apiUtils.ts
index 19d831ff..c61ff3f5 100644
--- a/clients/ui/frontend/src/shared/api/apiUtils.ts
+++ b/clients/ui/frontend/src/shared/api/apiUtils.ts
@@ -189,8 +189,3 @@ export const isModelRegistryResponse = (response: unknown): response is Model
export const assembleModelRegistryBody = (data: T): ModelRegistryBody => ({
data,
});
-
-export const getNamespaceQueryParam = (): string | null => {
- const params = new URLSearchParams(window.location.search);
- return params.get('ns');
-};
diff --git a/clients/ui/frontend/src/shared/context/DashboardScriptLoader.tsx b/clients/ui/frontend/src/shared/context/DashboardScriptLoader.tsx
new file mode 100644
index 00000000..0acd3d57
--- /dev/null
+++ b/clients/ui/frontend/src/shared/context/DashboardScriptLoader.tsx
@@ -0,0 +1,57 @@
+import React, { useEffect, useState } from 'react';
+import { Bullseye, Spinner } from '@patternfly/react-core';
+import { isIntegrated } from '~/shared/utilities/const';
+
+type DashboardScriptLoaderProps = {
+ children: React.ReactNode;
+};
+
+const loadScript = (src: string, onLoad: () => void, onError: () => void) => {
+ const script = document.createElement('script');
+ script.src = src;
+ script.async = true;
+ script.onload = onLoad;
+ script.onerror = onError;
+ document.head.appendChild(script);
+};
+
+/* eslint-disable no-console */
+const DashboardScriptLoader: React.FC = ({ children }) => {
+ const [scriptLoaded, setScriptLoaded] = useState(false);
+
+ useEffect(() => {
+ const scriptUrl = '/dashboard_lib.bundle.js';
+
+ if (!isIntegrated()) {
+ console.warn(
+ 'DashboardScriptLoader: Script not loaded because deployment mode is not integrated',
+ );
+ setScriptLoaded(true);
+ return;
+ }
+
+ fetch(scriptUrl, { method: 'HEAD' })
+ .then((response) => {
+ if (response.ok) {
+ loadScript(
+ scriptUrl,
+ () => setScriptLoaded(true),
+ () => console.error('Failed to load the script'),
+ );
+ } else {
+ console.warn('Script not found');
+ }
+ })
+ .catch((error) => console.error('Error checking script existence', error));
+ }, []);
+
+ return !scriptLoaded ? (
+
+
+
+ ) : (
+ <>{children}>
+ );
+};
+
+export default DashboardScriptLoader;
diff --git a/clients/ui/frontend/src/shared/context/NamespaceSelectorContext.tsx b/clients/ui/frontend/src/shared/context/NamespaceSelectorContext.tsx
index 372e9372..610052a3 100644
--- a/clients/ui/frontend/src/shared/context/NamespaceSelectorContext.tsx
+++ b/clients/ui/frontend/src/shared/context/NamespaceSelectorContext.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import useNamespaces from '~/shared/hooks/useNamespaces';
import { Namespace } from '~/shared/types';
+import { isIntegrated } from '~/shared/utilities/const';
export type NamespaceSelectorContextType = {
namespacesLoaded: boolean;
@@ -31,6 +32,13 @@ export const NamespaceSelectorContextProvider: React.FC
);
+declare global {
+ interface Window {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ centraldashboard: any;
+ }
+}
+
const EnabledNamespaceSelectorContextProvider: React.FC = ({
children,
}) => {
@@ -40,6 +48,24 @@ const EnabledNamespaceSelectorContextProvider: React.FC 0 ? namespaces[0] : null;
+ React.useEffect(() => {
+ if (isIntegrated()) {
+ // Initialize the central dashboard client
+ try {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ window.centraldashboard.CentralDashboardEventHandler.init((cdeh: any) => {
+ // eslint-disable-next-line no-param-reassign
+ cdeh.onNamespaceSelected = (newNamespace: string) => {
+ setPreferredNamespace({ name: newNamespace });
+ };
+ });
+ } catch (err) {
+ /* eslint-disable no-console */
+ console.error('Failed to initialize central dashboard client', err);
+ }
+ }
+ }, []);
+
const contextValue = React.useMemo(
() => ({
namespacesLoaded: isLoaded,
diff --git a/clients/ui/frontend/src/shared/hooks/useQueryParamNamespaces.ts b/clients/ui/frontend/src/shared/hooks/useQueryParamNamespaces.ts
index e24ce3de..23f4900d 100644
--- a/clients/ui/frontend/src/shared/hooks/useQueryParamNamespaces.ts
+++ b/clients/ui/frontend/src/shared/hooks/useQueryParamNamespaces.ts
@@ -1,12 +1,10 @@
import React from 'react';
import { NamespaceSelectorContext } from '~/shared/context/NamespaceSelectorContext';
-import { isStandalone } from '~/shared/utilities/const';
-import { getNamespaceQueryParam } from '~/shared/api/apiUtils';
import { useDeepCompareMemoize } from '~/shared/utilities/useDeepCompareMemoize';
const useQueryParamNamespaces = (): Record => {
const { preferredNamespace: namespaceSelector } = React.useContext(NamespaceSelectorContext);
- const namespace = isStandalone() ? namespaceSelector?.name : getNamespaceQueryParam();
+ const namespace = namespaceSelector?.name;
return useDeepCompareMemoize({ namespace });
};