diff --git a/ui/litellm-dashboard/src/components/common_components/NewBadge.test.tsx b/ui/litellm-dashboard/src/components/common_components/NewBadge.test.tsx
index a24b52db6b8..2500551d37b 100644
--- a/ui/litellm-dashboard/src/components/common_components/NewBadge.test.tsx
+++ b/ui/litellm-dashboard/src/components/common_components/NewBadge.test.tsx
@@ -49,4 +49,39 @@ describe("NewBadge", () => {
expect(container.firstChild).toBeNull();
});
+
+ it("should render badge with dot when dot prop is true", () => {
+ mockUseDisableShowNewBadge.mockReturnValue(false);
+
+ render(Test Content);
+
+ expect(screen.queryByText("New")).not.toBeInTheDocument();
+ expect(screen.getByText("Test Content")).toBeInTheDocument();
+ });
+
+ it("should render badge with 'New' text when dot prop is false", () => {
+ mockUseDisableShowNewBadge.mockReturnValue(false);
+
+ render(Test Content);
+
+ expect(screen.getByText("New")).toBeInTheDocument();
+ expect(screen.getByText("Test Content")).toBeInTheDocument();
+ });
+
+ it("should render badge with 'New' text when dot prop is not provided (defaults to false)", () => {
+ mockUseDisableShowNewBadge.mockReturnValue(false);
+
+ render(Test Content);
+
+ expect(screen.getByText("New")).toBeInTheDocument();
+ expect(screen.getByText("Test Content")).toBeInTheDocument();
+ });
+
+ it("should render badge with dot when dot is true and no children", () => {
+ mockUseDisableShowNewBadge.mockReturnValue(false);
+
+ render();
+
+ expect(screen.queryByText("New")).not.toBeInTheDocument();
+ });
});
diff --git a/ui/litellm-dashboard/src/components/common_components/NewBadge.tsx b/ui/litellm-dashboard/src/components/common_components/NewBadge.tsx
index 97cdea8cfbb..c9223a3c380 100644
--- a/ui/litellm-dashboard/src/components/common_components/NewBadge.tsx
+++ b/ui/litellm-dashboard/src/components/common_components/NewBadge.tsx
@@ -1,7 +1,13 @@
import { Badge } from "antd";
import { useDisableShowNewBadge } from "@/app/(dashboard)/hooks/useDisableShowNewBadge";
-export default function NewBadge({ children }: { children?: React.ReactNode }) {
+export default function NewBadge({
+ children,
+ dot = false
+}: {
+ children?: React.ReactNode;
+ dot?: boolean;
+}) {
const disableShowNewBadge = useDisableShowNewBadge();
if (disableShowNewBadge) {
@@ -9,10 +15,10 @@ export default function NewBadge({ children }: { children?: React.ReactNode }) {
}
return children ? (
-
+
{children}
) : (
-
+
);
}
diff --git a/ui/litellm-dashboard/src/components/leftnav.tsx b/ui/litellm-dashboard/src/components/leftnav.tsx
index 61071211778..b26590989d2 100644
--- a/ui/litellm-dashboard/src/components/leftnav.tsx
+++ b/ui/litellm-dashboard/src/components/leftnav.tsx
@@ -62,260 +62,260 @@ interface MenuGroup {
// Menu groups organized by category - defined outside component for export
const menuGroups: MenuGroup[] = [
- {
- groupLabel: "AI GATEWAY",
- items: [
- {
- key: "api-keys",
- page: "api-keys",
- label: "Virtual Keys",
- icon: ,
- },
- {
- key: "llm-playground",
- page: "llm-playground",
- label: "Playground",
- icon: ,
- roles: rolesWithWriteAccess,
- },
- {
- key: "models",
- page: "models",
- label: "Models + Endpoints",
- icon: ,
- roles: rolesWithWriteAccess,
- },
- {
- key: "agents",
- page: "agents",
- label: "Agents",
- icon: ,
- roles: rolesWithWriteAccess,
- },
- {
- key: "mcp-servers",
- page: "mcp-servers",
- label: "MCP Servers",
- icon: ,
- },
- {
- key: "guardrails",
- page: "guardrails",
- label: "Guardrails",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "policies",
- page: "policies",
- label: (
-
- Policies
-
- ),
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "tools",
- page: "tools",
- label: "Tools",
- icon: ,
- children: [
- {
- key: "search-tools",
- page: "search-tools",
- label: "Search Tools",
- icon: ,
- },
- {
- key: "vector-stores",
- page: "vector-stores",
- label: "Vector Stores",
- icon: ,
- },
- ],
- },
- ],
- },
- {
- groupLabel: "OBSERVABILITY",
- items: [
- {
- key: "new_usage",
- page: "new_usage",
- icon: ,
- roles: [...all_admin_roles, ...internalUserRoles],
- label: "Usage",
- },
- {
- key: "logs",
- page: "logs",
- label: (
-
- Logs
-
- ),
- icon: ,
- },
- ],
- },
- {
- groupLabel: "ACCESS CONTROL",
- items: [
- {
- key: "users",
- page: "users",
- label: "Internal Users",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "teams",
- page: "teams",
- label: "Teams",
- icon: ,
- },
- {
- key: "organizations",
- page: "organizations",
- label: "Organizations",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "budgets",
- page: "budgets",
- label: "Budgets",
- icon: ,
- roles: all_admin_roles,
- },
- ],
- },
- {
- groupLabel: "DEVELOPER TOOLS",
- items: [
- {
- key: "api_ref",
- page: "api_ref",
- label: "API Reference",
- icon: ,
- },
- {
- key: "model-hub-table",
- page: "model-hub-table",
- label: "AI Hub",
- icon: ,
- },
- {
- key: "learning-resources",
- page: "learning-resources",
- label: "Learning Resources",
- icon: ,
- external_url: "https://models.litellm.ai/cookbook",
- },
- {
- key: "experimental",
- page: "experimental",
- label: "Experimental",
- icon: ,
- children: [
- {
- key: "caching",
- page: "caching",
- label: "Caching",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "prompts",
- page: "prompts",
- label: "Prompts",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "transform-request",
- page: "transform-request",
- label: "API Playground",
- icon: ,
- roles: [...all_admin_roles, ...internalUserRoles],
- },
- {
- key: "tag-management",
- page: "tag-management",
- label: "Tag Management",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "claude-code-plugins",
- page: "claude-code-plugins",
- label: "Claude Code Plugins",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "4",
- page: "usage",
- label: "Old Usage",
- icon: ,
- }
- ],
- },
- ],
- },
- {
- groupLabel: "SETTINGS",
- roles: all_admin_roles,
- items: [
- {
- key: "settings",
- page: "settings",
- label: Settings,
- icon: ,
- roles: all_admin_roles,
- children: [
- {
- key: "router-settings",
- page: "router-settings",
- label: "Router Settings",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "logging-and-alerts",
- page: "logging-and-alerts",
- label: "Logging & Alerts",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "admin-panel",
- page: "admin-panel",
- label: "Admin Settings",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "cost-tracking",
- page: "cost-tracking",
- label: "Cost Tracking",
- icon: ,
- roles: all_admin_roles,
- },
- {
- key: "ui-theme",
- page: "ui-theme",
- label: "UI Theme",
- icon: ,
- roles: all_admin_roles,
- },
- ],
- },
- ],
- },
- ];
+ {
+ groupLabel: "AI GATEWAY",
+ items: [
+ {
+ key: "api-keys",
+ page: "api-keys",
+ label: "Virtual Keys",
+ icon: ,
+ },
+ {
+ key: "llm-playground",
+ page: "llm-playground",
+ label: "Playground",
+ icon: ,
+ roles: rolesWithWriteAccess,
+ },
+ {
+ key: "models",
+ page: "models",
+ label: "Models + Endpoints",
+ icon: ,
+ roles: rolesWithWriteAccess,
+ },
+ {
+ key: "agents",
+ page: "agents",
+ label: "Agents",
+ icon: ,
+ roles: rolesWithWriteAccess,
+ },
+ {
+ key: "mcp-servers",
+ page: "mcp-servers",
+ label: "MCP Servers",
+ icon: ,
+ },
+ {
+ key: "guardrails",
+ page: "guardrails",
+ label: "Guardrails",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "policies",
+ page: "policies",
+ label: (
+
+ Policies
+
+ ),
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "tools",
+ page: "tools",
+ label: "Tools",
+ icon: ,
+ children: [
+ {
+ key: "search-tools",
+ page: "search-tools",
+ label: "Search Tools",
+ icon: ,
+ },
+ {
+ key: "vector-stores",
+ page: "vector-stores",
+ label: "Vector Stores",
+ icon: ,
+ },
+ ],
+ },
+ ],
+ },
+ {
+ groupLabel: "OBSERVABILITY",
+ items: [
+ {
+ key: "new_usage",
+ page: "new_usage",
+ icon: ,
+ roles: [...all_admin_roles, ...internalUserRoles],
+ label: "Usage",
+ },
+ {
+ key: "logs",
+ page: "logs",
+ label: (
+
+ Logs
+
+ ),
+ icon: ,
+ },
+ ],
+ },
+ {
+ groupLabel: "ACCESS CONTROL",
+ items: [
+ {
+ key: "users",
+ page: "users",
+ label: "Internal Users",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "teams",
+ page: "teams",
+ label: "Teams",
+ icon: ,
+ },
+ {
+ key: "organizations",
+ page: "organizations",
+ label: "Organizations",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "budgets",
+ page: "budgets",
+ label: "Budgets",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ ],
+ },
+ {
+ groupLabel: "DEVELOPER TOOLS",
+ items: [
+ {
+ key: "api_ref",
+ page: "api_ref",
+ label: "API Reference",
+ icon: ,
+ },
+ {
+ key: "model-hub-table",
+ page: "model-hub-table",
+ label: "AI Hub",
+ icon: ,
+ },
+ {
+ key: "learning-resources",
+ page: "learning-resources",
+ label: "Learning Resources",
+ icon: ,
+ external_url: "https://models.litellm.ai/cookbook",
+ },
+ {
+ key: "experimental",
+ page: "experimental",
+ label: "Experimental",
+ icon: ,
+ children: [
+ {
+ key: "caching",
+ page: "caching",
+ label: "Caching",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "prompts",
+ page: "prompts",
+ label: "Prompts",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "transform-request",
+ page: "transform-request",
+ label: "API Playground",
+ icon: ,
+ roles: [...all_admin_roles, ...internalUserRoles],
+ },
+ {
+ key: "tag-management",
+ page: "tag-management",
+ label: "Tag Management",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "claude-code-plugins",
+ page: "claude-code-plugins",
+ label: "Claude Code Plugins",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "4",
+ page: "usage",
+ label: "Old Usage",
+ icon: ,
+ }
+ ],
+ },
+ ],
+ },
+ {
+ groupLabel: "SETTINGS",
+ roles: all_admin_roles,
+ items: [
+ {
+ key: "settings",
+ page: "settings",
+ label: Settings,
+ icon: ,
+ roles: all_admin_roles,
+ children: [
+ {
+ key: "router-settings",
+ page: "router-settings",
+ label: "Router Settings",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "logging-and-alerts",
+ page: "logging-and-alerts",
+ label: "Logging & Alerts",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "admin-panel",
+ page: "admin-panel",
+ label: "Admin Settings",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "cost-tracking",
+ page: "cost-tracking",
+ label: "Cost Tracking",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ {
+ key: "ui-theme",
+ page: "ui-theme",
+ label: "UI Theme",
+ icon: ,
+ roles: all_admin_roles,
+ },
+ ],
+ },
+ ],
+ },
+];
const Sidebar: React.FC = ({ setPage, defaultSelectedKey, collapsed = false, enabledPagesInternalUsers }) => {
const { userId, accessToken, userRole } = useAuthorized();
@@ -377,7 +377,7 @@ const Sidebar: React.FC = ({ setPage, defaultSelectedKey, collapse
if (!isAdmin && enabledPagesInternalUsers !== null && enabledPagesInternalUsers !== undefined) {
// If item has children, check if any children are visible
if (item.children && item.children.length > 0) {
- const hasVisibleChildren = item.children.some((child) =>
+ const hasVisibleChildren = item.children.some((child) =>
enabledPagesInternalUsers.includes(child.page)
);
if (hasVisibleChildren) {
@@ -385,7 +385,7 @@ const Sidebar: React.FC = ({ setPage, defaultSelectedKey, collapse
return true;
}
}
-
+
const isIncluded = enabledPagesInternalUsers.includes(item.page);
console.log(`[LeftNav] Page "${item.page}" (${item.key}): ${isIncluded ? "VISIBLE" : "HIDDEN"}`);
return isIncluded;
@@ -444,12 +444,12 @@ const Sidebar: React.FC = ({ setPage, defaultSelectedKey, collapse
})),
onClick: !item.children
? () => {
- if (item.external_url) {
- window.open(item.external_url, "_blank");
- } else {
- navigateToPage(item.page);
- }
+ if (item.external_url) {
+ window.open(item.external_url, "_blank");
+ } else {
+ navigateToPage(item.page);
}
+ }
: undefined,
})),
});
diff --git a/ui/litellm-dashboard/src/components/view_logs/SpendLogsSettingsModal/SpendLogsSettingsModal.tsx b/ui/litellm-dashboard/src/components/view_logs/SpendLogsSettingsModal/SpendLogsSettingsModal.tsx
index 6fe8b495346..29194ce9fcd 100644
--- a/ui/litellm-dashboard/src/components/view_logs/SpendLogsSettingsModal/SpendLogsSettingsModal.tsx
+++ b/ui/litellm-dashboard/src/components/view_logs/SpendLogsSettingsModal/SpendLogsSettingsModal.tsx
@@ -1,11 +1,12 @@
"use client";
+import { ConfigType, GeneralSettingsFieldName, useDeleteProxyConfigField, useProxyConfig } from "@/app/(dashboard)/hooks/proxyConfig/useProxyConfig";
import { StoreRequestInSpendLogsParams, useStoreRequestInSpendLogs } from "@/app/(dashboard)/hooks/storeRequestInSpendLogs/useStoreRequestInSpendLogs";
-import { ConfigType, useProxyConfig, useDeleteProxyConfigField, GeneralSettingsFieldName } from "@/app/(dashboard)/hooks/proxyConfig/useProxyConfig";
+import NewBadge from "@/components/common_components/NewBadge";
import NotificationsManager from "@/components/molecules/notifications_manager";
import { parseErrorMessage } from "@/components/shared/errorUtils";
import { ClockCircleOutlined } from "@ant-design/icons";
-import { Button, Form, Input, Modal, Skeleton, Space, Switch } from "antd";
+import { Button, Form, Input, Modal, Skeleton, Space, Switch, Typography } from "antd";
import React, { useEffect, useMemo } from "react";
interface SpendLogsSettingsModalProps {
@@ -98,7 +99,7 @@ const SpendLogsSettingsModal: React.FC = ({ isVisib
return (
Spend Logs Settings}
open={isVisible}
footer={
diff --git a/ui/litellm-dashboard/src/components/view_logs/index.tsx b/ui/litellm-dashboard/src/components/view_logs/index.tsx
index daf52619f8d..826fc7ccc02 100644
--- a/ui/litellm-dashboard/src/components/view_logs/index.tsx
+++ b/ui/litellm-dashboard/src/components/view_logs/index.tsx
@@ -1,38 +1,36 @@
+import { useQuery, useQueryClient } from "@tanstack/react-query";
import moment from "moment";
-import { useQuery } from "@tanstack/react-query";
-import { useState, useRef, useEffect, useCallback } from "react";
-import { useQueryClient } from "@tanstack/react-query";
+import { useCallback, useEffect, useRef, useState } from "react";
-import { uiSpendLogsCall, keyInfoV1Call, sessionSpendLogsCall, keyListCall, allEndUsersCall } from "../networking";
-import { DataTable } from "./table";
-import { columns, LogEntry } from "./columns";
-import { Row } from "@tanstack/react-table";
-import { prefetchLogDetails } from "./prefetch";
-import { RequestResponsePanel } from "./RequestResponsePanel";
-import { ErrorViewer } from "./ErrorViewer";
-import { internalUserRoles } from "../../utils/roles";
-import { ConfigInfoMessage } from "./ConfigInfoMessage";
-import { Button, Tooltip } from "antd";
-import { KeyResponse, Team } from "../key_team_helpers/key_list";
-import KeyInfoView from "../templates/key_info_view";
-import { SessionView } from "./SessionView";
-import { VectorStoreViewer } from "./VectorStoreViewer";
import GuardrailViewer from "@/components/view_logs/GuardrailViewer/GuardrailViewer";
-import { CostBreakdownViewer } from "./CostBreakdownViewer";
-import FilterComponent from "../molecules/filter";
-import { FilterOption } from "../molecules/filter";
-import { useLogFilterLogic } from "./log_filter_logic";
-import { fetchAllKeyAliases } from "../key_team_helpers/filter_helpers";
-import { Tab, TabGroup, TabList, TabPanels, TabPanel, Switch } from "@tremor/react";
-import AuditLogs from "./audit_logs";
-import { getTimeRangeDisplay } from "./logs_utils";
import { formatNumberWithCommas } from "@/utils/dataUtils";
import { truncateString } from "@/utils/textUtils";
+import { SettingOutlined } from "@ant-design/icons";
+import { Row } from "@tanstack/react-table";
+import { Switch, Tab, TabGroup, TabList, TabPanel, TabPanels } from "@tremor/react";
+import { Button, Tooltip } from "antd";
+import { internalUserRoles } from "../../utils/roles";
import DeletedKeysPage from "../DeletedKeysPage/DeletedKeysPage";
import DeletedTeamsPage from "../DeletedTeamsPage/DeletedTeamsPage";
-import NewBadge from "../common_components/NewBadge";
+import { fetchAllKeyAliases } from "../key_team_helpers/filter_helpers";
+import { KeyResponse, Team } from "../key_team_helpers/key_list";
+import FilterComponent, { FilterOption } from "../molecules/filter";
+import { allEndUsersCall, keyInfoV1Call, keyListCall, sessionSpendLogsCall, uiSpendLogsCall } from "../networking";
+import KeyInfoView from "../templates/key_info_view";
+import AuditLogs from "./audit_logs";
+import { columns, LogEntry } from "./columns";
+import { ConfigInfoMessage } from "./ConfigInfoMessage";
+import { CostBreakdownViewer } from "./CostBreakdownViewer";
+import { ErrorViewer } from "./ErrorViewer";
+import { useLogFilterLogic } from "./log_filter_logic";
+import { getTimeRangeDisplay } from "./logs_utils";
+import { prefetchLogDetails } from "./prefetch";
+import { RequestResponsePanel } from "./RequestResponsePanel";
+import { SessionView } from "./SessionView";
import SpendLogsSettingsModal from "./SpendLogsSettingsModal/SpendLogsSettingsModal";
-import { SettingOutlined } from "@ant-design/icons";
+import { DataTable } from "./table";
+import { VectorStoreViewer } from "./VectorStoreViewer";
+import NewBadge from "../common_components/NewBadge";
interface SpendLogsTableProps {
accessToken: string | null;
@@ -513,8 +511,8 @@ export default function SpendLogsTable({
Request Logs
Audit Logs
- <>Deleted Keys >
- <>Deleted Teams >
+ Deleted Keys
+ Deleted Teams
@@ -535,11 +533,12 @@ export default function SpendLogsTable({
)}
{!selectedSessionId && (
-