From aa0ab33ac702a9fc53f89b73f59dd01c7ff4b6d8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 23 Apr 2026 15:05:23 +0000 Subject: [PATCH] feat(ui): LogDetailsDrawer/DrawerHeader to shadcn - antd Button/Space/Tag/Tooltip/Typography + @ant-design Close/Up/ Down \u2192 shadcn Button/Badge/Tooltip + lucide X/ChevronUp/ChevronDown. - Typography.Text copyable rewritten as a custom inline copy button (same pattern as LabeledField / KeyInfoHeader). - Status badge uses categorical emerald/red palette; file added to .eslintrc.json overrides. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang --- ui/litellm-dashboard/.eslintrc.json | 1 + .../LogDetailsDrawer/DrawerHeader.tsx | 256 +++++++++++------- 2 files changed, 158 insertions(+), 99 deletions(-) diff --git a/ui/litellm-dashboard/.eslintrc.json b/ui/litellm-dashboard/.eslintrc.json index 95ff35094ab..61f76577b83 100644 --- a/ui/litellm-dashboard/.eslintrc.json +++ b/ui/litellm-dashboard/.eslintrc.json @@ -69,6 +69,7 @@ "src/components/vector_store_management/S3VectorsConfig.tsx", "src/components/mcp_tools/mcp_server_cost_config.tsx", "src/components/view_logs/GuardrailViewer/CompliancePanel.tsx", + "src/components/view_logs/LogDetailsDrawer/DrawerHeader.tsx", "src/components/prompts/prompt_editor_view/PromptEditorHeader.tsx", "src/components/prompts/prompt_editor_view/VersionHistorySidePanel.tsx", "src/app/(dashboard)/teams/components/TeamsTable/ModelsCell.tsx", diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/DrawerHeader.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/DrawerHeader.tsx index 25fcdf953e9..c62f3ba71a3 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/DrawerHeader.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/DrawerHeader.tsx @@ -1,5 +1,14 @@ -import { Button, Space, Tag, Tooltip, Typography } from "antd"; -import { CloseOutlined, UpOutlined, DownOutlined } from "@ant-design/icons"; +import React, { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { cn } from "@/lib/utils"; +import { Check, ChevronDown, ChevronUp, Copy, X } from "lucide-react"; import moment from "moment"; import { LogEntry } from "../columns"; import { getProviderLogoAndName } from "../../provider_info_helpers"; @@ -8,15 +17,11 @@ import { COLOR_BORDER, COLOR_BACKGROUND, SPACING_MEDIUM, - SPACING_LARGE, FONT_SIZE_HEADER, FONT_SIZE_MEDIUM, FONT_FAMILY_MONO, - SPACING_SMALL, } from "./constants"; -const { Text } = Typography; - interface DrawerHeaderProps { log: LogEntry; onClose: () => void; @@ -27,10 +32,6 @@ interface DrawerHeaderProps { environment: string; } -/** - * Header component for the log details drawer. - * Displays model/provider, request ID, navigation controls, status, environment, and timestamp. - */ export function DrawerHeader({ log, onClose, @@ -45,33 +46,41 @@ export function DrawerHeader({ return (
- {/* Row 0: Model + Provider with Logo */} - + - {/* Row 1: Request ID + Actions */} -
+
- +
- {/* Row 2: Status + Env + Timestamp */} - +
); } -/** - * Model and Provider display with logo - */ function ModelProviderSection({ model, providerLogo, @@ -82,62 +91,85 @@ function ModelProviderSection({ providerName?: string; }) { return ( - +
{providerLogo && ( + // eslint-disable-next-line @next/next/no-img-element {providerName { const target = e.target as HTMLImageElement; target.style.display = "none"; }} /> )} - - - {model} - +
+ {model} {providerName && ( - - {providerName} - + {providerName} )} - - - ); -} - -/** - * Request ID display with copy functionality - */ -function RequestIdSection({ requestId }: { requestId: string }) { - return ( -
- - - {requestId} - - +
+
+ ); +} + +function RequestIdSection({ requestId }: { requestId: string }) { + const [copied, setCopied] = useState(false); + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(requestId); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_err) { + /* noop */ + } + }; + + return ( +
+ + + + + {requestId} + + + {requestId} + + + + + + + + + {copied ? "Copied!" : "Copy Request ID"} + + +
); } -/** - * Navigation controls (previous, next, close) - * Shows keyboard shortcuts with bounding boxes for visibility - */ function NavigationSection({ onPrevious, onNext, @@ -147,36 +179,48 @@ function NavigationSection({ onNext: () => void; onClose: () => void; }) { - const keyboardShortcutStyle = { - border: "1px solid #d9d9d9", - borderRadius: 4, - padding: "0 4px", - fontSize: 12, - fontFamily: "monospace", - marginLeft: 4, - background: "#fafafa", - }; + const KeyHint = ({ children }: { children: React.ReactNode }) => ( + + {children} + + ); return ( - }> - - - - +
+
+ +
+
+ + + + + + ESC to close + + +
+
); } -/** - * Status bar with tags and timestamp - */ function StatusBar({ log, statusLabel, @@ -189,17 +233,31 @@ function StatusBar({ environment: string; }) { return ( - - {statusLabel} - Env: {environment} - - +
+ + {statusLabel} + + Env: {environment} +
+ {moment(log.startTime).format("MMM D, YYYY h:mm:ss A")} - - + + ({moment(log.startTime).fromNow()}) - - - + +
+
); }