diff --git a/ui/litellm-dashboard/src/app/page.tsx b/ui/litellm-dashboard/src/app/page.tsx
index d65d8e72374..f547ab7d057 100644
--- a/ui/litellm-dashboard/src/app/page.tsx
+++ b/ui/litellm-dashboard/src/app/page.tsx
@@ -407,7 +407,7 @@ export default function CreateKeyPage() {
/>
) : page == "api_ref" ? (
- ) : page == "settings" ? (
+ ) : page == "logging-and-alerts" ? (
) : page == "budgets" ? (
@@ -419,7 +419,7 @@ export default function CreateKeyPage() {
) : page == "transform-request" ? (
- ) : page == "general-settings" ? (
+ ) : page == "router-settings" ? (
) : page == "ui-theme" ? (
- ) : page == "cost-tracking-settings" ? (
+ ) : page == "cost-tracking" ? (
) : page == "model-hub-table" ? (
isAdminRole(userRole) ? (
diff --git a/ui/litellm-dashboard/src/components/leftnav.test.tsx b/ui/litellm-dashboard/src/components/leftnav.test.tsx
index 7f07c9c1b35..1512c8b9350 100644
--- a/ui/litellm-dashboard/src/components/leftnav.test.tsx
+++ b/ui/litellm-dashboard/src/components/leftnav.test.tsx
@@ -66,4 +66,33 @@ describe("Sidebar (leftnav)", () => {
expect(getByText("Search Tools")).toBeInTheDocument();
});
});
+ it("has no duplicate keys among all menu items and their children", () => {
+ // Helper to recursively extract all keys from Ant Design Menu items
+ function getAllKeysFromMenu(wrapper: HTMLElement): string[] {
+ const allKeys: string[] = [];
+ // Ant Design renders key as data-menu-id or inside attributes, but for this case, we look for text as fallback.
+ // For a generic check, here we fetch ids from rendered list items, and also descend into submenus
+ const items = wrapper.querySelectorAll("[data-menu-id]");
+ items.forEach((item) => {
+ const dataMenuId = item.getAttribute("data-menu-id");
+ if (dataMenuId) {
+ allKeys.push(dataMenuId);
+ }
+ });
+ return allKeys;
+ }
+
+ const { container } = render();
+ const allRenderedKeys = getAllKeysFromMenu(container);
+
+ const keySet = new Set();
+ const duplicates: string[] = [];
+ for (const key of allRenderedKeys) {
+ if (keySet.has(key)) {
+ duplicates.push(key);
+ }
+ keySet.add(key);
+ }
+ expect(duplicates).toHaveLength(0);
+ });
});
diff --git a/ui/litellm-dashboard/src/components/leftnav.tsx b/ui/litellm-dashboard/src/components/leftnav.tsx
index efd9f1bb560..78d8a3940ce 100644
--- a/ui/litellm-dashboard/src/components/leftnav.tsx
+++ b/ui/litellm-dashboard/src/components/leftnav.tsx
@@ -49,84 +49,89 @@ const Sidebar: React.FC = ({ accessToken, setPage, userRole, defau
// Note: If a menu item does not have a role, it is visible to all roles.
const menuItems: MenuItem[] = [
{
- key: "1",
+ key: "api-keys",
page: "api-keys",
label: "Virtual Keys",
icon: ,
},
{
- key: "3",
+ key: "llm-playground",
page: "llm-playground",
label: "Playground",
icon: ,
roles: rolesWithWriteAccess,
},
{
- key: "2",
+ key: "models",
page: "models",
label: "Models + Endpoints",
icon: ,
roles: rolesWithWriteAccess,
},
{
- key: "12",
+ key: "new_usage",
page: "new_usage",
label: "Usage",
icon: ,
roles: [...all_admin_roles, ...internalUserRoles],
},
- { key: "6", page: "teams", label: "Teams", icon: },
+ { key: "teams", page: "teams", label: "Teams", icon: },
{
- key: "17",
+ key: "organizations",
page: "organizations",
label: "Organizations",
icon: ,
roles: all_admin_roles,
},
{
- key: "5",
+ key: "users",
page: "users",
label: "Internal Users",
icon: ,
roles: all_admin_roles,
},
{
- key: "10",
+ key: "budgets",
page: "budgets",
label: "Budgets",
icon: ,
roles: all_admin_roles,
},
- { key: "14", page: "api_ref", label: "API Reference", icon: },
+ { key: "api_ref", page: "api_ref", label: "API Reference", icon: },
{
- key: "16",
+ key: "model-hub-table",
page: "model-hub-table",
label: "AI Hub",
icon: ,
},
- { key: "15", page: "logs", label: "Logs", icon: },
+ { key: "logs", page: "logs", label: "Logs", icon: },
{
- key: "11",
+ key: "guardrails",
page: "guardrails",
label: "Guardrails",
icon: ,
roles: all_admin_roles,
},
- { key: "18", page: "mcp-servers", label: "MCP Servers", icon: },
{
- key: "26",
+ key: "mcp-servers",
+ page: "mcp-servers",
+ label: "MCP Servers",
+ icon: ,
+ },
+ {
+ key: "tools",
page: "tools",
label: "Tools",
icon: ,
children: [
{
- key: "28",
+ key: "search-tools",
page: "search-tools",
label: "Search Tools",
icon: ,
},
{
- key: "21",
+ key: "vector-stores",
page: "vector-stores",
label: "Vector Stores",
icon: ,
@@ -141,35 +146,35 @@ const Sidebar: React.FC = ({ accessToken, setPage, userRole, defau
icon: ,
children: [
{
- key: "9",
+ key: "caching",
page: "caching",
label: "Caching",
icon: ,
roles: all_admin_roles,
},
{
- key: "29",
+ key: "agents",
page: "agents",
label: "Agents",
icon: ,
roles: rolesWithWriteAccess,
},
{
- key: "25",
+ key: "prompts",
page: "prompts",
label: "Prompts",
icon: ,
roles: all_admin_roles,
},
{
- key: "20",
+ key: "transform-request",
page: "transform-request",
label: "API Playground",
icon: ,
roles: [...all_admin_roles, ...internalUserRoles],
},
{
- key: "19",
+ key: "tag-management",
page: "tag-management",
label: "Tag Management",
icon: ,
@@ -186,35 +191,35 @@ const Sidebar: React.FC = ({ accessToken, setPage, userRole, defau
roles: all_admin_roles,
children: [
{
- key: "11",
- page: "general-settings",
+ key: "router-settings",
+ page: "router-settings",
label: "Router Settings",
icon: ,
roles: all_admin_roles,
},
{
- key: "8",
- page: "settings",
+ key: "logging-and-alerts",
+ page: "logging-and-alerts",
label: "Logging & Alerts",
icon: ,
roles: all_admin_roles,
},
{
- key: "13",
+ key: "admin-panel",
page: "admin-panel",
label: "Admin Settings",
icon: ,
roles: all_admin_roles,
},
{
- key: "27",
- page: "cost-tracking-settings",
+ key: "cost-tracking",
+ page: "cost-tracking",
label: "Cost Tracking",
icon: ,
roles: all_admin_roles,
},
{
- key: "14",
+ key: "ui-theme",
page: "ui-theme",
label: "UI Theme",
icon: ,