Skip to content

Commit c9917cb

Browse files
authored
Merge pull request #36918 from BerriAI/litellm_shadcn_modelhub_0814
refactor(ui): move the model hub and model select onto shadcn primitives
2 parents 5156bf0 + 693683c commit c9917cb

8 files changed

Lines changed: 1226 additions & 1171 deletions

File tree

tests/e2e/ui/tests/proxy-admin/teams.spec.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ test.describe("Proxy Admin - Teams", () => {
4747
// Fill Team Name — the input has id="team_alias"
4848
await dialog.locator("#team_alias").fill(uniqueAlias);
4949

50-
// Select models — the models multi-select is inside the modal
51-
// Click to open dropdown, select "All Proxy Models"
52-
await dialog.locator(".ant-select-selection-overflow").first().click();
53-
await page.locator(".ant-select-dropdown:visible").getByText("All Proxy Models").click();
50+
// Select models — the models multi-select is inside the modal. Its popup is
51+
// portaled to the body, so scope the option lookup to the page, not the dialog.
52+
await dialog.getByTestId("create-team-models-select").getByRole("combobox").click();
53+
await page.getByRole("option", { name: "All Proxy Models", exact: true }).click();
5454
await page.keyboard.press("Escape");
5555

5656
// Submit — click the submit button inside the dialog (not the header button)
@@ -191,11 +191,11 @@ test.describe("Proxy Admin - Teams", () => {
191191
const modelsSelect = page.locator("[data-testid='models-select']");
192192
await expect(modelsSelect).toBeVisible({ timeout: 10_000 });
193193

194-
const anthropicTag = modelsSelect
195-
.locator(".ant-select-selection-item")
194+
const anthropicChip = modelsSelect
195+
.locator('[data-slot="combobox-chip"]')
196196
.filter({ hasText: "fake-anthropic-claude" });
197-
await expect(anthropicTag).toBeVisible({ timeout: 5_000 });
198-
await anthropicTag.locator(".ant-select-selection-item-remove").click();
197+
await expect(anthropicChip).toBeVisible({ timeout: 5_000 });
198+
await anthropicChip.locator('[data-slot="combobox-chip-remove"]').click();
199199

200200
await page.getByRole("button", { name: "Save Changes" }).click();
201201

ui/litellm-dashboard/eslint-suppressions.json

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,21 +1772,13 @@
17721772
"src/components/GuardrailsMonitor/LogViewer.tsx": {
17731773
"no-nested-ternary": {
17741774
"count": 1
1775-
},
1776-
"no-restricted-imports": {
1777-
"count": 1
17781775
}
17791776
},
17801777
"src/components/HelpLink.test.tsx": {
17811778
"unused-imports/no-unused-imports": {
17821779
"count": 1
17831780
}
17841781
},
1785-
"src/components/ModelSelect/ModelSelect.tsx": {
1786-
"no-restricted-imports": {
1787-
"count": 1
1788-
}
1789-
},
17901782
"src/components/Navbar/BlogDropdown/BlogDropdown.test.tsx": {
17911783
"max-nested-callbacks": {
17921784
"count": 12
@@ -2239,9 +2231,6 @@
22392231
}
22402232
},
22412233
"src/components/claude_code_plugins/MakeSkillPublicForm.tsx": {
2242-
"no-restricted-imports": {
2243-
"count": 2
2244-
},
22452234
"react-hooks/set-state-in-effect": {
22462235
"count": 1
22472236
}
@@ -2760,9 +2749,6 @@
27602749
},
27612750
"max-lines": {
27622751
"count": 1
2763-
},
2764-
"no-restricted-imports": {
2765-
"count": 2
27662752
}
27672753
},
27682754
"src/components/query_param_input.tsx": {

ui/litellm-dashboard/src/components/GuardrailsMonitor/LogViewer.tsx

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { CheckCircleOutlined, CloseOutlined, DownOutlined, WarningOutlined } from "@ant-design/icons";
1+
import { CircleCheck, ChevronDown, TriangleAlert, X } from "lucide-react";
22
import { useQuery } from "@tanstack/react-query";
33
import moment from "moment";
4-
import { Button, Spin } from "antd";
54
import React, { useState } from "react";
5+
import { Button } from "@/components/ui/button";
6+
import { UiLoadingSpinner } from "@/components/ui/ui-loading-spinner";
67
import { uiSpendLogsCall } from "@/components/networking";
78
import { LogDetailsDrawer } from "@/components/view_logs/LogDetailsDrawer";
89
import type { LogEntry as ViewLogsLogEntry } from "@/components/view_logs/columns";
@@ -13,21 +14,21 @@ const actionConfig: Record<
1314
{ icon: React.ElementType; color: string; bg: string; border: string; label: string }
1415
> = {
1516
blocked: {
16-
icon: CloseOutlined,
17+
icon: X,
1718
color: "text-red-600",
1819
bg: "bg-red-50",
1920
border: "border-red-200",
2021
label: "Blocked",
2122
},
2223
passed: {
23-
icon: CheckCircleOutlined,
24+
icon: CircleCheck,
2425
color: "text-green-600",
2526
bg: "bg-green-50",
2627
border: "border-green-200",
2728
label: "Passed",
2829
},
2930
flagged: {
30-
icon: WarningOutlined,
31+
icon: TriangleAlert,
3132
color: "text-amber-600",
3233
bg: "bg-amber-50",
3334
border: "border-amber-200",
@@ -125,8 +126,8 @@ export function LogViewer({
125126
{filters.map((f) => (
126127
<Button
127128
key={f}
128-
type={activeFilter === f ? "primary" : "default"}
129-
size="small"
129+
variant={activeFilter === f ? "default" : "outline"}
130+
size="sm"
130131
onClick={() => setActiveFilter(f)}
131132
>
132133
{f.charAt(0).toUpperCase() + f.slice(1)}
@@ -139,8 +140,8 @@ export function LogViewer({
139140
{sampleSizes.map((size) => (
140141
<Button
141142
key={size}
142-
type={sampleSize === size ? "primary" : "default"}
143-
size="small"
143+
variant={sampleSize === size ? "default" : "outline"}
144+
size="sm"
144145
onClick={() => setSampleSize(size)}
145146
>
146147
{size}
@@ -154,7 +155,7 @@ export function LogViewer({
154155

155156
{logsLoading && (
156157
<div className="flex items-center justify-center py-12">
157-
<Spin />
158+
<UiLoadingSpinner className="size-5" />
158159
</div>
159160
)}
160161
{!logsLoading && displayLogs.length === 0 && (
@@ -182,11 +183,11 @@ export function LogViewer({
182183
</span>
183184
<span className="text-xs text-gray-400">{log.timestamp}</span>
184185
<span className="text-xs text-gray-400">·</span>
185-
{log.model && <span className="text-xs text-gray-500">{log.model}</span>}
186+
{log.model && <span className="min-w-0 text-xs break-words text-gray-500">{log.model}</span>}
186187
</div>
187188
<p className="text-sm text-gray-800 truncate">{log.input_snippet ?? log.input ?? "—"}</p>
188189
</div>
189-
<DownOutlined className="w-4 h-4 text-gray-400 shrink-0 mt-1" />
190+
<ChevronDown className="w-4 h-4 text-gray-400 shrink-0 mt-1" />
190191
</button>
191192
);
192193
})}

0 commit comments

Comments
 (0)