Skip to content

Commit 9f537a9

Browse files
Angfr95Angfr95
authored andcommitted
fix(ui): disable chat refresh button during active agent turn
The refresh button was only guarded by chatLoading and connected state, allowing clicks during active agent turns. This could stall the run, reset chat state, and wedge the gateway. Add chatSending, chatRunId, and chatStream guards to match the existing busy-state pattern used by the model and thinking selects. Fixes #65522
1 parent bd48e57 commit 9f537a9

2 files changed

Lines changed: 22 additions & 12 deletions

File tree

extensions/slack/src/monitor/provider.gateway-crash.test.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
1-
import { describe, it, expect, vi } from "vitest";
2-
import { monitorSlackProvider } from "./provider.js";
1+
import { describe, expect, it, vi } from "vitest";
32

43
vi.mock("@slack/bolt", () => {
4+
class SocketModeReceiver {
5+
requestListener = vi.fn();
6+
}
7+
class HTTPReceiver {
8+
requestListener = vi.fn();
9+
}
510
class App {
6-
client = {
7-
auth: {
8-
test: vi.fn().mockResolvedValue({ user_id: "U123", team_id: "T123", api_app_id: "A123" }),
9-
},
10-
};
11-
start = vi.fn().mockRejectedValue(new Error("An API error occurred: account_inactive"));
12-
stop = vi.fn().mockResolvedValue(undefined);
11+
receiver: unknown;
12+
constructor(opts: { receiver?: unknown } = {}) {
13+
this.receiver = opts.receiver;
14+
}
15+
use = vi.fn();
1316
event = vi.fn();
1417
message = vi.fn();
1518
action = vi.fn();
1619
shortcut = vi.fn();
1720
command = vi.fn();
1821
error = vi.fn();
22+
start = vi.fn().mockRejectedValue(new Error("An API error occurred: account_inactive"));
23+
stop = vi.fn().mockResolvedValue(undefined);
1924
}
20-
class HTTPReceiver {requestListener = vi.fn();}
21-
return { default: App, App, HTTPReceiver };
25+
return { default: App, App, HTTPReceiver, SocketModeReceiver };
2226
});
2327

2428
vi.mock("../accounts.js", () => ({
@@ -31,6 +35,12 @@ vi.mock("../accounts.js", () => ({
3135
}),
3236
}));
3337

38+
vi.mock("../client.js", () => ({
39+
resolveSlackWebClientOptions: vi.fn().mockReturnValue({}),
40+
}));
41+
42+
import { monitorSlackProvider } from "./provider.js";
43+
3444
describe("monitorSlackProvider - gateway crash prevention", () => {
3545
it("resolves instead of rejecting on non-recoverable auth error", async () => {
3646
await expect(

ui/src/ui/app-render.helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ export function renderChatControls(state: AppViewState) {
237237
<div class="chat-controls">
238238
<button
239239
class="btn btn--sm btn--icon"
240-
?disabled=${state.chatLoading || !state.connected}
240+
?disabled=${state.chatLoading || !state.connected || state.chatSending || Boolean(state.chatRunId) || state.chatStream !== null}
241241
@click=${async () => {
242242
const app = state as unknown as ChatRefreshHost;
243243
app.chatManualRefreshInFlight = true;

0 commit comments

Comments
 (0)