mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-06 08:16:43 +00:00
refactor(ui): keep the log drawer's trace sidebar in flow as a collapsed rail
The toggle was absolutely positioned over the drawer's flex row, owned by neither column. That forced two coupled workarounds: a stacking level so it could beat whatever it landed on, and pl-12 on the sidebar header to reserve space for a button that was not its child. The sidebar column now always renders, at 224px expanded and a 40px rail collapsed, and the toggle is a normal in-flow child of the column it controls. No absolute, no z-index, no reserved padding, and nothing that can paint over the button. It also stops the toggle from clipping the provider logo, which it did in the collapsed state even before the z-index scale landed. Costs 40px of drawer width while collapsed.
This commit is contained in:
parent
8278a92a06
commit
fcd6ea46ce
1 changed files with 94 additions and 87 deletions
|
|
@ -30,6 +30,7 @@ export interface LogDetailsDrawerProps {
|
|||
}
|
||||
|
||||
const SIDEBAR_WIDTH_PX = 224;
|
||||
const SIDEBAR_RAIL_WIDTH_PX = 40;
|
||||
|
||||
// Session logs are fetched page-by-page from the paginated backend and
|
||||
// accumulated so the drawer can show the whole session. page_size is the
|
||||
|
|
@ -312,98 +313,104 @@ export function LogDetailsDrawer({
|
|||
<SheetTitle className="sr-only">
|
||||
{logEntry?.request_id ? `Request ${logEntry.request_id} details` : "Request details"}
|
||||
</SheetTitle>
|
||||
<div style={{ height: "100%" }} className="flex relative">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
onClick={() => setIsSidebarCollapsed((collapsed) => !collapsed)}
|
||||
className="absolute top-2 left-2 z-floating bg-card! border! border-border! rounded-md!"
|
||||
aria-label={isSidebarCollapsed ? "Expand trace sidebar" : "Collapse trace sidebar"}
|
||||
<div style={{ height: "100%" }} className="flex">
|
||||
<div
|
||||
className="border-r border-border bg-muted flex flex-col shrink-0"
|
||||
style={{ width: isSidebarCollapsed ? SIDEBAR_RAIL_WIDTH_PX : SIDEBAR_WIDTH_PX }}
|
||||
>
|
||||
{isSidebarCollapsed ? <ChevronRight className="size-4" /> : <ChevronLeft className="size-4" />}
|
||||
</Button>
|
||||
{!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
|
||||
className={`flex items-start gap-1 py-2 pl-1 border-b border-border bg-card ${isSidebarCollapsed ? "pr-1" : "pr-3"}`}
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
onClick={() => setIsSidebarCollapsed((collapsed) => !collapsed)}
|
||||
className="shrink-0 border! border-border! rounded-md!"
|
||||
aria-label={isSidebarCollapsed ? "Expand trace sidebar" : "Collapse trace sidebar"}
|
||||
>
|
||||
{isSidebarCollapsed ? <ChevronRight className="size-4" /> : <ChevronLeft className="size-4" />}
|
||||
</Button>
|
||||
{!isSidebarCollapsed && (
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
{isSessionMode ? "Session" : "Trace"}
|
||||
</div>
|
||||
</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}>
|
||||
<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 && (
|
||||
<>
|
||||
<span className="mx-1.5">·</span>
|
||||
{count}
|
||||
{label}
|
||||
</span>
|
||||
) : null;
|
||||
})}
|
||||
<span className="mx-1.5">·</span>
|
||||
{isSessionMode ? getSpendString(totalSessionCost) : getSpendString(currentLog.spend || 0)}
|
||||
{sessionDurationSeconds}s
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{isSessionMode && (
|
||||
<>
|
||||
<span className="mx-1.5">·</span>
|
||||
{sessionDurationSeconds}s
|
||||
</>
|
||||
<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>
|
||||
{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>
|
||||
|
||||
{!isSidebarCollapsed && (
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
{normalizeGuardrailEntries(metadata?.guardrail_information).length > 0 && (
|
||||
<div className="px-3 pt-2">
|
||||
|
|
@ -447,8 +454,8 @@ export function LogDetailsDrawer({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex-1 flex flex-col overflow-hidden">
|
||||
<DrawerHeader
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue