mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 00:19:42 +02:00
feat(web): make a dead connection unmistakable instead of a red dot
Opening Codeman with nothing reachable (phone off the tailnet, VPN down, server stopped) rendered a normal-looking UI: the service worker serves the cached app shell, every /api call fails, and the only tell was an 8px red dot in the header corner. On a phone that reads as "there are no sessions". Two surfaces, chosen by whether there is anything worth looking at: - Full-screen overlay while no server state has loaded this page load. It names the host, lists the three things to check (network, VPN/Tailscale, server), counts down to the next retry, and offers "Retry now" plus "Show cached view" to demote itself to the banner. - Non-blocking banner once state HAS loaded, so a mid-session drop leaves the terminal scrollback readable. A 2.5s grace keeps a COM deploy (SSE is back in ~200ms) from flashing the banner every release; navigator.onLine === false skips the grace, since the device saying "no network" is never a blip. Retry re-arms the terminal WebSocket as well as SSE: planWsReconnect can give up outright, and the SSE backoff caps at 30s, so waiting it out is not always an option. The decision is pure (computeConnectionLossUi in constants.js, unit-tested in a node VM like the WS reconnect policy); app.js only writes the DOM.
This commit is contained in:
@@ -149,6 +149,16 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Connection-loss banner: shown once session state HAS loaded and the
|
||||
link then drops, so the terminal stays readable behind it.
|
||||
The blocking variant is #offlineOverlay at the end of <body>. -->
|
||||
<div class="offline-banner" id="offlineBanner" role="status" hidden>
|
||||
<span class="offline-banner-dot" aria-hidden="true"></span>
|
||||
<span class="offline-banner-text" id="offlineBannerText">No connection to the Codeman server</span>
|
||||
<span class="offline-banner-detail" id="offlineBannerDetail"></span>
|
||||
<button class="offline-banner-retry" id="offlineBannerRetry" onclick="app.retryConnection()">Retry now</button>
|
||||
</div>
|
||||
|
||||
<!-- Timer Banner (shown when timed run is active) -->
|
||||
<div class="timer-banner" id="timerBanner" style="display: none;">
|
||||
<div class="timer-content">
|
||||
@@ -2679,6 +2689,39 @@
|
||||
<!-- Lines drawn dynamically -->
|
||||
</svg>
|
||||
|
||||
<!-- Connection-loss overlay: the app shell is served from the service-worker
|
||||
cache, so Codeman renders even with nothing reachable. Without this, that
|
||||
looks like an empty dashboard rather than a dead connection. Only shown
|
||||
while no server state has loaded this page load. -->
|
||||
<div class="offline-overlay" id="offlineOverlay" hidden>
|
||||
<div class="offline-overlay-card" role="alertdialog" aria-labelledby="offlineOverlayTitle" aria-describedby="offlineOverlayBody">
|
||||
<div class="offline-overlay-icon" aria-hidden="true">
|
||||
<svg width="46" height="46" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M1 1l22 22"/>
|
||||
<path d="M16.72 11.06A10.94 10.94 0 0 1 19 12.55"/>
|
||||
<path d="M5 12.55a10.94 10.94 0 0 1 5.17-2.39"/>
|
||||
<path d="M10.71 5.05A16 16 0 0 1 22.58 9"/>
|
||||
<path d="M1.42 9a15.91 15.91 0 0 1 4.7-2.88"/>
|
||||
<path d="M8.53 16.11a6 6 0 0 1 6.95 0"/>
|
||||
<line x1="12" y1="20" x2="12.01" y2="20"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="offline-overlay-title" id="offlineOverlayTitle">Can't reach the Codeman server</h2>
|
||||
<p class="offline-overlay-body" id="offlineOverlayBody"></p>
|
||||
<div class="offline-overlay-host" id="offlineOverlayHost"></div>
|
||||
<ul class="offline-overlay-hints">
|
||||
<li>Check Wi-Fi or mobile data</li>
|
||||
<li>Check your VPN / Tailscale is connected</li>
|
||||
<li>Check the Codeman server is still running</li>
|
||||
</ul>
|
||||
<div class="offline-overlay-actions">
|
||||
<button class="offline-overlay-btn offline-overlay-btn--primary" id="offlineOverlayRetry" onclick="app.retryConnection()">Retry now</button>
|
||||
<button class="offline-overlay-btn" onclick="app.dismissOfflineOverlay()">Show cached view</button>
|
||||
</div>
|
||||
<div class="offline-overlay-status" id="offlineOverlayStatus">Retrying…</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script defer src="constants.js"></script>
|
||||
<script defer src="i18n.js"></script>
|
||||
<script defer src="mobile-handlers.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user