From c4ee14304b06042b5772f24fee5eeacb81953fab Mon Sep 17 00:00:00 2001 From: ryan-crabbe-berri Date: Fri, 12 Jun 2026 20:04:49 -0700 Subject: [PATCH] chore(ui): remove dead UI components unreferenced by any page These components are not reachable from any page: WebRTCTester, the agents agent_card/agent_card_grid pair (the agents route renders a Table directly), and view_logs ErrorViewer/RequestResponsePanel (logs uses inline equivalents in columns.tsx). Each was imported only by its own test, so the tests go too. Also drops the now-stale agent_card_grid vi.mock in agents.test.tsx and the WebRTCTester eslint-suppressions entry. --- ui/litellm-dashboard/eslint-suppressions.json | 8 - .../src/components/WebRTCTester.jsx | 648 ------------------ .../src/components/agents.test.tsx | 6 - .../src/components/agents/agent_card.test.tsx | 95 --- .../src/components/agents/agent_card.tsx | 88 --- .../agents/agent_card_grid.test.tsx | 80 --- .../src/components/agents/agent_card_grid.tsx | 67 -- .../components/view_logs/ErrorViewer.test.tsx | 85 --- .../src/components/view_logs/ErrorViewer.tsx | 180 ----- .../view_logs/RequestResponsePanel.test.tsx | 267 -------- .../view_logs/RequestResponsePanel.tsx | 146 ---- 11 files changed, 1670 deletions(-) delete mode 100644 ui/litellm-dashboard/src/components/WebRTCTester.jsx delete mode 100644 ui/litellm-dashboard/src/components/agents/agent_card.test.tsx delete mode 100644 ui/litellm-dashboard/src/components/agents/agent_card.tsx delete mode 100644 ui/litellm-dashboard/src/components/agents/agent_card_grid.test.tsx delete mode 100644 ui/litellm-dashboard/src/components/agents/agent_card_grid.tsx delete mode 100644 ui/litellm-dashboard/src/components/view_logs/ErrorViewer.test.tsx delete mode 100644 ui/litellm-dashboard/src/components/view_logs/ErrorViewer.tsx delete mode 100644 ui/litellm-dashboard/src/components/view_logs/RequestResponsePanel.test.tsx delete mode 100644 ui/litellm-dashboard/src/components/view_logs/RequestResponsePanel.tsx diff --git a/ui/litellm-dashboard/eslint-suppressions.json b/ui/litellm-dashboard/eslint-suppressions.json index 369efb7e338a..7820750cee3f 100644 --- a/ui/litellm-dashboard/eslint-suppressions.json +++ b/ui/litellm-dashboard/eslint-suppressions.json @@ -678,14 +678,6 @@ "count": 1 } }, - "src/components/WebRTCTester.jsx": { - "no-restricted-syntax": { - "count": 2 - }, - "react/no-unescaped-entities": { - "count": 2 - } - }, "src/components/activity_metrics.tsx": { "no-restricted-imports": { "count": 1 diff --git a/ui/litellm-dashboard/src/components/WebRTCTester.jsx b/ui/litellm-dashboard/src/components/WebRTCTester.jsx deleted file mode 100644 index 75e331f6586a..000000000000 --- a/ui/litellm-dashboard/src/components/WebRTCTester.jsx +++ /dev/null @@ -1,648 +0,0 @@ -import { useState, useRef, useEffect, useCallback } from "react"; - -const STYLES = ` -.wrt-wrap { - font-family: 'JetBrains Mono', 'Fira Code', monospace; - background: #0d0d14; - border: 1px solid #1e1e2e; - border-radius: 10px; - overflow: hidden; - margin: 24px 0; -} - -.wrt-toggle { - display: flex; - align-items: center; - justify-content: space-between; - padding: 14px 20px; - cursor: pointer; - user-select: none; - background: #0d0d14; - transition: background 0.15s; -} -.wrt-toggle:hover { background: #111120; } - -.wrt-toggle-left { display: flex; align-items: center; gap: 10px; } - -.wrt-live-dot { - width: 8px; height: 8px; border-radius: 50%; - background: #00ff88; - box-shadow: 0 0 8px #00ff88; - animation: wrt-blink 2s infinite; -} -@keyframes wrt-blink { 0%,100%{opacity:1} 50%{opacity:0.4} } - -.wrt-toggle-title { font-size: 12px; font-weight: 600; color: #e2e8f0; letter-spacing: 0.06em; } -.wrt-toggle-sub { font-size: 10px; color: #4a5568; margin-top: 1px; } -.wrt-chevron { font-size: 11px; color: #4a5568; transition: transform 0.2s; } -.wrt-chevron.open { transform: rotate(180deg); } - -.wrt-body { - border-top: 1px solid #1e1e2e; - display: grid; - grid-template-columns: 280px 1fr; - height: 460px; -} - -.wrt-sidebar { - border-right: 1px solid #1e1e2e; - padding: 14px; - display: flex; - flex-direction: column; - gap: 12px; - overflow-y: auto; -} - -.wrt-label { - font-size: 9px; - letter-spacing: 0.15em; - color: #4a5568; - text-transform: uppercase; - margin-bottom: 5px; -} - -.wrt-field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 6px; } -.wrt-field label { font-size: 10px; color: #4a5568; } -.wrt-field input { - background: #0a0a0f; - border: 1px solid #1e1e2e; - border-radius: 5px; - color: #e2e8f0; - font-family: inherit; - font-size: 11px; - padding: 7px 9px; - outline: none; - width: 100%; - transition: border-color 0.2s; -} -.wrt-field input:focus { border-color: #7c3aed; } - -.wrt-divider { height: 1px; background: #1e1e2e; } - -.wrt-btn { - display: flex; align-items: center; justify-content: center; - border: none; border-radius: 5px; cursor: pointer; - font-family: inherit; font-size: 11px; font-weight: 600; - padding: 8px; width: 100%; - transition: all 0.15s; letter-spacing: 0.04em; -} -.wrt-btn + .wrt-btn { margin-top: 5px; } -.wrt-btn-primary { background: #00ff88; color: #000; } -.wrt-btn-primary:hover:not(:disabled) { filter: brightness(1.1); } -.wrt-btn-primary:disabled { opacity: 0.35; cursor: not-allowed; } -.wrt-btn-danger { background: transparent; color: #ff4466; border: 1px solid #ff4466; } -.wrt-btn-danger:hover:not(:disabled) { background: rgba(255,68,102,0.08); } -.wrt-btn-danger:disabled { opacity: 0.3; cursor: not-allowed; } -.wrt-btn-ghost { background: #111118; color: #e2e8f0; border: 1px solid #1e1e2e; } -.wrt-btn-ghost:hover { border-color: #7c3aed; } - -.wrt-flow { display: flex; align-items: center; padding: 4px 0; gap: 0; } -.wrt-flow-box { - padding: 4px 7px; border-radius: 4px; font-size: 9px; - border: 1px solid #1e1e2e; color: #4a5568; - transition: all 0.3s; white-space: nowrap; -} -.wrt-flow-box.active { border-color: #00ff88; color: #00ff88; box-shadow: 0 0 8px rgba(0,255,136,0.15); } -.wrt-flow-arrow { font-size: 10px; color: #4a5568; padding: 0 4px; transition: color 0.3s; } -.wrt-flow-arrow.active { color: #00ff88; } - -.wrt-meta { display: flex; flex-direction: column; gap: 4px; } -.wrt-meta-row { display: flex; justify-content: space-between; font-size: 10px; } -.wrt-meta-row span:first-child { color: #4a5568; } -.wrt-meta-row span:last-child { color: #e2e8f0; } - -.wrt-status-pill { - display: flex; align-items: center; gap: 6px; - font-size: 10px; color: #4a5568; - background: #111118; border: 1px solid #1e1e2e; - border-radius: 100px; padding: 3px 10px; -} -.wrt-status-dot { - width: 6px; height: 6px; border-radius: 50%; - background: #4a5568; transition: all 0.3s; -} -.wrt-status-dot.connected { background: #00ff88; box-shadow: 0 0 6px #00ff88; } -.wrt-status-dot.connecting { background: #ffaa00; animation: wrt-blink 1s infinite; } -.wrt-status-dot.error { background: #ff4466; } - -.wrt-main { display: flex; flex-direction: column; overflow: hidden; } - -.wrt-header { - display: flex; align-items: center; justify-content: space-between; - padding: 8px 14px; border-bottom: 1px solid #1e1e2e; background: #111118; -} -.wrt-header-title { font-size: 10px; color: #4a5568; letter-spacing: 0.08em; } - -.wrt-tabs { display: flex; padding: 0 14px; border-bottom: 1px solid #1e1e2e; } -.wrt-tab { - font-size: 9px; letter-spacing: 0.08em; padding: 10px 12px; cursor: pointer; - color: #4a5568; border-bottom: 2px solid transparent; transition: all 0.15s; - user-select: none; -} -.wrt-tab.active { color: #00ff88; border-bottom-color: #00ff88; } -.wrt-tab:hover:not(.active) { color: #e2e8f0; } - -.wrt-tab-content { flex: 1; overflow: hidden; display: none; flex-direction: column; } -.wrt-tab-content.active { display: flex; } - -.wrt-log { - flex: 1; overflow-y: auto; padding: 8px 12px; - display: flex; flex-direction: column; gap: 2px; -} -.wrt-log::-webkit-scrollbar { width: 3px; } -.wrt-log::-webkit-scrollbar-thumb { background: #1e1e2e; border-radius: 2px; } - -.wrt-entry { - display: grid; grid-template-columns: 58px 56px 1fr; gap: 8px; - padding: 3px 7px; border-radius: 3px; - border-left: 2px solid transparent; - font-size: 10px; line-height: 1.5; - animation: wrt-fadein 0.15s ease; -} -@keyframes wrt-fadein { from { opacity:0; transform:translateY(2px); } to { opacity:1; transform:none; } } - -.wrt-entry.info { border-left-color: #7c3aed; } -.wrt-entry.info .we-tag { color: #7c3aed; } -.wrt-entry.success { border-left-color: #00ff88; } -.wrt-entry.success .we-tag { color: #00ff88; } -.wrt-entry.error { border-left-color: #ff4466; } -.wrt-entry.error .we-tag { color: #ff4466; } -.wrt-entry.warn { border-left-color: #ffaa00; } -.wrt-entry.warn .we-tag { color: #ffaa00; } -.wrt-entry.step { border-left-color: #60a5fa; } -.wrt-entry.step .we-tag { color: #60a5fa; } - -.we-time { color: #4a5568; font-size: 9px; padding-top: 1px; } -.we-tag { font-size: 9px; font-weight: 700; padding-top: 1px; } -.we-msg { color: #e2e8f0; word-break: break-all; white-space: pre-wrap; } - -.wrt-empty { - display: flex; flex-direction: column; align-items: center; justify-content: center; - flex: 1; gap: 6px; color: #4a5568; font-size: 11px; -} - -.wrt-sdp-pane { flex: 1; display: grid; grid-template-columns: 1fr 1fr; overflow: hidden; } -.wrt-sdp-box { display: flex; flex-direction: column; border-right: 1px solid #1e1e2e; overflow: hidden; } -.wrt-sdp-box:last-child { border-right: none; } -.wrt-sdp-hdr { - padding: 7px 12px; border-bottom: 1px solid #1e1e2e; - font-size: 9px; color: #4a5568; letter-spacing: 0.08em; - display: flex; align-items: center; gap: 6px; -} -.wrt-sdp-dot { width: 5px; height: 5px; border-radius: 50%; background: #1e1e2e; } -.wrt-sdp-dot.active { background: #00ff88; } -.wrt-sdp-pane textarea { - flex: 1; background: transparent; border: none; color: #e2e8f0; - font-family: inherit; font-size: 10px; padding: 10px 12px; - resize: none; outline: none; line-height: 1.5; -} - -.wrt-audio-pane { - flex: 1; display: flex; flex-direction: column; - align-items: center; justify-content: center; gap: 14px; -} -.wrt-viz { display: flex; align-items: center; gap: 2px; height: 44px; } -.wrt-bar { width: 3px; border-radius: 2px; min-height: 2px; background: #00ff88; transition: height 0.05s; } -.wrt-mic-btn { - width: 52px; height: 52px; border-radius: 50%; - background: #111118; border: 1.5px solid #1e1e2e; - font-size: 18px; cursor: pointer; - display: flex; align-items: center; justify-content: center; transition: all 0.2s; -} -.wrt-mic-btn.active { border-color: #00ff88; box-shadow: 0 0 16px rgba(0,255,136,0.2); } -.wrt-audio-status { font-size: 10px; color: #4a5568; text-align: center; } -`; - -function useLog() { - const [entries, setEntries] = useState([]); - const add = useCallback((level, tag, msg) => { - const time = new Date().toTimeString().slice(0, 8); - setEntries((prev) => [...prev, { level, tag, msg, time, id: Date.now() + Math.random() }]); - }, []); - const clear = useCallback(() => setEntries([]), []); - return { entries, add, clear }; -} - -export default function WebRTCTester() { - const [open, setOpen] = useState(false); - const [activeTab, setActiveTab] = useState("logs"); - const [proxyUrl, setProxyUrl] = useState("http://localhost:4000"); - const [apiKey, setApiKey] = useState("sk-1234"); - const [model, setModel] = useState("gpt-4o-realtime-preview"); - const [status, setStatus] = useState("idle"); - const [flowStep, setFlowStep] = useState(0); - const [tokenPreview, setTokenPreview] = useState("—"); - const [iceState, setIceState] = useState("—"); - const [connState, setConnState] = useState("—"); - const [dcState, setDcState] = useState("—"); - const [sdpOffer, setSdpOffer] = useState(""); - const [sdpAnswer, setSdpAnswer] = useState(""); - const [offerActive, setOfferActive] = useState(false); - const [answerActive, setAnswerActive] = useState(false); - const [audioStatus, setAudioStatus] = useState("Start a session first"); - const [micActive, setMicActive] = useState(false); - const [bars, setBars] = useState(Array(28).fill(2)); - const [connected, setConnected] = useState(false); - - const { entries, add: log, clear: clearLogs } = useLog(); - const logRef = useRef(null); - - const pcRef = useRef(null); - const dcRef = useRef(null); - const streamRef = useRef(null); - const audioCtxRef = useRef(null); - const analyserRef = useRef(null); - const animRef = useRef(null); - const tokenRef = useRef(null); - const micRef = useRef(false); - const remoteAudioRef = useRef(null); - - useEffect(() => { - if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight; - }, [entries]); - - function drawBars() { - animRef.current = requestAnimationFrame(drawBars); - if (!analyserRef.current) return; - const data = new Uint8Array(analyserRef.current.frequencyBinCount); - analyserRef.current.getByteFrequencyData(data); - setBars(Array.from({ length: 28 }, (_, i) => Math.max(2, ((data[i] || 0) / 255) * 42))); - } - - function setupAnalyser(stream) { - audioCtxRef.current = new AudioContext(); - const src = audioCtxRef.current.createMediaStreamSource(stream); - analyserRef.current = audioCtxRef.current.createAnalyser(); - analyserRef.current.fftSize = 64; - src.connect(analyserRef.current); - drawBars(); - } - - async function startSession() { - const url = proxyUrl.trim().replace(/\/$/, ""); - const key = apiKey.trim(); - const mdl = model.trim(); - - setConnected(true); - setStatus("connecting"); - setFlowStep(1); - - // Step 1: ephemeral token - log("step", "STEP 1", `POST ${url}/v1/realtime/client_secrets`); - let tokenResp; - try { - const r = await fetch(`${url}/v1/realtime/client_secrets`, { - method: "POST", - headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` }, - body: JSON.stringify({ model: mdl }), - }); - log("info", "HTTP", `${r.status} ${r.statusText}`); - const raw = await r.text(); - if (!r.ok) { - log("error", "ERR", raw); - stopSession(); - return; - } - tokenResp = JSON.parse(raw); - log("success", "TOKEN", "Received encrypted ephemeral token"); - } catch (e) { - log("error", "ERR", `client_secrets failed: ${e.message}`); - stopSession(); - return; - } - - const token = tokenResp?.client_secret?.value ?? tokenResp?.value; - if (!token) { - log("error", "ERR", `Cannot extract token: ${JSON.stringify(tokenResp)}`); - stopSession(); - return; - } - tokenRef.current = token; - setTokenPreview(token.slice(0, 10) + "…"); - log("info", "TOKEN", `Preview: ${token.slice(0, 10)}…`); - - // Step 2: PeerConnection - log("step", "STEP 2", "Creating RTCPeerConnection"); - const pc = new RTCPeerConnection(); - pcRef.current = pc; - - pc.oniceconnectionstatechange = () => { - setIceState(pc.iceConnectionState); - log("info", "ICE", pc.iceConnectionState); - if (pc.iceConnectionState === "connected" || pc.iceConnectionState === "completed") { - setStatus("connected"); - setFlowStep(3); - } - if (pc.iceConnectionState === "failed" || pc.iceConnectionState === "disconnected") { - setStatus("error"); - } - }; - - pc.onconnectionstatechange = () => { - setConnState(pc.connectionState); - log("info", "CONN", pc.connectionState); - }; - - pc.ontrack = (e) => { - log("success", "AUDIO", "Remote audio track received from OpenAI"); - if (remoteAudioRef.current) remoteAudioRef.current.srcObject = e.streams[0]; - setupAnalyser(e.streams[0]); - setAudioStatus("Receiving audio from OpenAI ✓"); - }; - - const dc = pc.createDataChannel("oai-events"); - dcRef.current = dc; - dc.onopen = () => { - setDcState("open"); - log("success", "DC", "Data channel open — ready!"); - setStatus("connected"); - }; - dc.onclose = () => { - setDcState("closed"); - log("warn", "DC", "Closed"); - }; - dc.onmessage = (e) => { - try { - log("info", "EVENT", JSON.parse(e.data).type ?? "unknown"); - } catch { - log("info", "EVENT", e.data.slice(0, 100)); - } - }; - - // Mic - try { - const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); - streamRef.current = stream; - stream.getTracks().forEach((t) => pc.addTrack(t, stream)); - log("success", "MIC", "Microphone access granted"); - setAudioStatus("Mic active — waiting for remote audio"); - micRef.current = true; - setMicActive(true); - } catch (e) { - log("warn", "MIC", `Mic denied: ${e.message}`); - const ctx = new AudioContext(); - const dest = ctx.createMediaStreamDestination(); - dest.stream.getTracks().forEach((t) => pc.addTrack(t, dest.stream)); - } - - // Step 3: SDP offer - log("step", "STEP 3", "Creating SDP offer"); - const offer = await pc.createOffer(); - await pc.setLocalDescription(offer); - setSdpOffer(offer.sdp); - setOfferActive(true); - log("info", "SDP", `Offer created (${offer.sdp.split("\n").length} lines)`); - - // Step 4: SDP exchange - setFlowStep(2); - log("step", "STEP 4", `POST ${url}/v1/realtime/calls`); - try { - const r = await fetch(`${url}/v1/realtime/calls`, { - method: "POST", - headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/sdp" }, - body: offer.sdp, - }); - log("info", "HTTP", `${r.status} ${r.statusText}`); - if (!r.ok) { - log("error", "ERR", await r.text()); - stopSession(); - return; - } - const ans = await r.text(); - log("success", "SDP", `Answer received (${ans.split("\n").length} lines)`); - - // Step 5: remote description - log("step", "STEP 5", "Setting remote description"); - await pc.setRemoteDescription({ type: "answer", sdp: ans }); - setSdpAnswer(ans); - setAnswerActive(true); - log("success", "CONN", "✓ Session established — Browser ↔ LiteLLM ↔ OpenAI"); - } catch (e) { - log("error", "ERR", `calls failed: ${e.message}`); - stopSession(); - } - } - - function stopSession() { - if (pcRef.current) { - pcRef.current.close(); - pcRef.current = null; - } - if (streamRef.current) { - streamRef.current.getTracks().forEach((t) => t.stop()); - streamRef.current = null; - } - if (animRef.current) { - cancelAnimationFrame(animRef.current); - animRef.current = null; - } - tokenRef.current = null; - micRef.current = false; - setConnected(false); - setStatus("idle"); - setFlowStep(0); - setTokenPreview("—"); - setIceState("—"); - setConnState("—"); - setDcState("—"); - setMicActive(false); - setOfferActive(false); - setAnswerActive(false); - setBars(Array(28).fill(2)); - setAudioStatus("Start a session first"); - log("warn", "SESSION", "Session stopped"); - } - - function toggleMic() { - if (!streamRef.current) { - log("warn", "MIC", "No active session"); - return; - } - const next = !micRef.current; - micRef.current = next; - streamRef.current.getAudioTracks().forEach((t) => { - t.enabled = next; - }); - setMicActive(next); - log("info", "MIC", next ? "Unmuted" : "Muted"); - } - - const f = (n) => flowStep >= n; - - return ( - <> - -
- {/* Toggle header */} -
setOpen((o) => !o)}> -
-
-
-
INTERACTIVE TESTER
-
Browser → LiteLLM → OpenAI · WebRTC
-
-
- -
- - {open && ( -
- {/* Sidebar */} -
-
-
Proxy Config
-
- - setProxyUrl(e.target.value)} - placeholder="http://localhost:4000" - /> -
-
- - setApiKey(e.target.value)} - placeholder="sk-1234" - /> -
-
- - setModel(e.target.value)} /> -
-
- -
- -
-
Flow
-
-
Browser
-
-
LiteLLM
-
-
OpenAI
-
-
- -
- -
-
Controls
- - - -
- -
- -
-
Session Info
-
- {[ - ["token", tokenPreview], - ["ice", iceState], - ["conn", connState], - ["data ch.", dcState], - ].map(([k, v]) => ( -
- {k} - {v} -
- ))} -
-
-
- - {/* Right panel */} -
-
- WEBRTC REALTIME TESTER -
-
- {status} -
-
- -
- {["logs", "sdp", "audio"].map((t) => ( -
setActiveTab(t)}> - {t.toUpperCase()} -
- ))} -
- - {/* Logs */} -
-
- {entries.length === 0 ? ( -
-
📡
-
Hit "Start Session" to begin
-
- ) : ( - entries.map((e) => ( -
- {e.time} - [{e.tag}] - {e.msg} -
- )) - )} -
-
- - {/* SDP */} -
-
-
-
-
- SDP OFFER -
-