diff --git a/ui/litellm-dashboard/src/app/layout.tsx b/ui/litellm-dashboard/src/app/layout.tsx
index 95c485fe2f0..1233da9046f 100644
--- a/ui/litellm-dashboard/src/app/layout.tsx
+++ b/ui/litellm-dashboard/src/app/layout.tsx
@@ -2,6 +2,8 @@ import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
+import AntdGlobalProvider from "@/contexts/AntdGlobalProvider";
+
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
@@ -17,7 +19,9 @@ export default function RootLayout({
}>) {
return (
-
{children}
+
+ {children}
+
);
}
diff --git a/ui/litellm-dashboard/src/components/molecules/notifications_manager.tsx b/ui/litellm-dashboard/src/components/molecules/notifications_manager.tsx
index 71b14bee885..59b048b412c 100644
--- a/ui/litellm-dashboard/src/components/molecules/notifications_manager.tsx
+++ b/ui/litellm-dashboard/src/components/molecules/notifications_manager.tsx
@@ -1,8 +1,18 @@
import React from "react";
-import { notification } from "antd";
+import { notification as staticNotification } from "antd";
+import type { NotificationInstance } from "antd/es/notification/interface";
import { parseErrorMessage } from "../shared/errorUtils";
import { ArgsProps } from "antd/es/notification";
+let notificationInstance: NotificationInstance | null = null;
+
+export const setNotificationInstance = (instance: NotificationInstance) => {
+ notificationInstance = instance;
+};
+
+// Helper to get the best available notification instance
+const getNotification = () => notificationInstance || staticNotification;
+
type Placement = "top" | "topLeft" | "topRight" | "bottom" | "bottomLeft" | "bottomRight";
type NotificationConfig = {
@@ -251,7 +261,7 @@ function looksErrorPayload(input: any, status?: number): boolean {
const NotificationManager = {
error(input: string | NotificationConfig) {
const cfg = normalize(input, "Error");
- notification.error({
+ getNotification().error({
...COMMON_NOTIFICATION_PROPS,
...cfg,
placement: cfg.placement ?? defaultPlacement(),
@@ -261,7 +271,7 @@ const NotificationManager = {
warning(input: string | NotificationConfig) {
const cfg = normalize(input, "Warning");
- notification.warning({
+ getNotification().warning({
...COMMON_NOTIFICATION_PROPS,
...cfg,
placement: cfg.placement ?? defaultPlacement(),
@@ -271,7 +281,7 @@ const NotificationManager = {
info(input: string | NotificationConfig) {
const cfg = normalize(input, "Info");
- notification.info({
+ getNotification().info({
...COMMON_NOTIFICATION_PROPS,
...cfg,
placement: cfg.placement ?? defaultPlacement(),
@@ -281,7 +291,7 @@ const NotificationManager = {
success(input: string | React.ReactNode | NotificationConfig) {
if (React.isValidElement(input)) {
- notification.success({
+ getNotification().success({
...COMMON_NOTIFICATION_PROPS,
message: "Success",
description: input,
@@ -291,7 +301,7 @@ const NotificationManager = {
return;
}
const cfg = normalize(input as string | NotificationConfig, "Success");
- notification.success({
+ getNotification().success({
...COMMON_NOTIFICATION_PROPS,
...cfg,
placement: cfg.placement ?? defaultPlacement(),
@@ -316,11 +326,11 @@ const NotificationManager = {
title === "Content Blocked" ||
title === "Integration Error"
) {
- notification.warning({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 7 });
+ getNotification().warning({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 7 });
return;
}
if (title === "Server Error") {
- notification.error({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 8 });
+ getNotification().error({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 8 });
return;
}
if (
@@ -331,10 +341,10 @@ const NotificationManager = {
title === "Error" ||
title === "Already Exists"
) {
- notification.error({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 6 });
+ getNotification().error({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 6 });
return;
}
- notification.info({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 4 });
+ getNotification().info({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 4 });
return;
}
@@ -343,18 +353,18 @@ const NotificationManager = {
const payload = { ...base, message: cls?.title ?? "Info" };
if (cls?.kind === "success") {
- notification.success({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 3.5 });
+ getNotification().success({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 3.5 });
return;
}
if (cls?.kind === "warning") {
- notification.warning({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 6 });
+ getNotification().warning({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 6 });
return;
}
- notification.info({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 4 });
+ getNotification().info({ ...COMMON_NOTIFICATION_PROPS, ...payload, duration: extra?.duration ?? 4 });
},
clear() {
- notification.destroy();
+ getNotification().destroy();
},
};
diff --git a/ui/litellm-dashboard/src/contexts/AntdGlobalProvider.tsx b/ui/litellm-dashboard/src/contexts/AntdGlobalProvider.tsx
new file mode 100644
index 00000000000..5b5c1036fa9
--- /dev/null
+++ b/ui/litellm-dashboard/src/contexts/AntdGlobalProvider.tsx
@@ -0,0 +1,24 @@
+"use client";
+
+import React, { useEffect, useRef } from "react";
+import { notification } from "antd";
+import { setNotificationInstance } from "@/components/molecules/notifications_manager";
+
+export default function AntdGlobalProvider({ children }: { children: React.ReactNode }) {
+ const [api, contextHolder] = notification.useNotification();
+ const initialized = useRef(false);
+
+ useEffect(() => {
+ if (!initialized.current) {
+ setNotificationInstance(api);
+ initialized.current = true;
+ }
+ }, [api]);
+
+ return (
+ <>
+ {contextHolder}
+ {children}
+ >
+ );
+}