diff --git a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx
index f6fcfb2fb74..462b0a3d99d 100644
--- a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx
+++ b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx
@@ -113,7 +113,7 @@ describe("KeyLifecycleSettings", () => {
renderWithProviders();
const input = screen.getByTestId("duration-input");
- expect(input).toHaveAttribute("placeholder", "e.g., 30d or -1 to never expire");
+ expect(input).toHaveAttribute("placeholder", "e.g., 30d");
});
it("should show correct tooltip in create mode", () => {
@@ -121,12 +121,12 @@ describe("KeyLifecycleSettings", () => {
const tooltips = screen.getAllByTestId("tooltip");
const expiryTooltip = tooltips.find((tooltip) =>
- tooltip.getAttribute("title")?.includes("Leave empty to never expire")
+ tooltip.getAttribute("title")?.includes("Leave empty to keep the current expiry unchanged")
);
expect(expiryTooltip).toBeInTheDocument();
expect(expiryTooltip).toHaveAttribute(
"title",
- "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to never expire."
+ "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to keep the current expiry unchanged."
);
});
@@ -135,12 +135,12 @@ describe("KeyLifecycleSettings", () => {
const tooltips = screen.getAllByTestId("tooltip");
const expiryTooltip = tooltips.find((tooltip) =>
- tooltip.getAttribute("title")?.includes("Use -1 to never expire")
+ tooltip.getAttribute("title")?.includes("Leave empty to keep the current expiry unchanged")
);
expect(expiryTooltip).toBeInTheDocument();
expect(expiryTooltip).toHaveAttribute(
"title",
- "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Use -1 to never expire."
+ "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to keep the current expiry unchanged."
);
});
diff --git a/ui/litellm-dashboard/src/components/leftnav.test.tsx b/ui/litellm-dashboard/src/components/leftnav.test.tsx
index 09109300dce..c168ffa21e0 100644
--- a/ui/litellm-dashboard/src/components/leftnav.test.tsx
+++ b/ui/litellm-dashboard/src/components/leftnav.test.tsx
@@ -9,6 +9,7 @@ vi.mock("../utils/roles", () => {
internalUserRoles: ["internal"],
rolesWithWriteAccess: ["admin", "internal"],
isAdminRole: (role: string) => role === "admin",
+ isUserTeamAdminForAnyTeam: () => false,
};
});
@@ -41,6 +42,10 @@ vi.mock("@/app/(dashboard)/hooks/organizations/useOrganizations", () => ({
useOrganizations: mockUseOrganizations,
}));
+vi.mock("@/app/(dashboard)/hooks/teams/useTeams", () => ({
+ useTeams: () => ({ data: [], isLoading: false, error: null }),
+}));
+
vi.mock("@/app/(dashboard)/hooks/uiConfig/useUIConfig", () => {
return {
useUIConfig: () => ({
@@ -64,17 +69,22 @@ describe("Sidebar (leftnav)", () => {
"Virtual Keys",
"Playground",
"Models + Endpoints",
+ "Agents",
+ "MCP Servers",
+ "Guardrails",
+ "Policies",
+ "Tools",
"Usage",
+ "Logs",
+ "Guardrails Monitor",
"Teams",
- "Organizations",
"Internal Users",
+ "Organizations",
+ "Access Groups",
"Budgets",
"API Reference",
"AI Hub",
- "Logs",
- "Guardrails",
- "MCP Servers",
- "Tools",
+ "Learning Resources",
"Experimental",
"Settings",
];
diff --git a/ui/litellm-dashboard/src/components/navbar.test.tsx b/ui/litellm-dashboard/src/components/navbar.test.tsx
index 125187e2340..9a3c781aaab 100644
--- a/ui/litellm-dashboard/src/components/navbar.test.tsx
+++ b/ui/litellm-dashboard/src/components/navbar.test.tsx
@@ -1,4 +1,5 @@
import userEvent from "@testing-library/user-event";
+import React, { useState } from "react";
import { describe, expect, it, vi } from "vitest";
import { renderWithProviders, screen, waitFor } from "../../tests/test-utils";
import Navbar from "./navbar";
@@ -6,8 +7,69 @@ import Navbar from "./navbar";
// Mock the hooks and utilities
vi.mock("@/components/networking", () => ({
getProxyBaseUrl: vi.fn(() => "http://localhost:4000"),
+ serverRootPath: "",
}));
+vi.mock("@/app/(dashboard)/hooks/useDisableBouncingIcon", () => ({
+ useDisableBouncingIcon: () => false,
+}));
+
+vi.mock("./Navbar/BlogDropdown/BlogDropdown", () => ({
+ BlogDropdown: () =>
Blog
,
+}));
+
+const mockUserDropdownData = vi.hoisted(() => ({
+ current: () => ({
+ userId: "test-user",
+ userEmail: "test@example.com",
+ userRole: "Admin",
+ premiumUser: false,
+ }),
+}));
+
+vi.mock("./Navbar/UserDropdown/UserDropdown", async (importOriginal) => {
+ const React = await import("react");
+ const { useState } = React;
+ const localStorageUtils = await import("@/utils/localStorageUtils");
+ return {
+ default: function MockUserDropdown({ onLogout }: { onLogout: () => void }) {
+ const { userId, userEmail, userRole, premiumUser } = mockUserDropdownData.current();
+ const [open, setOpen] = useState(false);
+ return (
+
+
+ {open && (
+
+ {userId}
+ {userRole}
+ {userEmail}
+ {premiumUser && Premium}
+
+
+
+ )}
+
+ );
+ },
+ };
+});
+
vi.mock("@/utils/proxyUtils", () => ({
fetchProxySettings: vi.fn(),
}));
@@ -122,7 +184,8 @@ describe("Navbar", () => {
it("should show premium user badge when premiumUser is true", async () => {
const user = userEvent.setup();
- mockUseAuthorizedImpl = () => ({
+ const originalCurrent = mockUserDropdownData.current;
+ mockUserDropdownData.current = () => ({
userId: "test-user",
userEmail: "test@example.com",
userRole: "Admin",
@@ -137,12 +200,7 @@ describe("Navbar", () => {
});
// Reset mock
- mockUseAuthorizedImpl = () => ({
- userId: "test-user",
- userEmail: "test@example.com",
- userRole: "Admin",
- premiumUser: false,
- });
+ mockUserDropdownData.current = originalCurrent;
});
it("should show version badge when health data contains version", () => {