From 86d228b38e63fbc2bb241801f409607cdbf34135 Mon Sep 17 00:00:00 2001 From: Xubin Ren <52506698+Re-bin@users.noreply.github.com> Date: Sat, 15 Aug 2026 15:07:04 +0800 Subject: [PATCH] fix(webui): include grouped tabs in range selection --- webui/src/components/ChatList.tsx | 1 + webui/src/tests/chat-list.test.tsx | 44 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/webui/src/components/ChatList.tsx b/webui/src/components/ChatList.tsx index e45f53e94..9cbee63e6 100644 --- a/webui/src/components/ChatList.tsx +++ b/webui/src/components/ChatList.tsx @@ -563,6 +563,7 @@ export const ChatList = memo(function ChatList({ const next = new Set(current); if (range) { for (const key of range) next.add(key); + for (const key of validKeys) next.add(key); return next; } const remove = validKeys.length > 0 && validKeys.every((key) => next.has(key)); diff --git a/webui/src/tests/chat-list.test.tsx b/webui/src/tests/chat-list.test.tsx index 4cff8b295..d8ef7333e 100644 --- a/webui/src/tests/chat-list.test.tsx +++ b/webui/src/tests/chat-list.test.tsx @@ -698,6 +698,50 @@ describe("ChatList", () => { } }); + it("includes every pane when a Shift-click range ends on a grouped tab", async () => { + render( + , + ); + + fireEvent.pointerDown(screen.getByRole("button", { + name: "Topic actions for First topic", + }), { button: 0, ctrlKey: false }); + fireEvent.click(await screen.findByRole("menuitem", { name: "Select" })); + fireEvent.click(screen.getByRole("button", { name: "Group: Root topic" }), { + shiftKey: true, + }); + + expect(screen.getByText("3 selected")).toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Group: Root topic" })) + .toHaveAttribute("aria-pressed", "true"); + expect(screen.getByRole("button", { name: "Root topic" })) + .toHaveAttribute("aria-pressed", "true"); + expect(screen.getByRole("button", { name: "Research pane" })) + .toHaveAttribute("aria-pressed", "true"); + }); + it("shows temporary chats separately and lets the user reopen or close them", async () => { const temporarySession = session({ key: "temporary:temporary-one",