authorgravatar for crazywolf132@gmail.com0x1f99d <crazywolf132@gmail.com> 2026-03-13 06:15:01+11:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-12 12:15:01-07:00
log224acebb57815193ef93c2d1861e606a626d23b3
tree169dbfa5f53cb8a98ee8fb604b8842cbdbaf26f2
parent85c174a6cac04b4fda68f311a904af0435c85807
signature Signed by PGP key B5690EEEBB952194

fix(web): add pointer cursor to running stop-generation button (#900)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

2 files changed, 26 insertions(+), 2 deletions(-)

apps/web/src/components/ChatView.browser.tsx+25-1
......@@ -11,6 +11,7 @@ import {
1111 type WsWelcomePayload,
1212 WS_CHANNELS,
1313 WS_METHODS,
14 OrchestrationSessionStatus,
1415} from "@t3tools/contracts";
1516import { RouterProvider, createMemoryHistory } from "@tanstack/react-router";
1617import { HttpResponse, http, ws } from "msw";
......@@ -153,6 +154,7 @@ function createSnapshotForTargetUser(options: {
153154 targetMessageId: MessageId;
154155 targetText: string;
155156 targetAttachmentCount?: number;
157 sessionStatus?: OrchestrationSessionStatus;
156158}): OrchestrationReadModel {
157159 const messages: Array<OrchestrationReadModel["threads"][number]["messages"][number]> = [];
158160
......@@ -222,7 +224,7 @@ function createSnapshotForTargetUser(options: {
222224 checkpoints: [],
223225 session: {
224226 threadId: THREAD_ID,
225 status: "ready",
227 status: options.sessionStatus ?? "ready",
226228 providerName: "codex",
227229 runtimeMode: "full-access",
228230 activeTurnId: null,
......@@ -1009,6 +1011,28 @@ describe("ChatView timeline estimator parity (full app)", () => {
10091011 }
10101012 });
10111013
1014 it("shows a pointer cursor for the running stop button", async () => {
1015 const mounted = await mountChatView({
1016 viewport: DEFAULT_VIEWPORT,
1017 snapshot: createSnapshotForTargetUser({
1018 targetMessageId: "msg-user-stop-button-cursor" as MessageId,
1019 targetText: "stop button cursor target",
1020 sessionStatus: "running",
1021 }),
1022 });
1023
1024 try {
1025 const stopButton = await waitForElement(
1026 () => document.querySelector<HTMLButtonElement>('button[aria-label="Stop generation"]'),
1027 "Unable to find stop generation button.",
1028 );
1029
1030 expect(getComputedStyle(stopButton).cursor).toBe("pointer");
1031 } finally {
1032 await mounted.cleanup();
1033 }
1034 });
1035
10121036 it("keeps the new thread selected after clicking the new-thread button", async () => {
10131037 const mounted = await mountChatView({
10141038 viewport: DEFAULT_VIEWPORT,
apps/web/src/components/ChatView.tsx+1-1
......@@ -3604,7 +3604,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
36043604 ) : phase === "running" ? (
36053605 <button
36063606 type="button"
3607 className="flex size-8 items-center justify-center rounded-full bg-rose-500/90 text-white transition-all duration-150 hover:bg-rose-500 hover:scale-105 sm:h-8 sm:w-8"
3607 className="flex size-8 cursor-pointer items-center justify-center rounded-full bg-rose-500/90 text-white transition-all duration-150 hover:bg-rose-500 hover:scale-105 sm:h-8 sm:w-8"
36083608 onClick={() => void onInterrupt()}
36093609 aria-label="Stop generation"
36103610 >