diff --git a/webui/src/lib/chat-groups.ts b/webui/src/lib/chat-groups.ts index 2fda9f8f0..f4b4b9a1a 100644 --- a/webui/src/lib/chat-groups.ts +++ b/webui/src/lib/chat-groups.ts @@ -281,19 +281,18 @@ function groupSessionsByProject( ), })); - groups.sort((a, b) => { - const timeOrder = dateToTime(b.updatedAt) - dateToTime(a.updatedAt); - if (timeOrder !== 0) return timeOrder; - return a.label.localeCompare(b.label, "en", { - numeric: true, - sensitivity: "base", - }); - }); - if (conversations.length) { + const chatsUpdatedAt = conversations.reduce( + (best, s) => { + const candidate = s.updatedAt ?? s.createdAt ?? null; + return isNewerDate(candidate, best) ? candidate : best; + }, + null, + ); groups.push({ id: "workspace:chats", label: labels.all, + updatedAt: chatsUpdatedAt, sessions: sortProjectSessions( conversations, options.sort, @@ -304,6 +303,15 @@ function groupSessionsByProject( }); } + groups.sort((a, b) => { + const timeOrder = dateToTime(b.updatedAt) - dateToTime(a.updatedAt); + if (timeOrder !== 0) return timeOrder; + return a.label.localeCompare(b.label, "en", { + numeric: true, + sensitivity: "base", + }); + }); + return groups; } diff --git a/webui/src/tests/chat-list.test.tsx b/webui/src/tests/chat-list.test.tsx index eb3ae5c8b..f678d3c06 100644 --- a/webui/src/tests/chat-list.test.tsx +++ b/webui/src/tests/chat-list.test.tsx @@ -256,4 +256,60 @@ describe("ChatList", () => { expect(within(chatsSection).getByText("Chat 0")).toBeInTheDocument(); expect(within(chatsSection).getByRole("button", { name: "Show less" })).toBeInTheDocument(); }); + + it("sorts Chats section among project groups by recency, not always last", () => { + const sessions = [ + session({ + chatId: "recent-chat", + title: "Recent chat", + updatedAt: "2026-05-21T12:00:00Z", + }), + session({ + chatId: "project-a", + title: "Project A task", + updatedAt: "2026-05-21T10:00:00Z", + workspaceScope: { + project_path: "/Users/me/project-a", + project_name: "project-a", + access_mode: "restricted", + }, + }), + session({ + chatId: "project-b", + title: "Project B task", + updatedAt: "2026-05-21T11:00:00Z", + workspaceScope: { + project_path: "/Users/me/project-b", + project_name: "project-b", + access_mode: "restricted", + }, + }), + ]; + + render( + , + ); + + const allRegions = screen.getAllByRole("region"); + const regionNames = allRegions.map((r) => r.getAttribute("aria-label") ?? r.textContent); + + // The most recently updated conversation ("Recent chat" at 12:00) must be + // in the first group — Chats should come before both projects. + const chatsIdx = regionNames.findIndex((n) => n?.includes("Chats")); + const projAIdx = regionNames.findIndex((n) => n?.includes("project-a")); + const projBIdx = regionNames.findIndex((n) => n?.includes("project-b")); + + expect(chatsIdx).toBeLessThan(projAIdx); + expect(chatsIdx).toBeLessThan(projBIdx); + expect(within(allRegions[chatsIdx]).getByText("Recent chat")).toBeInTheDocument(); + }); });