mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-06 08:16:43 +00:00
refactor(ui): give the collapsed log drawer its own sidebar toggle
Open, the trace sidebar is byte-identical to before: the toggle sits over its header exactly where it did, and the header keeps the padding that makes room for it. Collapsed, that button has nowhere to live, so the drawer header shows one instead, on the model row or the request id row when the log names no model. Both come from SidebarToggle, so they cannot drift in design. The chevrons now point the way the sidebar will move: right while it is open, left while it is collapsed.
This commit is contained in:
parent
20e6d6457a
commit
4a3dcd5e8e
2 changed files with 88 additions and 82 deletions
|
|
@ -312,90 +312,94 @@ export function LogDetailsDrawer({
|
|||
<SheetTitle className="sr-only">
|
||||
{logEntry?.request_id ? `Request ${logEntry.request_id} details` : "Request details"}
|
||||
</SheetTitle>
|
||||
<div style={{ height: "100%" }} className="flex">
|
||||
<div style={{ height: "100%" }} className="flex relative">
|
||||
{!isSidebarCollapsed && (
|
||||
<div className="border-r border-border bg-muted flex flex-col shrink-0" style={{ width: SIDEBAR_WIDTH_PX }}>
|
||||
<div className="flex items-start gap-1 py-2 pl-1 pr-3 border-b border-border bg-card">
|
||||
<SidebarToggle
|
||||
isCollapsed={isSidebarCollapsed}
|
||||
onToggle={() => setIsSidebarCollapsed((collapsed) => !collapsed)}
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
{isSessionMode ? "Session" : "Trace"}
|
||||
<SidebarToggle
|
||||
isCollapsed={false}
|
||||
onToggle={() => setIsSidebarCollapsed(true)}
|
||||
className="absolute top-2 left-2 z-raised"
|
||||
/>
|
||||
)}
|
||||
{!isSidebarCollapsed && (
|
||||
<div className="border-r border-border bg-muted flex flex-col" style={{ width: SIDEBAR_WIDTH_PX }}>
|
||||
<div className="pl-12 pr-3 py-2 border-b border-border bg-card">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div>
|
||||
<div className="text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
{isSessionMode ? "Session" : "Trace"}
|
||||
</div>
|
||||
<div className="font-mono text-[12px] text-foreground leading-tight flex items-center gap-1">
|
||||
<span className="truncate">{leftPanelDisplayId}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCopyLeftPanelId}
|
||||
className="text-muted-foreground hover:text-foreground"
|
||||
aria-label="Copy trace id"
|
||||
>
|
||||
{copiedLeftPanelId ? <Check className="size-3" /> : <Copy className="size-3" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="font-mono text-[12px] text-foreground leading-tight flex items-center gap-1">
|
||||
<span className="truncate">{leftPanelDisplayId}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCopyLeftPanelId}
|
||||
className="text-muted-foreground hover:text-foreground"
|
||||
aria-label="Copy trace id"
|
||||
>
|
||||
{copiedLeftPanelId ? <Check className="size-3" /> : <Copy className="size-3" />}
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
||||
{logsForList.length} req
|
||||
{[
|
||||
isSessionMode
|
||||
? llmCount
|
||||
: logsForList.filter(
|
||||
(row) =>
|
||||
!MCP_CALL_TYPES.includes(row.call_type) && !AGENT_CALL_TYPES.includes(row.call_type),
|
||||
).length,
|
||||
isSessionMode
|
||||
? agentCount
|
||||
: logsForList.filter((row) => AGENT_CALL_TYPES.includes(row.call_type)).length,
|
||||
isSessionMode
|
||||
? mcpCount
|
||||
: logsForList.filter((row) => MCP_CALL_TYPES.includes(row.call_type)).length,
|
||||
].map((count, i) => {
|
||||
const label = [" LLM", " Agent", " MCP"][i];
|
||||
return count > 0 ? (
|
||||
<span key={label}>
|
||||
<span className="mx-1.5">·</span>
|
||||
{count}
|
||||
{label}
|
||||
</span>
|
||||
) : null;
|
||||
})}
|
||||
<span className="mx-1.5">·</span>
|
||||
{isSessionMode ? getSpendString(totalSessionCost) : getSpendString(currentLog.spend || 0)}
|
||||
{isSessionMode && (
|
||||
<>
|
||||
</div>
|
||||
<div className="mt-1 text-[11px] text-muted-foreground font-mono">
|
||||
{logsForList.length} req
|
||||
{[
|
||||
isSessionMode
|
||||
? llmCount
|
||||
: logsForList.filter(
|
||||
(row) => !MCP_CALL_TYPES.includes(row.call_type) && !AGENT_CALL_TYPES.includes(row.call_type),
|
||||
).length,
|
||||
isSessionMode
|
||||
? agentCount
|
||||
: logsForList.filter((row) => AGENT_CALL_TYPES.includes(row.call_type)).length,
|
||||
isSessionMode
|
||||
? mcpCount
|
||||
: logsForList.filter((row) => MCP_CALL_TYPES.includes(row.call_type)).length,
|
||||
].map((count, i) => {
|
||||
const label = [" LLM", " Agent", " MCP"][i];
|
||||
return count > 0 ? (
|
||||
<span key={label}>
|
||||
<span className="mx-1.5">·</span>
|
||||
{sessionDurationSeconds}s
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{count}
|
||||
{label}
|
||||
</span>
|
||||
) : null;
|
||||
})}
|
||||
<span className="mx-1.5">·</span>
|
||||
{isSessionMode ? getSpendString(totalSessionCost) : getSpendString(currentLog.spend || 0)}
|
||||
{isSessionMode && (
|
||||
<div className="text-[11px] text-muted-foreground font-mono whitespace-nowrap">
|
||||
{cacheHitCount}/{logsForList.length} cached
|
||||
</div>
|
||||
)}
|
||||
{isSessionMode && sessionTruncated && (
|
||||
<div className="mt-1 text-[11px] text-warning font-mono">
|
||||
Showing most recent {logsForList.length} of {sessionTotalCount}
|
||||
</div>
|
||||
)}
|
||||
{isSessionMode && (
|
||||
<Tabs
|
||||
className="mt-1.5"
|
||||
value={sessionSortMode}
|
||||
onValueChange={(value) => setSessionSortMode(value as SessionLogSortMode)}
|
||||
>
|
||||
<TabsList className="w-full">
|
||||
<TabsTrigger value="duration" className="text-[11px]">
|
||||
Duration
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="start_time" className="text-[11px]">
|
||||
Start time
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
<>
|
||||
<span className="mx-1.5">·</span>
|
||||
{sessionDurationSeconds}s
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{isSessionMode && (
|
||||
<div className="text-[11px] text-muted-foreground font-mono whitespace-nowrap">
|
||||
{cacheHitCount}/{logsForList.length} cached
|
||||
</div>
|
||||
)}
|
||||
{isSessionMode && sessionTruncated && (
|
||||
<div className="mt-1 text-[11px] text-warning font-mono">
|
||||
Showing most recent {logsForList.length} of {sessionTotalCount}
|
||||
</div>
|
||||
)}
|
||||
{isSessionMode && (
|
||||
<Tabs
|
||||
className="mt-1.5"
|
||||
value={sessionSortMode}
|
||||
onValueChange={(value) => setSessionSortMode(value as SessionLogSortMode)}
|
||||
>
|
||||
<TabsList className="w-full">
|
||||
<TabsTrigger value="duration" className="text-[11px]">
|
||||
Duration
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="start_time" className="text-[11px]">
|
||||
Start time
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/cva.config";
|
||||
|
||||
export interface SidebarToggleProps {
|
||||
isCollapsed: boolean;
|
||||
onToggle: () => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function SidebarToggle({ isCollapsed, onToggle }: SidebarToggleProps) {
|
||||
export function SidebarToggle({ isCollapsed, onToggle, className }: SidebarToggleProps) {
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
size="icon-sm"
|
||||
onClick={onToggle}
|
||||
className="shrink-0"
|
||||
className={cn("shrink-0 bg-card! border! border-border! rounded-md!", className)}
|
||||
aria-label={isCollapsed ? "Expand trace sidebar" : "Collapse trace sidebar"}
|
||||
>
|
||||
{isCollapsed ? <ChevronRight className="size-4" /> : <ChevronLeft className="size-4" />}
|
||||
{isCollapsed ? <ChevronLeft className="size-4" /> : <ChevronRight className="size-4" />}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue