From 9799859eca0c0710c065b29b0034493f81c9e0c0 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Thu, 19 Feb 2026 08:55:41 -0800 Subject: [PATCH] fix(gateway-ui): preserve assistant overrides and bust stale cache --- src/gateway/ui/pages/dashboard.js | 43 ++++++++++++++++++++++++++----- src/gateway/ui/style.css | 6 ++--- src/gateway/ui/sw.js | 2 +- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/gateway/ui/pages/dashboard.js b/src/gateway/ui/pages/dashboard.js index ac73cbf..d77997a 100644 --- a/src/gateway/ui/pages/dashboard.js +++ b/src/gateway/ui/pages/dashboard.js @@ -11,6 +11,8 @@ let _dashboardClient = null; let _lastPlaybookRollbackPatches = null; let _lastBriefingTestAt = null; let _assistantSaveState = null; +let _lastAssistantConfig = null; +let _assistantManualOverrides = new Set(); function formatUptime(seconds) { const d = Math.floor(seconds / 86400); @@ -77,7 +79,7 @@ function getAssistantStateSnapshot(configData) { function buildPlaybookPatches(playbook) { if (playbook === 'executive') { - return { + const patches = { 'automation.delivery_mode': 'announce', 'automation.daily_briefing.enabled': true, 'memory.daily_log.enabled': true, @@ -87,9 +89,13 @@ function buildPlaybookPatches(playbook) { 'tts.enabled_channels': [], 'server.queue.mode': 'interrupt', }; + for (const key of _assistantManualOverrides) { + delete patches[key]; + } + return patches; } if (playbook === 'operator') { - return { + const patches = { 'automation.delivery_mode': 'announce', 'automation.daily_briefing.enabled': true, 'memory.daily_log.enabled': true, @@ -98,8 +104,12 @@ function buildPlaybookPatches(playbook) { 'tts.enabled': false, 'server.queue.mode': 'steer_backlog', }; + for (const key of _assistantManualOverrides) { + delete patches[key]; + } + return patches; } - return { + const patches = { 'automation.delivery_mode': 'shared_session', 'automation.daily_briefing.enabled': false, 'memory.daily_log.enabled': false, @@ -108,6 +118,10 @@ function buildPlaybookPatches(playbook) { 'tts.enabled': false, 'server.queue.mode': 'collect', }; + for (const key of _assistantManualOverrides) { + delete patches[key]; + } + return patches; } function buildRollbackPatchesFromSnapshot(snapshot) { @@ -792,14 +806,19 @@ function updateAssistantHealth(configData) { let patches = null; if (action === 'toggle-announce') { patches = { 'automation.delivery_mode': announce ? 'shared_session' : 'announce' }; + _assistantManualOverrides.add('automation.delivery_mode'); } else if (action === 'toggle-daily-briefing') { patches = { 'automation.daily_briefing.enabled': !dailyBriefing }; + _assistantManualOverrides.add('automation.daily_briefing.enabled'); } else if (action === 'toggle-memory-daily') { patches = { 'memory.daily_log.enabled': !memoryDaily }; + _assistantManualOverrides.add('memory.daily_log.enabled'); } else if (action === 'toggle-memory-proactive') { patches = { 'memory.proactive_extract.enabled': !memoryProactive }; + _assistantManualOverrides.add('memory.proactive_extract.enabled'); } else if (action === 'toggle-tts') { patches = { 'tts.enabled': !ttsEnabled }; + _assistantManualOverrides.add('tts.enabled'); } else if (action === 'test-daily-briefing') { await triggerDailyBriefingTest(briefingName, statusEl); } else if (action === 'playbook-executive') { @@ -836,6 +855,7 @@ function updateAssistantHealth(configData) { 'automation.daily_briefing.output.peer': peer, 'automation.daily_briefing.enabled': true, }; + _assistantManualOverrides.add('automation.daily_briefing.enabled'); } if (!patches) {return;} await applyAssistantPatch(patches, statusEl); @@ -845,8 +865,13 @@ function updateAssistantHealth(configData) { updateServices(refreshed.services); updateSessionAnalytics(refreshed.sessionAnalytics); updateContextHealth(refreshed.contextUsage); - // Capture status message before re-render destroys the DOM element - updateAssistantHealth(refreshed.config); + // Only re-render assistant controls from a confirmed config snapshot. + if (refreshed.config) { + _lastAssistantConfig = refreshed.config; + updateAssistantHealth(_lastAssistantConfig); + } else if (_lastAssistantConfig) { + updateAssistantHealth(_lastAssistantConfig); + } } }); }); @@ -980,7 +1005,8 @@ async function loadDashboard(el, client) { updateContextHealth(slow.contextUsage); } if (slow?.config) { - updateAssistantHealth(slow.config); + _lastAssistantConfig = slow.config; + updateAssistantHealth(_lastAssistantConfig); } // Fast refresh: 3 seconds for metrics, events, requests @@ -1012,7 +1038,8 @@ async function loadDashboard(el, client) { updateContextHealth(data.contextUsage); } if (data.config) { - updateAssistantHealth(data.config); + _lastAssistantConfig = data.config; + updateAssistantHealth(_lastAssistantConfig); } }, 10000); } @@ -1037,5 +1064,7 @@ export const DashboardPage = { _lastPlaybookRollbackPatches = null; _lastBriefingTestAt = null; _assistantSaveState = null; + _lastAssistantConfig = null; + _assistantManualOverrides = new Set(); }, }; diff --git a/src/gateway/ui/style.css b/src/gateway/ui/style.css index 1f376a0..e587ef0 100644 --- a/src/gateway/ui/style.css +++ b/src/gateway/ui/style.css @@ -74,10 +74,8 @@ color: white; } -/* ---------- Hidden utility ---------- */ -.hidden { - display: none !important; -} +/* Tailwind provides .hidden natively — do NOT re-declare here. + An !important rule would conflict with responsive overrides (md:flex). */ /* ---------- Links ---------- */ a { diff --git a/src/gateway/ui/sw.js b/src/gateway/ui/sw.js index 31fc6ee..02d0246 100644 --- a/src/gateway/ui/sw.js +++ b/src/gateway/ui/sw.js @@ -1,4 +1,4 @@ -const CACHE_NAME = 'flynn-webchat-v3'; +const CACHE_NAME = 'flynn-webchat-v5'; const token = new URL(self.location.href).searchParams.get('token'); const withToken = (path) => { if (!token) {