From dfdafbf89b8566c9db0ed9fc531b6f129e5148bb Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Thu, 13 Aug 2026 12:50:56 -0700 Subject: [PATCH] fix(ui): keep the tools panel mounted so a tool's expanded detail survives antd's Collapse kept the panel mounted once opened, so a tool a user had expanded stayed expanded after closing and reopening Tools. Base UI renders only the open branch, so the migration silently reset every ToolItem. The regression test passes against the antd original, fails against the migration without keepMounted, and passes with it. --- .../ToolsSection/ToolsSection.test.tsx | 25 +++++++++++++++---- .../view_logs/ToolsSection/ToolsSection.tsx | 2 +- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ui/litellm-dashboard/src/components/view_logs/ToolsSection/ToolsSection.test.tsx b/ui/litellm-dashboard/src/components/view_logs/ToolsSection/ToolsSection.test.tsx index 2e9d83d9c6d..e146f38b42b 100644 --- a/ui/litellm-dashboard/src/components/view_logs/ToolsSection/ToolsSection.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/ToolsSection/ToolsSection.test.tsx @@ -2,7 +2,7 @@ * Core tests for Tools section */ -import { render, screen } from "@testing-library/react"; +import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { describe, it, expect } from "vitest"; import { parseToolsFromLog } from "./utils"; @@ -152,6 +152,8 @@ describe("ToolsSection", () => { }); }); +const isShown = (text: string) => screen.queryAllByText(text).some((el) => el.closest("[hidden]") === null); + describe("ToolsSection rendering", () => { it("summarises how many tools were provided and called", () => { render(); @@ -175,12 +177,25 @@ describe("ToolsSection rendering", () => { it("reveals the tool list only after the section is expanded", async () => { render(); - expect(screen.queryByText("called")).not.toBeInTheDocument(); - expect(screen.queryByText("not called")).not.toBeInTheDocument(); + expect(isShown("called")).toBe(false); + expect(isShown("not called")).toBe(false); await userEvent.click(screen.getByText("Tools")); - expect(await screen.findByText("called")).toBeInTheDocument(); - expect(screen.getByText("not called")).toBeInTheDocument(); + await waitFor(() => expect(isShown("called")).toBe(true)); + expect(isShown("not called")).toBe(true); + }); + + it("keeps a tool's expanded detail across a close and reopen", async () => { + render(); + + await userEvent.click(screen.getByText("Tools")); + await userEvent.click(await screen.findByText(/1\. get_weather/)); + expect(isShown("Description")).toBe(true); + + await userEvent.click(screen.getByText("Tools")); + await userEvent.click(screen.getByText("Tools")); + + await waitFor(() => expect(isShown("Description")).toBe(true)); }); }); diff --git a/ui/litellm-dashboard/src/components/view_logs/ToolsSection/ToolsSection.tsx b/ui/litellm-dashboard/src/components/view_logs/ToolsSection/ToolsSection.tsx index 46c820caa25..e3965f182fd 100644 --- a/ui/litellm-dashboard/src/components/view_logs/ToolsSection/ToolsSection.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/ToolsSection/ToolsSection.tsx @@ -52,7 +52,7 @@ export function ToolsSection({ log }: ToolsSectionProps) { - +
{tools.map((tool) => (