diff --git a/CHANGELOG.md b/CHANGELOG.md index f7e486f5..fe1f161d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Fixed -- **Offline recovery now verifies unreliable browser offline reports with the existing `/health` probe before showing or sticking on the browser-reason banner (#4170).** `navigator.onLine` is treated as a hint for the banner reason, while server reachability remains the source of truth, so browsers that incorrectly report offline can recover without a page reload or permanent connection-lost state. (#4170) +- **Offline recovery now verifies unreliable browser offline reports with the existing `/health` probe before showing or sticking on the browser-reason banner.** `navigator.onLine` is treated as a hint for the banner reason, while server reachability remains the source of truth, so browsers that incorrectly report offline can recover without a page reload or permanent connection-lost state. (#4170) ## [v0.51.410] — 2026-06-14 — Release NW (chat Mermaid lightbox + workspace CSV table preview, #4075/#4025) diff --git a/static/ui.js b/static/ui.js index 588ee007..cf84abec 100644 --- a/static/ui.js +++ b/static/ui.js @@ -86,7 +86,10 @@ async function _probeOfflineRecovery(){ finally{_offlineHealthProbePromise=null;} } async function _showOfflineBannerIfProbeFails(reason){ + const visibleAtStart=_offlineVisible; + if(visibleAtStart)_setOfflineChecking(true); const ok=await _probeOfflineRecovery(); + if(visibleAtStart)_setOfflineChecking(false); if(ok){ if(_offlineVisible){_stopOfflineProbeTimer();await _recoverFromOfflineSoftly();} return true; @@ -101,7 +104,7 @@ async function checkOfflineRecoveryNow(){ _setOfflineChecking(true); const ok=await _probeOfflineRecovery(); _setOfflineChecking(false); - if(ok){_stopOfflineProbeTimer();await _recoverFromOfflineSoftly();return true;} + if(ok){if(!_offlineVisible)return true;_stopOfflineProbeTimer();await _recoverFromOfflineSoftly();return true;} showOfflineBanner(_browserReportsOnline()?'network':'browser'); return false; })(); diff --git a/tests/test_4170_offline_probe.py b/tests/test_4170_offline_probe.py index 15801f3c..69217b8c 100644 --- a/tests/test_4170_offline_probe.py +++ b/tests/test_4170_offline_probe.py @@ -37,12 +37,16 @@ def test_recovery_loop_probes_even_when_browser_reports_offline(): assert "_probeOfflineRecovery()" in body assert "if(!_browserReportsOnline()){showOfflineBanner('browser');return false;}" not in body assert body.find("_probeOfflineRecovery()") < body.find("showOfflineBanner(") + assert "if(ok){if(!_offlineVisible)return true;_stopOfflineProbeTimer();await _recoverFromOfflineSoftly();return true;}" in body assert "showOfflineBanner(_browserReportsOnline()?'network':'browser')" in body def test_probe_backed_browser_banner_helper_uses_health_as_source_of_truth(): body = _strip_comments(_fn_body(UI_JS, "async function _showOfflineBannerIfProbeFails(")) + assert "const visibleAtStart=_offlineVisible;" in body + assert "if(visibleAtStart)_setOfflineChecking(true);" in body assert "const ok=await _probeOfflineRecovery();" in body + assert "if(visibleAtStart)_setOfflineChecking(false);" in body assert "if(ok)" in body assert "showOfflineBanner(reason||(_browserReportsOnline()?'network':'browser'))" in body assert body.find("_probeOfflineRecovery()") < body.find("showOfflineBanner(")