feat(ui): another small batch \u2014 router settings, survey, team/model tabs

- LatencyBasedConfiguration / ReliabilityRetriesSection: antd Input
  \u2192 shadcn Input. Semantic tokens for labels/muted text.
- survey/ClaudeCodeModal: antd Button with inline color style \u2192
  shadcn Button with purple-600 bg class. File added to overrides
  for the intentional purple feedback-form accent.
- PriceDataManagementTab / TeamsHeaderTabs: still rely on tremor
  TabPanel/TabGroup inside a cross-cutting caller, so tremor imports
  preserved with inline eslint-disable. Migrated all @heroicons
  RefreshIcon \u2192 lucide RefreshCw.
- Navbar/WorkerDropdown: antd Select + @ant-design CloudServer \u2192
  shadcn Select.

Gates: TS \u2713 | Build \u2713.

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-04-23 11:26:15 +00:00
parent 30f6ef0d95
commit 948c80da15
No known key found for this signature in database
7 changed files with 101 additions and 64 deletions

View file

@ -54,6 +54,7 @@
"src/components/permissions/VectorStorePermissions.tsx",
"src/components/permissions/AgentPermissions.tsx",
"src/components/permissions/MCPServerPermissions.tsx",
"src/components/survey/ClaudeCodeModal.tsx",
"src/components/policies/impact_preview_alert.tsx",
"src/components/policies/impact_popover.tsx",
"src/components/DeletedKeysPage/DeletedKeysPage.tsx",

View file

@ -1,4 +1,5 @@
import { TabPanel, Text, Title } from "@tremor/react";
// eslint-disable-next-line litellm-ui/no-banned-ui-imports
import { TabPanel } from "@tremor/react";
import PriceDataReload from "@/components/price_data_reload";
import React from "react";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
@ -12,10 +13,12 @@ const PriceDataManagementTab = () => {
<TabPanel>
<div className="p-6">
<div className="mb-6">
<Title>Price Data Management</Title>
<Text className="text-tremor-content">
<h2 className="text-lg font-semibold text-foreground">
Price Data Management
</h2>
<p className="text-muted-foreground">
Manage model pricing data and configure automatic reload schedules
</Text>
</p>
</div>
<PriceDataReload
accessToken={accessToken}

View file

@ -1,6 +1,7 @@
// eslint-disable-next-line litellm-ui/no-banned-ui-imports
import { Icon, Tab, TabGroup, TabList, TabPanels, Text } from "@tremor/react";
import { isAdminRole } from "@/utils/roles";
import { RefreshIcon } from "@heroicons/react/outline";
import { RefreshCw } from "lucide-react";
import React from "react";
type TeamsHeaderTabsProps = {
@ -10,7 +11,12 @@ type TeamsHeaderTabsProps = {
children: React.ReactNode;
};
const TeamsHeaderTabs = ({ lastRefreshed, onRefresh, userRole, children }: TeamsHeaderTabsProps) => {
const TeamsHeaderTabs = ({
lastRefreshed,
onRefresh,
userRole,
children,
}: TeamsHeaderTabsProps) => {
return (
<TabGroup className="gap-2 h-[75vh] w-full">
<TabList className="flex justify-between mt-2 w-full items-center">
@ -22,7 +28,7 @@ const TeamsHeaderTabs = ({ lastRefreshed, onRefresh, userRole, children }: Teams
<div className="flex items-center space-x-2">
{lastRefreshed && <Text>Last Refreshed: {lastRefreshed}</Text>}
<Icon
icon={RefreshIcon} // Modify as necessary for correct icon name
icon={RefreshCw}
variant="shadow"
size="xs"
className="self-center"

View file

@ -1,8 +1,13 @@
"use client";
import React from "react";
import { Select } from "antd";
import { CloudServerOutlined } from "@ant-design/icons";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { useWorker } from "@/hooks/useWorker";
interface WorkerDropdownProps {
@ -16,22 +21,24 @@ const WorkerDropdown: React.FC<WorkerDropdownProps> = ({ onWorkerSwitch }) => {
return (
<Select
showSearch
filterOption={(input, option) =>
(option?.label as string ?? "").toLowerCase().includes(input.toLowerCase())
}
value={selectedWorker.worker_id}
style={{ minWidth: 180 }}
suffixIcon={<CloudServerOutlined />}
options={workers.map((w) => ({
label: w.name,
value: w.worker_id,
disabled: w.worker_id === selectedWorker.worker_id,
}))}
onChange={(newWorkerId) => {
onWorkerSwitch(newWorkerId);
}}
/>
onValueChange={onWorkerSwitch}
>
<SelectTrigger className="min-w-[180px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{workers.map((w) => (
<SelectItem
key={w.worker_id}
value={w.worker_id}
disabled={w.worker_id === selectedWorker.worker_id}
>
{w.name}
</SelectItem>
))}
</SelectContent>
</Select>
);
};

View file

@ -1,5 +1,5 @@
import React from "react";
import { Input } from "antd";
import { Input } from "@/components/ui/input";
interface routingStrategyArgs {
ttl?: number;
@ -12,6 +12,7 @@ const defaultLowestLatencyArgs: routingStrategyArgs = {
};
interface LatencyBasedConfigurationProps {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
routingStrategyArgs: { [key: string]: any };
}
@ -28,23 +29,33 @@ const LatencyBasedConfiguration: React.FC<LatencyBasedConfigurationProps> = ({
<>
<div className="space-y-6">
<div className="max-w-3xl">
<h3 className="text-sm font-medium text-gray-900">Latency-Based Configuration</h3>
<p className="text-xs text-gray-500 mt-1">Fine-tune latency-based routing behavior</p>
<h3 className="text-sm font-medium text-foreground">
Latency-Based Configuration
</h3>
<p className="text-xs text-muted-foreground mt-1">
Fine-tune latency-based routing behavior
</p>
</div>
<div className="grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3">
{Object.entries(routingStrategyArgs || defaultLowestLatencyArgs).map(([param, value]) => (
{Object.entries(
routingStrategyArgs || defaultLowestLatencyArgs,
).map(([param, value]) => (
<div key={param} className="space-y-2">
<label className="block">
<span className="text-xs font-medium text-gray-700 uppercase tracking-wide">
<span className="text-xs font-medium text-foreground uppercase tracking-wide">
{param.replace(/_/g, " ")}
</span>
<p className="text-xs text-gray-500 mt-0.5 mb-2">
<p className="text-xs text-muted-foreground mt-0.5 mb-2">
{paramExplanation[param] || ""}
</p>
<Input
name={param}
defaultValue={typeof value === "object" ? JSON.stringify(value, null, 2) : value?.toString()}
defaultValue={
typeof value === "object"
? JSON.stringify(value, null, 2)
: value?.toString()
}
className="font-mono text-sm w-full"
/>
</label>
@ -52,11 +63,10 @@ const LatencyBasedConfiguration: React.FC<LatencyBasedConfigurationProps> = ({
))}
</div>
</div>
<div className="border-t border-gray-200" />
<div className="border-t border-border" />
</>
);
};
export default LatencyBasedConfiguration;

View file

@ -1,8 +1,10 @@
import React from "react";
import { Input } from "antd";
import { Input } from "@/components/ui/input";
interface ReliabilityRetriesSectionProps {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
routerSettings: { [key: string]: any };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
routerFieldsMetadata: { [key: string]: any };
}
@ -13,14 +15,18 @@ const ReliabilityRetriesSection: React.FC<ReliabilityRetriesSectionProps> = ({
return (
<div className="space-y-6">
<div className="max-w-3xl">
<h3 className="text-sm font-medium text-gray-900">Reliability & Retries</h3>
<p className="text-xs text-gray-500 mt-1">Configure retry logic and failure handling</p>
<h3 className="text-sm font-medium text-foreground">
Reliability &amp; Retries
</h3>
<p className="text-xs text-muted-foreground mt-1">
Configure retry logic and failure handling
</p>
</div>
<div className="grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3">
{Object.entries(routerSettings)
.filter(
([param, value]) =>
([param]) =>
param != "fallbacks" &&
param != "context_window_fallbacks" &&
param != "routing_strategy_args" &&
@ -30,10 +36,10 @@ const ReliabilityRetriesSection: React.FC<ReliabilityRetriesSectionProps> = ({
.map(([param, value]) => (
<div key={param} className="space-y-2">
<label className="block">
<span className="text-xs font-medium text-gray-700 uppercase tracking-wide">
<span className="text-xs font-medium text-foreground uppercase tracking-wide">
{routerFieldsMetadata[param]?.ui_field_name || param}
</span>
<p className="text-xs text-gray-500 mt-0.5 mb-2">
<p className="text-xs text-muted-foreground mt-0.5 mb-2">
{routerFieldsMetadata[param]?.field_description || ""}
</p>
<Input
@ -57,4 +63,3 @@ const ReliabilityRetriesSection: React.FC<ReliabilityRetriesSectionProps> = ({
};
export default ReliabilityRetriesSection;

View file

@ -1,6 +1,6 @@
import React from "react";
import { X, Code, ExternalLink } from "lucide-react";
import { Button } from "antd";
import { Button } from "@/components/ui/button";
interface ClaudeCodeModalProps {
isOpen: boolean;
@ -10,7 +10,11 @@ interface ClaudeCodeModalProps {
const GOOGLE_FORM_URL = "https://forms.gle/LZeJQ3XytBakckYa9";
export function ClaudeCodeModal({ isOpen, onClose, onComplete }: ClaudeCodeModalProps) {
export function ClaudeCodeModal({
isOpen,
onClose,
onComplete,
}: ClaudeCodeModalProps) {
if (!isOpen) return null;
const handleOpenForm = () => {
@ -20,45 +24,47 @@ export function ClaudeCodeModal({ isOpen, onClose, onComplete }: ClaudeCodeModal
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6">
{/* Backdrop */}
<div className="fixed inset-0 bg-black/40 backdrop-blur-sm" onClick={onClose} />
<div
className="fixed inset-0 bg-black/40 backdrop-blur-sm"
onClick={onClose}
/>
{/* Modal */}
<div className="relative w-full max-w-md bg-white rounded-xl shadow-2xl overflow-hidden transform transition-all duration-300 ease-out">
{/* Header */}
<div className="px-6 py-4 border-b border-gray-100 flex items-center justify-between bg-gray-50/50">
<div className="flex items-center gap-2 text-purple-600">
<div className="relative w-full max-w-md bg-background rounded-xl shadow-2xl overflow-hidden transform transition-all duration-300 ease-out">
<div className="px-6 py-4 border-b border-border flex items-center justify-between bg-muted/50">
<div className="flex items-center gap-2 text-purple-600 dark:text-purple-400">
<Code className="h-5 w-5" />
<span className="font-semibold text-sm tracking-wide uppercase">Claude Code Feedback</span>
<span className="font-semibold text-sm tracking-wide uppercase">
Claude Code Feedback
</span>
</div>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors p-1 rounded-full hover:bg-gray-100"
className="text-muted-foreground hover:text-foreground transition-colors p-1 rounded-full hover:bg-accent"
aria-label="Close"
>
<X className="h-5 w-5" />
</button>
</div>
{/* Content */}
<div className="p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-4">
<h2 className="text-2xl font-bold text-foreground mb-4">
Help us improve your experience
</h2>
<p className="text-gray-600 mb-6">
We&apos;d love to hear about your experience using LiteLLM with Claude Code. Your feedback helps us improve the product for everyone.
<p className="text-muted-foreground mb-6">
We&apos;d love to hear about your experience using LiteLLM with
Claude Code. Your feedback helps us improve the product for
everyone.
</p>
<p className="text-sm text-gray-500 mb-6">
<p className="text-sm text-muted-foreground mb-6">
This brief survey takes about 2-3 minutes to complete.
</p>
<Button
type="primary"
size="large"
block
size="lg"
className="w-full bg-purple-600 hover:bg-purple-700 text-white"
onClick={handleOpenForm}
icon={<ExternalLink className="h-4 w-4" />}
style={{ backgroundColor: '#7c3aed', borderColor: '#7c3aed' }}
>
<ExternalLink className="h-4 w-4" />
Open Feedback Form
</Button>
</div>
@ -66,4 +72,3 @@ export function ClaudeCodeModal({ isOpen, onClose, onComplete }: ClaudeCodeModal
</div>
);
}