mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
Ensure unique keys in navbar menu items (#16987)
This commit is contained in:
parent
f3cd0b0bc4
commit
16a5178527
3 changed files with 66 additions and 32 deletions
|
|
@ -407,7 +407,7 @@ export default function CreateKeyPage() {
|
|||
/>
|
||||
) : page == "api_ref" ? (
|
||||
<APIReferenceView proxySettings={proxySettings} />
|
||||
) : page == "settings" ? (
|
||||
) : page == "logging-and-alerts" ? (
|
||||
<Settings userID={userID} userRole={userRole} accessToken={accessToken} premiumUser={premiumUser} />
|
||||
) : page == "budgets" ? (
|
||||
<BudgetPanel accessToken={accessToken} />
|
||||
|
|
@ -419,7 +419,7 @@ export default function CreateKeyPage() {
|
|||
<PromptsPanel accessToken={accessToken} userRole={userRole} />
|
||||
) : page == "transform-request" ? (
|
||||
<TransformRequestPanel accessToken={accessToken} />
|
||||
) : page == "general-settings" ? (
|
||||
) : page == "router-settings" ? (
|
||||
<GeneralSettings
|
||||
userID={userID}
|
||||
userRole={userRole}
|
||||
|
|
@ -428,7 +428,7 @@ export default function CreateKeyPage() {
|
|||
/>
|
||||
) : page == "ui-theme" ? (
|
||||
<UIThemeSettings userID={userID} userRole={userRole} accessToken={accessToken} />
|
||||
) : page == "cost-tracking-settings" ? (
|
||||
) : page == "cost-tracking" ? (
|
||||
<CostTrackingSettings userID={userID} userRole={userRole} accessToken={accessToken} />
|
||||
) : page == "model-hub-table" ? (
|
||||
isAdminRole(userRole) ? (
|
||||
|
|
|
|||
|
|
@ -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(<Sidebar {...defaultProps} />);
|
||||
const allRenderedKeys = getAllKeysFromMenu(container);
|
||||
|
||||
const keySet = new Set<string>();
|
||||
const duplicates: string[] = [];
|
||||
for (const key of allRenderedKeys) {
|
||||
if (keySet.has(key)) {
|
||||
duplicates.push(key);
|
||||
}
|
||||
keySet.add(key);
|
||||
}
|
||||
expect(duplicates).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -49,84 +49,89 @@ const Sidebar: React.FC<SidebarProps> = ({ 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: <KeyOutlined style={{ fontSize: "18px" }} />,
|
||||
},
|
||||
{
|
||||
key: "3",
|
||||
key: "llm-playground",
|
||||
page: "llm-playground",
|
||||
label: "Playground",
|
||||
icon: <PlayCircleOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: rolesWithWriteAccess,
|
||||
},
|
||||
{
|
||||
key: "2",
|
||||
key: "models",
|
||||
page: "models",
|
||||
label: "Models + Endpoints",
|
||||
icon: <BlockOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: rolesWithWriteAccess,
|
||||
},
|
||||
{
|
||||
key: "12",
|
||||
key: "new_usage",
|
||||
page: "new_usage",
|
||||
label: "Usage",
|
||||
icon: <BarChartOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: [...all_admin_roles, ...internalUserRoles],
|
||||
},
|
||||
{ key: "6", page: "teams", label: "Teams", icon: <TeamOutlined style={{ fontSize: "18px" }} /> },
|
||||
{ key: "teams", page: "teams", label: "Teams", icon: <TeamOutlined style={{ fontSize: "18px" }} /> },
|
||||
{
|
||||
key: "17",
|
||||
key: "organizations",
|
||||
page: "organizations",
|
||||
label: "Organizations",
|
||||
icon: <BankOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{
|
||||
key: "5",
|
||||
key: "users",
|
||||
page: "users",
|
||||
label: "Internal Users",
|
||||
icon: <UserOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{
|
||||
key: "10",
|
||||
key: "budgets",
|
||||
page: "budgets",
|
||||
label: "Budgets",
|
||||
icon: <CreditCardOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{ key: "14", page: "api_ref", label: "API Reference", icon: <ApiOutlined style={{ fontSize: "18px" }} /> },
|
||||
{ key: "api_ref", page: "api_ref", label: "API Reference", icon: <ApiOutlined style={{ fontSize: "18px" }} /> },
|
||||
{
|
||||
key: "16",
|
||||
key: "model-hub-table",
|
||||
page: "model-hub-table",
|
||||
label: "AI Hub",
|
||||
icon: <AppstoreOutlined style={{ fontSize: "18px" }} />,
|
||||
},
|
||||
{ key: "15", page: "logs", label: "Logs", icon: <LineChartOutlined style={{ fontSize: "18px" }} /> },
|
||||
{ key: "logs", page: "logs", label: "Logs", icon: <LineChartOutlined style={{ fontSize: "18px" }} /> },
|
||||
{
|
||||
key: "11",
|
||||
key: "guardrails",
|
||||
page: "guardrails",
|
||||
label: "Guardrails",
|
||||
icon: <SafetyOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{ key: "18", page: "mcp-servers", label: "MCP Servers", icon: <ToolOutlined style={{ fontSize: "18px" }} /> },
|
||||
{
|
||||
key: "26",
|
||||
key: "mcp-servers",
|
||||
page: "mcp-servers",
|
||||
label: "MCP Servers",
|
||||
icon: <ToolOutlined style={{ fontSize: "18px" }} />,
|
||||
},
|
||||
{
|
||||
key: "tools",
|
||||
page: "tools",
|
||||
label: "Tools",
|
||||
icon: <ToolOutlined style={{ fontSize: "18px" }} />,
|
||||
children: [
|
||||
{
|
||||
key: "28",
|
||||
key: "search-tools",
|
||||
page: "search-tools",
|
||||
label: "Search Tools",
|
||||
icon: <SearchOutlined style={{ fontSize: "18px" }} />,
|
||||
},
|
||||
{
|
||||
key: "21",
|
||||
key: "vector-stores",
|
||||
page: "vector-stores",
|
||||
label: "Vector Stores",
|
||||
icon: <DatabaseOutlined style={{ fontSize: "18px" }} />,
|
||||
|
|
@ -141,35 +146,35 @@ const Sidebar: React.FC<SidebarProps> = ({ accessToken, setPage, userRole, defau
|
|||
icon: <ExperimentOutlined style={{ fontSize: "18px" }} />,
|
||||
children: [
|
||||
{
|
||||
key: "9",
|
||||
key: "caching",
|
||||
page: "caching",
|
||||
label: "Caching",
|
||||
icon: <DatabaseOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{
|
||||
key: "29",
|
||||
key: "agents",
|
||||
page: "agents",
|
||||
label: "Agents",
|
||||
icon: <RobotOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: rolesWithWriteAccess,
|
||||
},
|
||||
{
|
||||
key: "25",
|
||||
key: "prompts",
|
||||
page: "prompts",
|
||||
label: "Prompts",
|
||||
icon: <FileTextOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{
|
||||
key: "20",
|
||||
key: "transform-request",
|
||||
page: "transform-request",
|
||||
label: "API Playground",
|
||||
icon: <ApiOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: [...all_admin_roles, ...internalUserRoles],
|
||||
},
|
||||
{
|
||||
key: "19",
|
||||
key: "tag-management",
|
||||
page: "tag-management",
|
||||
label: "Tag Management",
|
||||
icon: <TagsOutlined style={{ fontSize: "18px" }} />,
|
||||
|
|
@ -186,35 +191,35 @@ const Sidebar: React.FC<SidebarProps> = ({ accessToken, setPage, userRole, defau
|
|||
roles: all_admin_roles,
|
||||
children: [
|
||||
{
|
||||
key: "11",
|
||||
page: "general-settings",
|
||||
key: "router-settings",
|
||||
page: "router-settings",
|
||||
label: "Router Settings",
|
||||
icon: <SettingOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{
|
||||
key: "8",
|
||||
page: "settings",
|
||||
key: "logging-and-alerts",
|
||||
page: "logging-and-alerts",
|
||||
label: "Logging & Alerts",
|
||||
icon: <SettingOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{
|
||||
key: "13",
|
||||
key: "admin-panel",
|
||||
page: "admin-panel",
|
||||
label: "Admin Settings",
|
||||
icon: <SettingOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{
|
||||
key: "27",
|
||||
page: "cost-tracking-settings",
|
||||
key: "cost-tracking",
|
||||
page: "cost-tracking",
|
||||
label: "Cost Tracking",
|
||||
icon: <BarChartOutlined style={{ fontSize: "18px" }} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{
|
||||
key: "14",
|
||||
key: "ui-theme",
|
||||
page: "ui-theme",
|
||||
label: "UI Theme",
|
||||
icon: <BgColorsOutlined style={{ fontSize: "18px" }} />,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue