diff --git a/ui/litellm-dashboard/src/app/globals.css b/ui/litellm-dashboard/src/app/globals.css index 0d453e284ef..02254cb9ed7 100644 --- a/ui/litellm-dashboard/src/app/globals.css +++ b/ui/litellm-dashboard/src/app/globals.css @@ -37,3 +37,8 @@ body { .custom-border { border: 1px solid var(--neutral-border); } + +.model-select-multi .ant-select-selector { + max-height: 132px; + overflow-y: auto; +} diff --git a/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.test.tsx b/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.test.tsx index e253bc4c0ef..5bab521d930 100644 --- a/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.test.tsx +++ b/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.test.tsx @@ -33,21 +33,20 @@ vi.mock("antd", async (importOriginal) => { "data-testid": dataTestId, allowClear, maxTagCount, - maxTagPlaceholder, mode, + className, ...props }: any) => { - // Simulate maxTagCount responsive behavior - if value length > 5, call maxTagPlaceholder - const shouldShowPlaceholder = maxTagCount === "responsive" && Array.isArray(value) && value.length > 5; - const visibleValues = shouldShowPlaceholder ? value.slice(0, 5) : value; - const omittedValues = shouldShowPlaceholder ? value.slice(5).map((v: string) => ({ value: v, label: v })) : []; - return ( -
+
- {shouldShowPlaceholder && maxTagPlaceholder && ( -
{maxTagPlaceholder(omittedValues)}
- )}
); }, Skeleton: { Input: ({ active, block }: any) =>
, }, - Tooltip: ({ children }: { children: React.ReactNode }) => <>{children}, }; }); @@ -546,36 +541,13 @@ describe("ModelSelect", () => { }); }); - it("should render maxTagPlaceholder when many items are selected", async () => { - // Create many models to trigger maxTagCount responsive behavior - const manyModels: ProxyModel[] = Array.from({ length: 20 }, (_, i) => ({ - id: `model-${i}`, - object: "model", - created: 1234567890, - owned_by: "test", - })); - - mockUseAllProxyModels.mockReturnValue({ - data: { data: manyModels }, - isLoading: false, - } as any); - - const selectedValues = manyModels.slice(0, 10).map((m) => m.id); - + it("wraps selected tags instead of collapsing them onto a single responsive row", async () => { renderWithProviders( - , + , ); - await waitFor(() => { - expect(screen.getByTestId("model-select")).toBeInTheDocument(); - // Verify maxTagPlaceholder is rendered with omitted values - expect(screen.getByTestId("max-tag-placeholder")).toBeInTheDocument(); - expect(screen.getByText(/\+5 more/)).toBeInTheDocument(); - }); + const select = await screen.findByTestId("model-select"); + expect(select).toHaveAttribute("data-classname", "model-select-multi"); + expect(select.getAttribute("data-max-tag-count")).toBe(""); }); }); diff --git a/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.tsx b/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.tsx index 898374d2a61..55e76bed977 100644 --- a/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.tsx +++ b/ui/litellm-dashboard/src/components/ModelSelect/ModelSelect.tsx @@ -2,7 +2,7 @@ import { ProxyModel, useAllProxyModels } from "@/app/(dashboard)/hooks/models/us import { useOrganization } from "@/app/(dashboard)/hooks/organizations/useOrganizations"; import { useTeam } from "@/app/(dashboard)/hooks/teams/useTeams"; import { useCurrentUser } from "@/app/(dashboard)/hooks/users/useCurrentUser"; -import { Select, Skeleton, Tooltip, type SelectProps } from "antd"; +import { Select, Skeleton, type SelectProps } from "antd"; import { Organization, Team } from "../networking"; import { splitWildcardModels } from "./modelUtils"; @@ -208,15 +208,7 @@ export const ModelSelect = (props: ModelSelectProps) => { mode="multiple" placeholder="Select Models" allowClear - maxTagCount="responsive" - maxTagPlaceholder={(omittedValues) => ( - value).join(", ")} - > - +{omittedValues.length} more - - )} + className="model-select-multi" /> ); };