From 458e326ff7068dc01092bf8a604555ee5d5fb43d Mon Sep 17 00:00:00 2001 From: Steve Sewell Date: Tue, 14 Apr 2026 17:13:42 -0700 Subject: [PATCH 1/2] updates-99: fix stuck-loading after stop + chart/sidebar polish - AssistantChat: nuclear stop now also unblocks submission (sets isRunning=false immediately), fixing the "queueing forever" state after a tab refresh + stop during reconnect. Moves the stop button to extraActionButton and tones down its color so it doesn't compete with send. - TiptapComposer / SqlChart / SqlChartCard: small UI polish. --- packages/core/src/client/AssistantChat.tsx | 33 ++++++++----------- .../src/client/composer/TiptapComposer.tsx | 4 +++ .../app/components/dashboard/SqlChart.tsx | 3 ++ .../adhoc/sql-dashboard/SqlChartCard.tsx | 2 +- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/packages/core/src/client/AssistantChat.tsx b/packages/core/src/client/AssistantChat.tsx index 69f1d752..f7ebc9e7 100644 --- a/packages/core/src/client/AssistantChat.tsx +++ b/packages/core/src/client/AssistantChat.tsx @@ -1057,18 +1057,17 @@ const AssistantChatInner = forwardRef< const [reconnectFrozen, setReconnectFrozen] = useState(false); const reconnectRunIdRef = useRef(null); const reconnectAbortRef = useRef(null); - // Nuclear stop: user clicked stop but runtime hasn't cleared yet. - // This ONLY affects UI display (button + thinking indicator). Submission - // and queue gating still use the real `isRunning` so we never overlap a - // new run on top of one that's still cancelling on the server. + // Nuclear stop: user clicked stop. Clears the stop button/indicator AND + // lets new submissions go through immediately — prevents the "stuck + // queueing forever" state where isReconnecting or isRuntimeRunning gets + // wedged (e.g. after a tab refresh + stop during reconnect). const [forceStopped, setForceStopped] = useState(false); // Real running state — drives submission/queue gating. Treat reconnecting - // to an active run the same as running. - const isRunning = isRuntimeRunning || isReconnecting; + // to an active run the same as running, UNLESS the user has explicitly + // clicked stop (forceStopped). + const isRunning = !forceStopped && (isRuntimeRunning || isReconnecting); // UI-only running state — drives the stop button and thinking indicator. - // forceStopped lets us flip the indicator off immediately even if the - // underlying runtime or reconnect state hasn't caught up yet. - const showRunningInUI = !forceStopped && isRunning; + const showRunningInUI = isRunning; const wasRunningRef = useRef(false); const tiptapRef = useRef(null); @@ -1800,34 +1799,30 @@ const AssistantChatInner = forwardRef< onSlashCommand={onSlashCommand} execMode={execMode} onExecModeChange={onExecModeChange} - actionButton={ + extraActionButton={ showRunningInUI ? (