mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-09-01 16:51:53 +03:00
fix(webui): assign readable session handles
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import type { MouseEvent as ReactMouseEvent, ReactElement } from "react";
|
||||
import type { CSSProperties, MouseEvent as ReactMouseEvent, ReactElement } from "react";
|
||||
import {
|
||||
Archive,
|
||||
ArchiveRestore,
|
||||
@@ -50,7 +50,6 @@ import {
|
||||
} from "@/components/ui/tooltip";
|
||||
import { MAX_WORKBENCH_PANES } from "@/components/workbench/workbench-model";
|
||||
import { SIDEBAR_SELECTION_ITEM_CLASS } from "@/components/SidebarSelectionHighlight";
|
||||
import { SessionHandleLabel } from "@/components/SessionHandleLabel";
|
||||
import { deriveTitle, relativeTime, visibleSessionPreview } from "@/lib/format";
|
||||
import {
|
||||
COLLAPSED_CHATS_VISIBLE_COUNT,
|
||||
@@ -131,11 +130,19 @@ function SidebarSessionHandle({ handle }: { handle: ChatSummary["handle"] }) {
|
||||
if (!handle) return null;
|
||||
return (
|
||||
<span
|
||||
data-sidebar-session-handle
|
||||
className="flex max-w-20 shrink-0 items-center overflow-hidden whitespace-nowrap text-[11px] font-medium leading-5"
|
||||
>
|
||||
<SessionHandleLabel id={handle.id}>
|
||||
<span
|
||||
data-sidebar-session-handle-underline
|
||||
className="inline border-b-2 text-foreground"
|
||||
style={{
|
||||
"--sidebar-session-handle-color": sessionHandleColor(handle.id),
|
||||
borderBottomColor: "var(--sidebar-session-handle-color)",
|
||||
} as CSSProperties}
|
||||
>
|
||||
@{handle.name}
|
||||
</SessionHandleLabel>
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { fireEvent, render, screen, within } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { ChatList } from "@/components/ChatList";
|
||||
import { sessionHandleColor } from "@/lib/session-handle";
|
||||
import { readDraggedSession, SESSION_DRAG_TYPE } from "@/lib/session-drag";
|
||||
import type { ChatSummary } from "@/lib/types";
|
||||
|
||||
@@ -66,6 +67,90 @@ describe("ChatList", () => {
|
||||
expect(onTogglePin).toHaveBeenCalledWith("websocket:review");
|
||||
});
|
||||
|
||||
it("restores the colored handle underline and animated active track", () => {
|
||||
render(
|
||||
<ChatList
|
||||
sessions={[session({
|
||||
chatId: "review",
|
||||
title: "Review the patch",
|
||||
handle: { id: "handle_1234", name: "mira" },
|
||||
})]}
|
||||
activeKey="websocket:review"
|
||||
onSelect={vi.fn()}
|
||||
onRequestDelete={vi.fn()}
|
||||
onTogglePin={vi.fn()}
|
||||
onRequestRename={vi.fn()}
|
||||
onToggleArchive={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
const conversation = screen.getByRole("button", {
|
||||
name: "@mira Review the patch",
|
||||
});
|
||||
const handle = conversation.querySelector("[data-sidebar-session-handle]");
|
||||
expect(handle).toHaveClass("max-w-20", "shrink-0");
|
||||
const underline = handle?.querySelector("[data-sidebar-session-handle-underline]");
|
||||
expect(underline).toHaveClass("border-b-2", "text-foreground");
|
||||
expect(underline?.getAttribute("style"))
|
||||
.toContain(sessionHandleColor("handle_1234"));
|
||||
|
||||
const activeTrack = conversation.querySelector("[data-sidebar-selection-track]");
|
||||
expect(activeTrack).toHaveClass(
|
||||
"origin-left",
|
||||
"scale-x-100",
|
||||
"transition-transform",
|
||||
"motion-reduce:transition-none",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps handle columns intact inside grouped panes", () => {
|
||||
render(
|
||||
<ChatList
|
||||
sessions={[session({
|
||||
key: "tab:group",
|
||||
chatId: "workbench-tab:group",
|
||||
title: "Grouped work",
|
||||
})]}
|
||||
activeKey="websocket:root"
|
||||
paneGroups={{
|
||||
"tab:group": {
|
||||
tabKey: "tab:group",
|
||||
title: "Grouped work",
|
||||
activePaneKey: "websocket:root",
|
||||
visible: true,
|
||||
panes: [
|
||||
{
|
||||
key: "websocket:root",
|
||||
chatId: "root",
|
||||
title: "Short",
|
||||
handle: { id: "handle_1234", name: "mira" },
|
||||
},
|
||||
{
|
||||
key: "websocket:child",
|
||||
chatId: "child",
|
||||
title: "A much longer conversation title",
|
||||
handle: { id: "handle_5678", name: "nora" },
|
||||
},
|
||||
],
|
||||
},
|
||||
}}
|
||||
onSelect={vi.fn()}
|
||||
onRequestDelete={vi.fn()}
|
||||
onTogglePin={vi.fn()}
|
||||
onRequestRename={vi.fn()}
|
||||
onToggleArchive={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole("button", { name: "@mira Short" }))
|
||||
.toHaveTextContent("@mira");
|
||||
expect(screen.getByRole("button", { name: "@nora A much longer conversation title" }))
|
||||
.toHaveTextContent("@nora");
|
||||
for (const handle of document.querySelectorAll("[data-sidebar-session-handle]")) {
|
||||
expect(handle).toHaveClass("max-w-20", "shrink-0");
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps tab grouping out of drag protocols while exposing inactive panes as mention sources", () => {
|
||||
render(
|
||||
<ChatList
|
||||
|
||||
Reference in New Issue
Block a user