mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-07 21:08:34 +03:00
fix(webui): preserve session drag contracts
This commit is contained in:
@@ -221,7 +221,11 @@ export const ChatList = memo(function ChatList({
|
||||
const targetIndex = reordered.indexOf(targetKey);
|
||||
if (targetIndex < 0) return;
|
||||
reordered.splice(targetIndex + (edge === "after" ? 1 : 0), 0, draggedSessionKey);
|
||||
onReorderSessions(reordered);
|
||||
const groupedKeys = new Set(keys);
|
||||
onReorderSessions([
|
||||
...reordered,
|
||||
...sessionOrder.filter((key) => !groupedKeys.has(key)),
|
||||
]);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1730,9 +1730,8 @@ export function ThreadComposer({
|
||||
|
||||
const previewSessionDrop = useCallback((event: React.DragEvent) => {
|
||||
if (!hasDraggedSession(event.dataTransfer)) return false;
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = "copy";
|
||||
if (disabled) {
|
||||
event.dataTransfer.dropEffect = "none";
|
||||
setSessionDragPreview(null);
|
||||
return true;
|
||||
}
|
||||
@@ -1744,9 +1743,12 @@ export function ThreadComposer({
|
||||
(candidate) => candidate.session_key === mention.session_key,
|
||||
);
|
||||
if (!mention || (!alreadySelected && activeSessionMentions.length >= SESSION_MENTIONS_LIMIT)) {
|
||||
event.dataTransfer.dropEffect = "none";
|
||||
setSessionDragPreview(null);
|
||||
return true;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = "copy";
|
||||
const start = textareaRef.current?.selectionStart ?? value.length;
|
||||
const end = textareaRef.current?.selectionEnd ?? start;
|
||||
setSessionDragPreview((current) => (
|
||||
|
||||
@@ -88,6 +88,8 @@ describe("ChatList", () => {
|
||||
session({ chatId: "alpha", title: "Alpha" }),
|
||||
session({ chatId: "bravo", title: "Bravo" }),
|
||||
session({ chatId: "charlie", title: "Charlie" }),
|
||||
session({ chatId: "old-a", title: "Old A" }),
|
||||
session({ chatId: "old-b", title: "Old B" }),
|
||||
];
|
||||
const { rerender } = render(
|
||||
<ChatList
|
||||
@@ -99,6 +101,8 @@ describe("ChatList", () => {
|
||||
onRequestRename={vi.fn()}
|
||||
onToggleArchive={vi.fn()}
|
||||
onReorderSessions={onReorderSessions}
|
||||
archivedKeys={["websocket:old-a", "websocket:old-b"]}
|
||||
sessionOrder={sessions.map((item) => item.key)}
|
||||
/>,
|
||||
);
|
||||
const dataTransfer = {
|
||||
@@ -117,6 +121,8 @@ describe("ChatList", () => {
|
||||
"websocket:bravo",
|
||||
"websocket:charlie",
|
||||
"websocket:alpha",
|
||||
"websocket:old-a",
|
||||
"websocket:old-b",
|
||||
]);
|
||||
|
||||
rerender(
|
||||
@@ -129,10 +135,13 @@ describe("ChatList", () => {
|
||||
onRequestRename={vi.fn()}
|
||||
onToggleArchive={vi.fn()}
|
||||
onReorderSessions={onReorderSessions}
|
||||
archivedKeys={["websocket:old-a", "websocket:old-b"]}
|
||||
sessionOrder={[
|
||||
"websocket:bravo",
|
||||
"websocket:charlie",
|
||||
"websocket:alpha",
|
||||
"websocket:old-a",
|
||||
"websocket:old-b",
|
||||
]}
|
||||
sort="manual"
|
||||
/>,
|
||||
|
||||
@@ -1647,6 +1647,28 @@ describe("ThreadComposer", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects session drops that are unavailable to the composer", () => {
|
||||
render(
|
||||
<ThreadComposer
|
||||
onSend={vi.fn()}
|
||||
placeholder="Type your message..."
|
||||
sessions={[]}
|
||||
/>,
|
||||
);
|
||||
const input = screen.getByLabelText("Message input");
|
||||
const dataTransfer = {
|
||||
types: [SESSION_DRAG_TYPE],
|
||||
effectAllowed: "copyMove",
|
||||
dropEffect: "copy",
|
||||
files: [],
|
||||
getData: () => "websocket:current",
|
||||
};
|
||||
|
||||
expect(fireEvent.dragEnter(input, { dataTransfer })).toBe(true);
|
||||
expect(fireEvent.dragOver(input, { dataTransfer })).toBe(true);
|
||||
expect(screen.queryByTestId("composer-session-drag-preview")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("disambiguates duplicate and capability-colliding session names", () => {
|
||||
render(
|
||||
<ThreadComposer
|
||||
|
||||
Reference in New Issue
Block a user