feat(webui): drag sessions into composer mentions
This commit is contained in:
@@ -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 { SESSION_DRAG_TYPE } from "@/lib/session-drag";
|
||||
import type { ChatSummary } from "@/lib/types";
|
||||
|
||||
function session(overrides: Partial<ChatSummary>): ChatSummary {
|
||||
@@ -47,6 +48,39 @@ describe("ChatList", () => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it("exposes inactive chats as session mention drag sources", () => {
|
||||
const dataTransfer = {
|
||||
effectAllowed: "",
|
||||
setData: vi.fn(),
|
||||
};
|
||||
render(
|
||||
<ChatList
|
||||
sessions={[
|
||||
session({ chatId: "active", title: "Active chat" }),
|
||||
session({ chatId: "reference", title: "Reference chat" }),
|
||||
]}
|
||||
activeKey="websocket:active"
|
||||
onSelect={vi.fn()}
|
||||
onRequestDelete={vi.fn()}
|
||||
onTogglePin={vi.fn()}
|
||||
onRequestRename={vi.fn()}
|
||||
onToggleArchive={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole("button", { name: "Active chat" }))
|
||||
.toHaveAttribute("draggable", "false");
|
||||
const reference = screen.getByRole("button", { name: "Reference chat" });
|
||||
expect(reference).toHaveAttribute("draggable", "true");
|
||||
|
||||
fireEvent.dragStart(reference, { dataTransfer });
|
||||
|
||||
expect(dataTransfer.setData).toHaveBeenCalledWith(
|
||||
SESSION_DRAG_TYPE,
|
||||
"websocket:reference",
|
||||
);
|
||||
});
|
||||
|
||||
it("orders chats by latest session activity by default", () => {
|
||||
const sessions = [
|
||||
session({
|
||||
|
||||
@@ -3,6 +3,7 @@ import userEvent from "@testing-library/user-event";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { ThreadComposer } from "@/components/thread/ThreadComposer";
|
||||
import { SESSION_DRAG_TYPE } from "@/lib/session-drag";
|
||||
import type { ChatSummary, CliAppInfo, McpPresetInfo, SlashCommand } from "@/lib/types";
|
||||
|
||||
vi.mock("@/lib/imageEncode", () => ({
|
||||
@@ -1593,6 +1594,47 @@ describe("ThreadComposer", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("turns a dropped sidebar session into the shared structured mention", () => {
|
||||
const onSend = vi.fn();
|
||||
render(
|
||||
<ThreadComposer
|
||||
onSend={onSend}
|
||||
placeholder="Type your message..."
|
||||
sessions={[session("pricing", "收费设计", "讨论云存储")]}
|
||||
/>,
|
||||
);
|
||||
|
||||
const input = screen.getByLabelText("Message input") as HTMLTextAreaElement;
|
||||
fireEvent.change(input, { target: { value: "Compare notes" } });
|
||||
input.setSelectionRange(7, 7);
|
||||
const dataTransfer = {
|
||||
types: [SESSION_DRAG_TYPE],
|
||||
effectAllowed: "copy",
|
||||
dropEffect: "none",
|
||||
files: [],
|
||||
getData: (type: string) => (
|
||||
type === SESSION_DRAG_TYPE ? "websocket:pricing" : ""
|
||||
),
|
||||
};
|
||||
|
||||
fireEvent.dragEnter(input, { dataTransfer });
|
||||
fireEvent.dragOver(input, { dataTransfer });
|
||||
fireEvent.drop(input, { dataTransfer });
|
||||
|
||||
expect(input).toHaveValue("Compare @收费设计 notes");
|
||||
expect(screen.getByTestId("composer-session-mention-收费设计"))
|
||||
.toHaveTextContent("@收费设计");
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Send message" }));
|
||||
expect(onSend).toHaveBeenCalledWith("Compare @收费设计 notes", undefined, {
|
||||
sessionMentions: [{
|
||||
name: "收费设计",
|
||||
session_key: "websocket:pricing",
|
||||
title: "收费设计",
|
||||
}],
|
||||
});
|
||||
});
|
||||
|
||||
it("disambiguates duplicate and capability-colliding session names", () => {
|
||||
render(
|
||||
<ThreadComposer
|
||||
|
||||
Reference in New Issue
Block a user