Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions apps/web/src/components/chat/MessagesTimeline.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1764,4 +1764,53 @@ describe("MessagesTimeline", () => {
expect(markup).toContain("lucide-circle-alert");
expect(markup).toContain("text-destructive");
});

it("only withholds an expanded tool-call label click while text is selected", async () => {
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
vi.stubGlobal("requestAnimationFrame", () => 0);
vi.stubGlobal("cancelAnimationFrame", () => {});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
let renderer: ReactTestRenderer | undefined;
try {
await act(() => {
renderer = create(
<MessagesTimeline
{...buildProps()}
timelineEntries={[
{
id: "entry-standalone",
kind: "work",
createdAt: MESSAGE_CREATED_AT,
entry: {
id: "work-standalone",
createdAt: MESSAGE_CREATED_AT,
toolCallId: "call-standalone",
label: "Run lint",
tone: "tool",
itemType: "command_execution",
command: "pnpm lint",
toolLifecycleStatus: "completed",
},
},
]}
/>,
);
});
await act(() => renderer!.root.findByProps({ "aria-expanded": false }).props.onClick());
const label = renderer!.root.findAll(
(node) => node.type === "span" && String(node.props.className).includes("select-text"),
)[0];
const stopPropagation = vi.fn();
// Only the click that ends a selection may be withheld from the row
// toggle; the plain click has to reach it so the label can collapse.
for (const isCollapsed of [false, true]) {
label!.props.onClick({
currentTarget: { ownerDocument: { getSelection: () => ({ isCollapsed }) } },
stopPropagation,
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
expect(stopPropagation).toHaveBeenCalledTimes(1);
} finally {
await act(() => renderer?.unmount());
}
});
});
14 changes: 13 additions & 1 deletion apps/web/src/components/chat/MessagesTimeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3172,6 +3172,18 @@ function workEntryIconName(workEntry: TimelineWorkEntry): WorkEntryIconName {

const stopRowToggle = (e: { stopPropagation: () => void }) => e.stopPropagation();

/**
* Click handler for expanded row labels, which turn text selection back on.
* Only a click that ends a real selection is withheld from the row toggle, so
* an ordinary click on the label still bubbles and collapses the row it opened.
*/
const stopRowToggleWhileSelectingText = (e: MouseEvent<HTMLElement>) => {
const selection = e.currentTarget.ownerDocument.getSelection();
if (selection && !selection.isCollapsed) {
e.stopPropagation();
}
};

/**
* A1 spawn CTA: one anchored row per workflow run (or per-turn direct-spawn
* batch). Live status is derived from the shared agent panel model at render
Expand Down Expand Up @@ -3407,7 +3419,7 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: {
expanded ? "whitespace-pre-wrap break-words select-text" : "truncate",
headingClass,
)}
onClick={expanded ? stopRowToggle : undefined}
onClick={expanded ? stopRowToggleWhileSelectingText : undefined}
onPointerDown={expanded ? stopRowToggle : undefined}
>
{previewText}
Expand Down
Loading