- {showSwitcher ? (
-
-
-
- ) : (
- section && {section}
- )}
- {(showSwitcher || section) && }
+
+
+
+
{title}
diff --git a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.test.tsx b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.test.tsx
index bdbf74cdf7d..d9a28b2ab8c 100644
--- a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.test.tsx
+++ b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.test.tsx
@@ -49,9 +49,23 @@ describe("ViewSwitcher", () => {
state.setMode.mockClear();
});
- it("renders nothing with no plugins, chat disabled, and a non-admin user", () => {
- const { container } = render();
- expect(container.firstChild).toBeNull();
+ it("still renders the selector with a disabled Chat hint when there are no plugins and chat is off", async () => {
+ render();
+
+ const button = screen.getByRole("button");
+ expect(button).toHaveTextContent("AI Gateway");
+
+ act(() => {
+ fireEvent.click(button);
+ });
+ await waitFor(() => expect(screen.getByText("Chat")).toBeInTheDocument());
+ expect(screen.getByText(/Admins can enable in Settings/i)).toBeInTheDocument();
+
+ act(() => {
+ fireEvent.click(screen.getByText("Chat"));
+ });
+ expect(assignSpy).not.toHaveBeenCalled();
+ expect(state.setMode).not.toHaveBeenCalled();
});
it("labels the button from the active plugin and lists AI Gateway + each plugin", async () => {
@@ -95,7 +109,7 @@ describe("ViewSwitcher", () => {
fireEvent.click(screen.getByRole("button"));
});
await waitFor(() => expect(screen.getByText("Chat")).toBeInTheDocument());
- expect(screen.queryByText(/Enable in Admin Settings/i)).not.toBeInTheDocument();
+ expect(screen.queryByText(/Admins can enable in Settings/i)).not.toBeInTheDocument();
act(() => {
fireEvent.click(screen.getByText("Chat"));
@@ -121,7 +135,7 @@ describe("ViewSwitcher", () => {
expect(assignSpy).toHaveBeenCalledWith("/ui/");
});
- it("hides the Chat entry from everyone when disabled", async () => {
+ it("shows Chat as a disabled, non-navigating entry with an admin hint when disabled", async () => {
state.enableChatUI = false;
state.plugins = [{ name: "obs", display_name: "Observability", url: "http://localhost:9000" }];
render();
@@ -130,6 +144,12 @@ describe("ViewSwitcher", () => {
fireEvent.click(screen.getByRole("button"));
});
await waitFor(() => expect(screen.getByText("Observability")).toBeInTheDocument());
- expect(screen.queryByText("Chat")).not.toBeInTheDocument();
+ expect(screen.getByText("Chat")).toBeInTheDocument();
+ expect(screen.getByText(/Admins can enable in Settings/i)).toBeInTheDocument();
+
+ act(() => {
+ fireEvent.click(screen.getByText("Chat"));
+ });
+ expect(assignSpy).not.toHaveBeenCalled();
});
});
diff --git a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.tsx b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.tsx
index b4876f791eb..09a4538ae18 100644
--- a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.tsx
+++ b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.tsx
@@ -11,12 +11,6 @@ import { migratedHref } from "@/utils/migratedPages";
const GATEWAY = "ai-gateway";
const CHAT = "chat";
-export function useViewSwitcherVisible(): boolean {
- const { plugins } = usePluginMode();
- const { data: uiSettings } = useUISettings();
- return plugins.length > 0 || Boolean(uiSettings?.values?.enable_chat_ui);
-}
-
export default function ViewSwitcher() {
const { mode, setMode, plugins } = usePluginMode();
const { data: uiSettings } = useUISettings();
@@ -24,8 +18,6 @@ export default function ViewSwitcher() {
const chatEnabled = Boolean(uiSettings?.values?.enable_chat_ui);
- if (plugins.length === 0 && !chatEnabled) return null;
-
const chatHref = migratedHref(CHAT);
const normalizedPathname = (pathname ?? "").replace(/\/+$/, "");
const isChatRoute = chatEnabled && (normalizedPathname === chatHref || normalizedPathname.startsWith(`${chatHref}/`));
@@ -37,6 +29,29 @@ export default function ViewSwitcher() {
...plugins.map((p) => ({ key: p.name, label: p.display_name })),
];
+ const chatItem = chatEnabled
+ ? {
+ key: CHAT,
+ label: (
+
+ Chat
+ {isChatRoute && }
+
+ ),
+ }
+ : {
+ key: CHAT,
+ disabled: true,
+ label: (
+
+ Chat
+
+ Admins can enable in Settings
+
+
+ ),
+ };
+
const items: MenuProps["items"] = [
...modeEntries.map((e) => ({
key: e.key,
@@ -47,19 +62,7 @@ export default function ViewSwitcher() {
),
})),
- ...(chatEnabled
- ? [
- {
- key: CHAT,
- label: (
-
- Chat
- {isChatRoute && }
-
- ),
- },
- ]
- : []),
+ chatItem,
];
const onClick: MenuProps["onClick"] = ({ key }) => {