From 8278a92a065506e592010bdc07c18e70a2100267 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Sat, 29 Aug 2026 10:42:48 -0700 Subject: [PATCH 1/5] fix(ui): let the log drawer's trace sidebar expand again once collapsed The sidebar toggle sits absolutely positioned over the drawer's flex row. With the sidebar expanded it lands on the sidebar header, but once collapsed it lands on the drawer header, which is sticky at z-chrome (10). The named-z-scale refactor moved the toggle from z-20 to z-raised (1), so from then on the header painted over it and swallowed the click: collapse the trace list and there was no way to bring it back. Moves the toggle to z-floating (30) and folds the two mirrored buttons into one, since they only ever differed by icon, label and handler. Covered by a Playwright spec, which is the tier that can see the layering: the button stays visible and enabled either way, so the pre-fix failure is a click interception that jsdom cannot reproduce. --- tests/e2e/ui/tests/logs/logs.spec.ts | 26 ++++++++++++++++ .../LogDetailsDrawer/LogDetailsDrawer.tsx | 30 ++++++------------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/tests/e2e/ui/tests/logs/logs.spec.ts b/tests/e2e/ui/tests/logs/logs.spec.ts index b29a72cbf81..56a3d0f0109 100644 --- a/tests/e2e/ui/tests/logs/logs.spec.ts +++ b/tests/e2e/ui/tests/logs/logs.spec.ts @@ -148,6 +148,32 @@ test.describe("Logs page", () => { }); }); + test("the trace sidebar collapses and expands again", async ({ page, request }) => { + const prompt = `logs-sidebar-prompt-${uniqueSuffix()}`; + const requestId = await sendChatCompletion(request, { + model: CHAT_MODEL_A, + prompt, + }); + await waitForSpendLog(request, requestId); + + const row = await openLogsForRequest(page, requestId); + await row.click(); + + const drawer = page.getByRole("dialog").first(); + await expect(drawer.getByText("Request & Response")).toBeVisible({ timeout: 20_000 }); + + const toggle = drawer.getByLabel("Collapse trace sidebar"); + await expect(toggle).toBeVisible({ timeout: 10_000 }); + await toggle.click(); + + const expandToggle = drawer.getByLabel("Expand trace sidebar"); + await expect(expandToggle).toBeVisible({ timeout: 10_000 }); + await expandToggle.click({ timeout: 10_000 }); + + await expect(drawer.getByLabel("Collapse trace sidebar")).toBeVisible({ timeout: 10_000 }); + await expect(drawer.getByText(prompt, { exact: false })).toBeVisible({ timeout: 10_000 }); + }); + test("the JSON view exposes Request and Response tabs", async ({ page, request }) => { const prompt = `logs-json-prompt-${uniqueSuffix()}`; const requestId = await sendChatCompletion(request, { diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx index f677a66cc54..c1e01d4d0ba 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx @@ -313,27 +313,15 @@ export function LogDetailsDrawer({ {logEntry?.request_id ? `Request ${logEntry.request_id} details` : "Request details"}
- {!isSidebarCollapsed ? ( - - ) : ( - - )} + {!isSidebarCollapsed && (
From fcd6ea46ce5fb9fb098a615514a7b0d012d41f17 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Sat, 29 Aug 2026 11:00:47 -0700 Subject: [PATCH 2/5] 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. --- .../LogDetailsDrawer/LogDetailsDrawer.tsx | 181 +++++++++--------- 1 file changed, 94 insertions(+), 87 deletions(-) diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx index c1e01d4d0ba..511e1a18253 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx @@ -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({ {logEntry?.request_id ? `Request ${logEntry.request_id} details` : "Request details"} -
- - {!isSidebarCollapsed && ( -
-
-
-
-
- {isSessionMode ? "Session" : "Trace"} -
-
- {leftPanelDisplayId} - -
+
+ + {!isSidebarCollapsed && ( +
+
+ {isSessionMode ? "Session" : "Trace"}
-
-
- {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 ? ( - +
+ {leftPanelDisplayId} + +
+
+ {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 ? ( + + · + {count} + {label} + + ) : null; + })} + · + {isSessionMode ? getSpendString(totalSessionCost) : getSpendString(currentLog.spend || 0)} + {isSessionMode && ( + <> · - {count} - {label} - - ) : null; - })} - · - {isSessionMode ? getSpendString(totalSessionCost) : getSpendString(currentLog.spend || 0)} + {sessionDurationSeconds}s + + )} +
{isSessionMode && ( - <> - · - {sessionDurationSeconds}s - +
+ {cacheHitCount}/{logsForList.length} cached +
+ )} + {isSessionMode && sessionTruncated && ( +
+ Showing most recent {logsForList.length} of {sessionTotalCount} +
+ )} + {isSessionMode && ( + setSessionSortMode(value as SessionLogSortMode)} + > + + + Duration + + + Start time + + + )}
- {isSessionMode && ( -
- {cacheHitCount}/{logsForList.length} cached -
- )} - {isSessionMode && sessionTruncated && ( -
- Showing most recent {logsForList.length} of {sessionTotalCount} -
- )} - {isSessionMode && ( - setSessionSortMode(value as SessionLogSortMode)} - > - - - Duration - - - Start time - - - - )} -
+ )} +
+ {!isSidebarCollapsed && (
{normalizeGuardrailEntries(metadata?.guardrail_information).length > 0 && (
@@ -447,8 +454,8 @@ export function LogDetailsDrawer({
)}
-
- )} + )} +
Date: Sat, 29 Aug 2026 11:42:45 -0700 Subject: [PATCH 3/5] refactor(ui): move the trace sidebar toggle into the log drawer header The collapsed rail kept the toggle in flow but left a 40px stub of empty sidebar on screen. The toggle now leads the drawer header's first row, ahead of the provider logo and the model name, so it reads as part of the header and the sidebar goes back to unmounting when collapsed. Still no absolute positioning and no stacking level: the button is a normal in-flow child of the header row it sits in. DrawerHeader takes the collapsed state and the toggle handler as props rather than reaching for the drawer's state. --- .../LogDetailsDrawer/DrawerHeader.tsx | 33 ++++++++++++----- .../LogDetailsDrawer/LogDetailsDrawer.tsx | 36 ++++++------------- 2 files changed, 34 insertions(+), 35 deletions(-) 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 751667b917b..d6eb33d0b0a 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,5 @@ import { useState } from "react"; -import { Check, ChevronDown, ChevronUp, Copy, X } from "lucide-react"; +import { Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Copy, X } from "lucide-react"; import moment from "moment"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; @@ -26,6 +26,8 @@ interface DrawerHeaderProps { statusLabel: string; statusColor: "error" | "success"; environment: string; + isSidebarCollapsed: boolean; + onToggleSidebar: () => void; } /** @@ -40,6 +42,8 @@ export function DrawerHeader({ statusLabel, statusColor, environment, + isSidebarCollapsed, + onToggleSidebar, }: DrawerHeaderProps) { const provider = log.custom_llm_provider || ""; const providerInfo = provider ? getProviderLogoAndName(provider) : null; @@ -56,13 +60,24 @@ export function DrawerHeader({ }} > {/* Row 0: Model + Provider with Logo */} - +
+ + +
{/* Row 1: Request ID + Actions */}
+
{providerLogo && (
-
-
- - {!isSidebarCollapsed && ( -
+ {!isSidebarCollapsed && ( +
+
+
{isSessionMode ? "Session" : "Trace"}
@@ -407,10 +391,8 @@ export function LogDetailsDrawer({ )}
- )} -
+
- {!isSidebarCollapsed && (
{normalizeGuardrailEntries(metadata?.guardrail_information).length > 0 && (
@@ -454,13 +436,15 @@ export function LogDetailsDrawer({
)}
- )} -
+
+ )}
setIsSidebarCollapsed((collapsed) => !collapsed)} onPrevious={selectPreviousLog} onNext={selectNextLog} statusLabel={statusLabel} From 20e6d6457a9a0ef5fe15bf516bb71e55710500ce Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Sat, 29 Aug 2026 11:48:04 -0700 Subject: [PATCH 4/5] refactor(ui): show the log drawer's sidebar toggle only where it has a row Putting the toggle in the drawer header unconditionally stranded it on its own line: the model row renders empty for a log that names no model or provider, so the chevron sat alone above the request id. The sidebar keeps the toggle whenever it is open, in its own header. Collapsed, the toggle moves into the drawer header and joins the model row, or the request id row when there is no model to join. Shared between both through SidebarToggle so the two call sites cannot drift. --- .../LogDetailsDrawer/DrawerHeader.test.tsx | 67 +++++++++++++++++++ .../LogDetailsDrawer/DrawerHeader.tsx | 24 ++++--- .../LogDetailsDrawer/LogDetailsDrawer.tsx | 9 ++- .../LogDetailsDrawer/SidebarToggle.tsx | 21 ++++++ 4 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/DrawerHeader.test.tsx create mode 100644 ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SidebarToggle.tsx diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/DrawerHeader.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/DrawerHeader.test.tsx new file mode 100644 index 00000000000..a8e27504019 --- /dev/null +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/DrawerHeader.test.tsx @@ -0,0 +1,67 @@ +import { screen, within } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import { render } from "../../../../tests/test-utils"; +import type { LogEntry } from "../columns"; +import { DrawerHeader } from "./DrawerHeader"; + +const logEntry = (overrides: Partial): LogEntry => + ({ + request_id: "170d64ea-69f0-431a-be72-332f8f78c18a", + api_key: "key-1", + team_id: "team-1", + model: "gpt-4o", + model_id: "model-1", + custom_llm_provider: "openai", + call_type: "acompletion", + spend: 0.01, + total_tokens: 10, + prompt_tokens: 5, + completion_tokens: 5, + startTime: "2026-07-07T09:50:13Z", + endTime: "2026-07-07T09:50:14Z", + cache_hit: "false", + messages: [], + response: {}, + ...overrides, + }) as LogEntry; + +const renderHeader = (log: LogEntry, isSidebarCollapsed: boolean) => + render( + , + ); + +const expandToggle = () => screen.getByLabelText("Expand trace sidebar"); + +describe("DrawerHeader sidebar toggle", () => { + it("stays out of the header while the sidebar owns it", () => { + renderHeader(logEntry({}), false); + + expect(screen.queryByLabelText("Expand trace sidebar")).not.toBeInTheDocument(); + expect(screen.queryByLabelText("Collapse trace sidebar")).not.toBeInTheDocument(); + }); + + it("shares the model row once the sidebar is collapsed", () => { + renderHeader(logEntry({}), true); + + const row = expandToggle().parentElement as HTMLElement; + expect(within(row).getByText("gpt-4o")).toBeInTheDocument(); + }); + + it("falls back to the request id row when the log names no model", () => { + renderHeader(logEntry({ model: "", custom_llm_provider: "" }), true); + + const row = expandToggle().parentElement as HTMLElement; + expect(within(row).getByText("170d64ea-69f0-431a-be72-332f8f78c18a")).toBeInTheDocument(); + }); +}); 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 d6eb33d0b0a..65b5801602c 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,5 @@ import { useState } from "react"; -import { Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Copy, X } from "lucide-react"; +import { Check, ChevronDown, ChevronUp, Copy, X } from "lucide-react"; import moment from "moment"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; @@ -7,6 +7,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/comp import { LogEntry } from "../columns"; import { AutoRouterTag } from "@/components/shared/table_cells"; import { ClassifyTag } from "./ClassifyTag"; +import { SidebarToggle } from "./SidebarToggle"; import { getProviderLogoAndName } from "../../provider_info_helpers"; import { DRAWER_HEADER_PADDING, @@ -47,6 +48,8 @@ export function DrawerHeader({ }: DrawerHeaderProps) { const provider = log.custom_llm_provider || ""; const providerInfo = provider ? getProviderLogoAndName(provider) : null; + const showToggleWithProvider = isSidebarCollapsed && Boolean(providerInfo || log.model); + const showToggleWithRequestId = isSidebarCollapsed && !showToggleWithProvider; return (
{/* Row 0: Model + Provider with Logo */}
- + {showToggleWithProvider && } + {showToggleWithRequestId && }
diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx index e25c1a1b8b2..9849c95de71 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx @@ -8,6 +8,7 @@ import { AGENT_CALL_TYPES, MCP_CALL_TYPES } from "../constants"; import { getEventDisplayName } from "../utils"; import { ClassifyTag } from "./ClassifyTag"; import { DrawerHeader } from "./DrawerHeader"; +import { SidebarToggle } from "./SidebarToggle"; import { useKeyboardNavigation } from "./useKeyboardNavigation"; import { LogDetailContent, GuardrailJumpLink } from "./LogDetailContent"; import { sessionSpendLogsCall } from "../../networking"; @@ -314,8 +315,12 @@ export function LogDetailsDrawer({
{!isSidebarCollapsed && (
-
-
+
+ setIsSidebarCollapsed((collapsed) => !collapsed)} + /> +
{isSessionMode ? "Session" : "Trace"}
diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SidebarToggle.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SidebarToggle.tsx new file mode 100644 index 00000000000..b4ee191f4cd --- /dev/null +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SidebarToggle.tsx @@ -0,0 +1,21 @@ +import { ChevronLeft, ChevronRight } from "lucide-react"; +import { Button } from "@/components/ui/button"; + +export interface SidebarToggleProps { + isCollapsed: boolean; + onToggle: () => void; +} + +export function SidebarToggle({ isCollapsed, onToggle }: SidebarToggleProps) { + return ( + + ); +} From 4a3dcd5e8ebc579e5e3dc5f2bcf00c702899e57d Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Sat, 29 Aug 2026 11:53:14 -0700 Subject: [PATCH 5/5] 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. --- .../LogDetailsDrawer/LogDetailsDrawer.tsx | 160 +++++++++--------- .../LogDetailsDrawer/SidebarToggle.tsx | 10 +- 2 files changed, 88 insertions(+), 82 deletions(-) diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx index 9849c95de71..ddd0a650c04 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx @@ -312,90 +312,94 @@ export function LogDetailsDrawer({ {logEntry?.request_id ? `Request ${logEntry.request_id} details` : "Request details"} -
+
{!isSidebarCollapsed && ( -
-
- setIsSidebarCollapsed((collapsed) => !collapsed)} - /> -
-
- {isSessionMode ? "Session" : "Trace"} + setIsSidebarCollapsed(true)} + className="absolute top-2 left-2 z-raised" + /> + )} + {!isSidebarCollapsed && ( +
+
+
+
+
+ {isSessionMode ? "Session" : "Trace"} +
+
+ {leftPanelDisplayId} + +
-
- {leftPanelDisplayId} - -
-
- {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 ? ( - - · - {count} - {label} - - ) : null; - })} - · - {isSessionMode ? getSpendString(totalSessionCost) : getSpendString(currentLog.spend || 0)} - {isSessionMode && ( - <> +
+
+ {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 ? ( + · - {sessionDurationSeconds}s - - )} -
+ {count} + {label} + + ) : null; + })} + · + {isSessionMode ? getSpendString(totalSessionCost) : getSpendString(currentLog.spend || 0)} {isSessionMode && ( -
- {cacheHitCount}/{logsForList.length} cached -
- )} - {isSessionMode && sessionTruncated && ( -
- Showing most recent {logsForList.length} of {sessionTotalCount} -
- )} - {isSessionMode && ( - setSessionSortMode(value as SessionLogSortMode)} - > - - - Duration - - - Start time - - - + <> + · + {sessionDurationSeconds}s + )}
+ {isSessionMode && ( +
+ {cacheHitCount}/{logsForList.length} cached +
+ )} + {isSessionMode && sessionTruncated && ( +
+ Showing most recent {logsForList.length} of {sessionTotalCount} +
+ )} + {isSessionMode && ( + setSessionSortMode(value as SessionLogSortMode)} + > + + + Duration + + + Start time + + + + )}
diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SidebarToggle.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SidebarToggle.tsx index b4ee191f4cd..a1ba7ff2491 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SidebarToggle.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SidebarToggle.tsx @@ -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 ( ); }