[feat](trx-frontend-http): add connection-lost overlay for trx-client and trx-server failures

Show a full-screen blurred overlay (reusing decode-history-overlay styles)
when the SSE connection to trx-client drops or when trx-server is reported
unreachable via server_connected=false.  The overlay distinguishes the two
failure modes with separate titles and sub-text.  It is dismissed on
es.onopen (trx-client back) or when a message with server_connected!=false
arrives (trx-server back), and cleared on explicit disconnect/logout.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
2026-03-16 23:44:18 +01:00
parent 84dc28cf77
commit 9fba303bd8
2 changed files with 24 additions and 2 deletions
@@ -334,6 +334,9 @@ const loadingSub = document.getElementById("loading-sub");
const decodeHistoryOverlayEl = document.getElementById("decode-history-overlay");
const decodeHistoryOverlayTitleEl = document.getElementById("decode-history-overlay-title");
const decodeHistoryOverlaySubEl = document.getElementById("decode-history-overlay-sub");
const connLostOverlayEl = document.getElementById("conn-lost-overlay");
const connLostOverlayTitleEl = document.getElementById("conn-lost-overlay-title");
const connLostOverlaySubEl = document.getElementById("conn-lost-overlay-sub");
const overviewCanvas = document.getElementById("overview-canvas");
const signalOverlayCanvas = document.getElementById("signal-overlay-canvas");
const overviewGl = typeof createTrxWebGlRenderer === "function"
@@ -401,6 +404,13 @@ function setDecodeHistoryOverlayVisible(visible, title = "", sub = "") {
if (decodeHistoryOverlaySubEl) decodeHistoryOverlaySubEl.textContent = sub || "";
decodeHistoryOverlayEl.classList.toggle("is-hidden", !visible);
}
function setConnLostOverlay(visible, title = "Connection lost", sub = "Retrying\u2026") {
if (!connLostOverlayEl) return;
if (connLostOverlayTitleEl) connLostOverlayTitleEl.textContent = title;
if (connLostOverlaySubEl) connLostOverlaySubEl.textContent = sub;
connLostOverlayEl.classList.toggle("is-hidden", !visible);
}
const decodeHistoryTextDecoder = typeof TextDecoder === "function" ? new TextDecoder() : null;
let decodeHistoryReplayActive = false;
let decodeMapSyncPending = false;
@@ -3093,6 +3103,7 @@ function connect() {
es = new EventSource("/events");
lastEventAt = Date.now();
es.onopen = () => {
setConnLostOverlay(false);
pollFreshSnapshot();
refreshRigList();
};
@@ -3105,8 +3116,10 @@ function connect() {
lastEventAt = Date.now();
if (data.server_connected === false) {
powerHint.textContent = "trx-server connection lost";
} else if (data.initialized) {
powerHint.textContent = readyText();
setConnLostOverlay(true, "trx-server connection lost", "trx-client is running but cannot reach the radio server");
} else {
setConnLostOverlay(false);
if (data.initialized) powerHint.textContent = readyText();
}
} catch (e) {
console.error("Bad event data", e);
@@ -3125,6 +3138,7 @@ function connect() {
// Check if this is an auth error by looking at readyState
if (es.readyState === EventSource.CLOSED) {
powerHint.textContent = "trx-client connection lost, retrying\u2026";
setConnLostOverlay(true, "trx-client connection lost", "Retrying\u2026");
es.close();
pollFreshSnapshot();
scheduleReconnect(1000);
@@ -3135,6 +3149,7 @@ function connect() {
const now = Date.now();
if (now - lastEventAt > 15000) {
powerHint.textContent = "trx-client connection lost, retrying\u2026";
setConnLostOverlay(true, "trx-client connection lost", "Retrying\u2026");
es.close();
pollFreshSnapshot();
scheduleReconnect(250);
@@ -3163,6 +3178,7 @@ function disconnect() {
reconnectTimer = null;
}
setDecodeHistoryOverlayVisible(false);
setConnLostOverlay(false);
}
// Yield the main thread so the browser can paint before heavy async work.
@@ -980,6 +980,12 @@
<div id="decode-history-overlay-sub" class="decode-history-overlay-sub">Preparing recent decodes for the UI</div>
</div>
</div>
<div id="conn-lost-overlay" class="decode-history-overlay is-hidden" aria-live="assertive" aria-atomic="true">
<div class="decode-history-overlay-card">
<div id="conn-lost-overlay-title" class="decode-history-overlay-title">Connection lost</div>
<div id="conn-lost-overlay-sub" class="decode-history-overlay-sub">Retrying…</div>
</div>
</div>
<script src="/webgl-renderer.js"></script>
<script src="/app.js"></script>
<script src="/ais.js"></script>