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 666172947d1..5bb48a78437 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
@@ -65,10 +65,19 @@ vi.mock("@/components/EntityUsageExport/EntityUsageExportModal", () => ({
}));
vi.mock("@/components/EntityUsageExport", () => ({
- UsageExportHeader: ({ filterLabel, filterSlot }: { filterLabel?: string; filterSlot?: ReactNode }) => (
+ UsageExportHeader: ({
+ filterLabel,
+ filterSlot,
+ showFilters,
+ }: {
+ filterLabel?: string;
+ filterSlot?: ReactNode;
+ showFilters?: boolean;
+ }) => (
Usage Export Header
{filterLabel}
+ {`show-filters:${showFilters === true}`}
{filterSlot}
),
@@ -739,6 +748,26 @@ describe("EntityUsage", () => {
});
});
+ it("should still request the filter when the caller's tag scope is empty", async () => {
+ render();
+
+ await waitFor(() => {
+ expect(mockTagDailyActivityCall).toHaveBeenCalled();
+ });
+
+ expect(screen.getByText("show-filters:true")).toBeInTheDocument();
+ });
+
+ it("should not request the filter while the entity list is still unresolved", async () => {
+ render();
+
+ await waitFor(() => {
+ expect(mockTagDailyActivityCall).toHaveBeenCalled();
+ });
+
+ expect(screen.getByText("show-filters:false")).toBeInTheDocument();
+ });
+
it("should display Agent Activity tab for team entity type", async () => {
render();
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 9501fa7a9a1..ef3943e5b71 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
@@ -661,7 +661,7 @@ const EntityUsage: React.FC = ({
dateValue={dateValue}
entityType={entityType}
spendData={spendData}
- showFilters={filterSlot === undefined && entityList !== null && entityList.length > 0}
+ showFilters={filterSlot === undefined && entityList !== null}
filterSlot={filterSlot}
filterLabel={getFilterLabel(entityType)}
filterPlaceholder={getFilterPlaceholder(entityType)}
diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/UsageExportHeader.test.tsx b/ui/litellm-dashboard/src/components/EntityUsageExport/UsageExportHeader.test.tsx
index 27985c3db28..6c824459c08 100644
--- a/ui/litellm-dashboard/src/components/EntityUsageExport/UsageExportHeader.test.tsx
+++ b/ui/litellm-dashboard/src/components/EntityUsageExport/UsageExportHeader.test.tsx
@@ -84,4 +84,41 @@ describe("UsageExportHeader", () => {
expect(screen.getByTestId("custom-filter")).toBeInTheDocument();
expect(screen.queryByRole("combobox")).not.toBeInTheDocument();
});
+
+ it("should keep the filter visible and disabled with an explanation when the caller has no options", () => {
+ renderWithProviders(
+ ,
+ );
+
+ expect(screen.getByText("Filter by tag")).toBeInTheDocument();
+ const input = screen.getByPlaceholderText("No tags with usage in this range");
+ expect(input).toBeDisabled();
+ expect(screen.queryByPlaceholderText("Select tag to filter...")).not.toBeInTheDocument();
+ });
+
+ it("should leave the filter enabled with its normal placeholder when options exist", () => {
+ renderWithProviders(
+ ,
+ );
+
+ const input = screen.getByPlaceholderText("Select tag to filter...");
+ expect(input).toBeEnabled();
+ expect(screen.queryByPlaceholderText("No tags with usage in this range")).not.toBeInTheDocument();
+ });
});
diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/UsageExportHeader.tsx b/ui/litellm-dashboard/src/components/EntityUsageExport/UsageExportHeader.tsx
index e694f905d8c..0d040e7c30b 100644
--- a/ui/litellm-dashboard/src/components/EntityUsageExport/UsageExportHeader.tsx
+++ b/ui/litellm-dashboard/src/components/EntityUsageExport/UsageExportHeader.tsx
@@ -54,9 +54,11 @@ const UsageExportHeader: React.FC = ({
const anchor = useComboboxAnchor();
const [isExportModalOpen, setIsExportModalOpen] = useState(false);
- const hasFilters = filterSlot != null || (showFilters && filterOptions.length > 0);
+ const hasFilters = filterSlot != null || showFilters;
const optionValues = filterOptions.map((option) => option.value);
const labelOf = (value: string) => filterOptions.find((option) => option.value === value)?.label ?? value;
+ const hasNoOptions = filterOptions.length === 0;
+ const emptyPlaceholder = `No ${entityType}s with usage in this range`;
const filterList = (
@@ -74,6 +76,7 @@ const UsageExportHeader: React.FC = ({
const builtInFilter = (
onFiltersChange?.(next)}
@@ -88,7 +91,10 @@ const UsageExportHeader: React.FC = ({
))
}
-
+
{selectedFilters.length > 0 && }
{filterList}