From 3b540f0ec28c15f07f8e1c35df805d196efd6e07 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 23 Apr 2026 07:52:55 +0000 Subject: [PATCH] feat(ui): migrate caching (cache_settings) section to shadcn - index.tsx (CacheSettings): @tremor Button/Accordion \u2192 shadcn Button/ Accordion. Added a renderField helper to dedupe the per-category map. Section h4/h5 headers use semantic foreground tokens. - CacheFieldRenderer: @tremor NumberInput/TextInput + antd Select \u2192 shadcn Input/Textarea/Select with an inline searchable embedding-model Select (Search input inside SelectContent; stopPropagation on keydown so typing in the search box doesn't fight the Select's keyboard nav). - RedisTypeSelector: @tremor Select \u2192 shadcn Select + Label. Gates: TS \u2713 | Lint \u2713 | Vitest 9/9 \u2713 | Build \u2713. Co-authored-by: yuneng-jiang --- ui/litellm-dashboard/docs/CYCLES.md | 10 + .../cache_settings/CacheFieldRenderer.tsx | 169 +++++++----- .../cache_settings/RedisTypeSelector.tsx | 35 ++- .../src/components/cache_settings/index.tsx | 240 +++++++++--------- 4 files changed, 266 insertions(+), 188 deletions(-) diff --git a/ui/litellm-dashboard/docs/CYCLES.md b/ui/litellm-dashboard/docs/CYCLES.md index b1cbf270a71..62cc4e3929f 100644 --- a/ui/litellm-dashboard/docs/CYCLES.md +++ b/ui/litellm-dashboard/docs/CYCLES.md @@ -100,6 +100,16 @@ Layer abbreviations: **TS** (tsc --noEmit), **Lint** (eslint), **Vitest** section (CostTrackingSettings/*) is pending in a follow-up commit. - Tests updated for required-field label regex matching. +## 26. Caching (caching) + +- Cycles used: 1 / 7 +- Layer outcomes per cycle: + - cycle 1: TS ✓ | Lint ✓ | Vitest ✓ (9/9) | Build ✓ | Parity ⏭ | Snap ⏭ +- Final status: **done** +- Scope: cache_settings/index.tsx (top-level CacheSettings), CacheFieldRenderer + (per-type input renderer), RedisTypeSelector. Inline searchable Select for + embedding models replaces antd Select with showSearch. + ## 24. Guardrails Monitor (guardrails-monitor) - Cycles used: 1 / 7 diff --git a/ui/litellm-dashboard/src/components/cache_settings/CacheFieldRenderer.tsx b/ui/litellm-dashboard/src/components/cache_settings/CacheFieldRenderer.tsx index eeabda23f9f..92615b4cc96 100644 --- a/ui/litellm-dashboard/src/components/cache_settings/CacheFieldRenderer.tsx +++ b/ui/litellm-dashboard/src/components/cache_settings/CacheFieldRenderer.tsx @@ -1,53 +1,83 @@ "use client"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; -import { NumberInput, TextInput } from "@tremor/react"; -import { Select } from "antd"; -import React, { useEffect, useState } from "react"; -import { fetchAvailableModels, ModelGroup } from "../playground/llm_calls/fetch_models"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Textarea } from "@/components/ui/textarea"; +import React, { useEffect, useMemo, useState } from "react"; +import { + fetchAvailableModels, + ModelGroup, +} from "../playground/llm_calls/fetch_models"; import NumericalInput from "../shared/numerical_input"; interface CacheFieldRendererProps { + // eslint-disable-next-line @typescript-eslint/no-explicit-any field: any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any currentValue: any; } -const CacheFieldRenderer: React.FC = ({ field, currentValue }) => { +const CacheFieldRenderer: React.FC = ({ + field, + currentValue, +}) => { const [modelInfo, setModelInfo] = useState([]); - const [selectedModel, setSelectedModel] = useState(currentValue || ""); + const [selectedModel, setSelectedModel] = useState( + currentValue || "", + ); + const [modelQuery, setModelQuery] = useState(""); const { accessToken } = useAuthorized(); useEffect(() => { if (!accessToken) return; - const loadModels = async () => { try { const uniqueModels = await fetchAvailableModels(accessToken); - console.log("Fetched models for selector:", uniqueModels); - - if (uniqueModels.length > 0) { - setModelInfo(uniqueModels); - } + if (uniqueModels.length > 0) setModelInfo(uniqueModels); } catch (error) { console.error("Error fetching model info:", error); } }; - loadModels(); }, [accessToken]); + const embeddingModels = useMemo( + () => + modelInfo.filter((option: ModelGroup) => option.mode === "embedding"), + [modelInfo], + ); + const filteredEmbeddingModels = useMemo( + () => + embeddingModels.filter((m) => + modelQuery + ? m.model_group.toLowerCase().includes(modelQuery.toLowerCase()) + : true, + ), + [embeddingModels, modelQuery], + ); + if (field.field_type === "Boolean") { return (
- +
- {field.field_description} + + {field.field_description} +
); @@ -56,14 +86,17 @@ const CacheFieldRenderer: React.FC = ({ field, currentV if (field.field_type === "Integer" || field.field_type === "Float") { return (
- + -

{field.field_description}

+

+ {field.field_description} +

); } @@ -71,77 +104,85 @@ const CacheFieldRenderer: React.FC = ({ field, currentV if (field.field_type === "List") { return (
- -