From 09fa0833b43820c039f45027ce26663de5a5dc54 Mon Sep 17 00:00:00 2001 From: yassin Date: Wed, 16 Sep 2026 10:17:46 +0000 Subject: [PATCH] feat(ui): surface top-key truncation on the team usage view Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../components/EntityUsage/EntityUsage.test.tsx | 17 +++++++++++++++++ .../components/EntityUsage/EntityUsage.tsx | 15 ++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.test.tsx index 2a6c2ede478..5846a63bc70 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.test.tsx @@ -569,6 +569,23 @@ describe("EntityUsage", () => { expect(screen.getAllByText("Activity Metrics")[1]).toBeInTheDocument(); }); + it("tells the team view how many keys the proxy left out of the per-key lists", async () => { + mockTeamDailyActivityAggregatedCall.mockResolvedValue({ + ...mockSpendData, + metadata: { ...mockSpendData.metadata, api_key_limit: 100, total_api_keys: 3000 }, + }); + render(); + + await waitFor(() => { + expect(mockTeamDailyActivityAggregatedCall).toHaveBeenCalled(); + }); + act(() => { + fireEvent.click(screen.getByText("Key Activity")); + }); + + expect(await screen.findByRole("note")).toHaveTextContent("Only the 100 highest-spend keys of 3,000 are loaded"); + }); + // An inactive tab panel is marked aria-selected="false" by one tab library and hidden by the // other, so treat either as "not on screen" and the assertion holds whichever one is rendering. const isShowing = (element: HTMLElement): boolean => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.tsx b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.tsx index 001fee4b7bc..27460b21108 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.tsx @@ -25,7 +25,7 @@ import TeamMultiSelect from "@/components/common_components/team_multi_select"; import UserDropdown from "@/components/common_components/UserDropdown"; import { ActivityMetrics, processActivityData } from "@/components/activity_metrics"; import { UsageExportHeader } from "@/components/EntityUsageExport"; -import { getExportBlockedReason } from "@/components/EntityUsageExport/exportBlockedReason"; +import { getApiKeyTruncation, getExportBlockedReason } from "@/components/EntityUsageExport/exportBlockedReason"; import type { EntityType } from "@/components/EntityUsageExport/types"; import { agentDailyActivityCall, @@ -71,6 +71,8 @@ interface EntitySpendData { total_successful_requests: number; total_failed_requests: number; total_tokens: number; + api_key_limit?: number | null; + total_api_keys?: number | null; }; } @@ -160,6 +162,7 @@ const EntityUsage: React.FC = ({ }); const spendData = spendDataRaw as unknown as EntitySpendData; + const apiKeyTruncation = getApiKeyTruncation(spendData.metadata?.api_key_limit, spendData.metadata?.total_api_keys); const { data: agentSpendDataRaw, @@ -659,12 +662,18 @@ const EntityUsage: React.FC = ({ { key: "keys", label: "Key Activity", - content: , + content: ( + + ), }, { key: "endpoints", label: "Endpoint Activity", content: }, ]; - const spendFetchState = { coversRange, cancelled, failed, apiKeyTruncation: undefined }; + const spendFetchState = { coversRange, cancelled, failed, apiKeyTruncation }; return (