From 6c6d6f67e7849e47f704125886f75e4af3f9a4aa Mon Sep 17 00:00:00 2001 From: iris Date: Fri, 5 Jun 2026 11:39:35 +0200 Subject: [PATCH] fix(dashboard): preserve q-history details open state on SSE-triggered renderQuestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a question_added or question_resolved SSE event fires, the handler calls renderQuestions() directly — bypassing the snapshotOpenDetails / restoreOpenDetails pair that refreshState wraps around it. This caused the answered-history
(data-restore-key="q-history") to collapse every time a question arrived or was resolved while the operator had it open. Fix: call snapshotOpenDetails() at the start of renderQuestions() and restoreOpenDetails() at the end. The double-restore in the refreshState path is harmless — re-opening an already-open
is idempotent, and restoreOpenDetails is a no-op when the snapshot set is empty. --- frontend/packages/dashboard/src/tabs.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/packages/dashboard/src/tabs.js b/frontend/packages/dashboard/src/tabs.js index f8fb9bd8..60feefbb 100644 --- a/frontend/packages/dashboard/src/tabs.js +++ b/frontend/packages/dashboard/src/tabs.js @@ -1564,6 +1564,13 @@ window.marked = marked; // no-op when the section is missing. `question_added` / // `question_resolved` SSE events route through here. if (!root) return; + // Snapshot open
state before wiping the DOM so SSE-triggered + // calls (applyQuestionAdded / applyQuestionResolved) preserve it just + // as well as the full refreshState path. The double-restore that happens + // when renderQuestions is called from inside refreshState is harmless — + // restoreOpenDetails is a no-op when the set is empty, and re-opening an + // already-open
is idempotent. + const openDetails = snapshotOpenDetails(); root.replaceChildren(); const fmt = (n) => new Date(n * 1000).toISOString().replace('T', ' ').slice(0, 19); const allPending = questionsState.pending; @@ -1741,6 +1748,7 @@ window.marked = marked; details.append(hul); root.append(details); } + restoreOpenDetails(openDetails); } // Format a remaining-seconds count as the `⏳ …` TTL chip text on a