Add receiver health UX, fix restart crash, add interface scan selector
Receiver management improvements for the admin Receivers tab: - Per-receiver health: server now tracks each connection's state (connecting/connected/down), message count, and last-message time, exposed via new GET /api/admin/receiver-status and POST /api/admin/test-receivers. - Receivers tab redesign: live "Active Receivers" panel with colored indicators (green=receiving, yellow=connected/no data, red=unreachable), a clear select -> SAVE & APPLY -> auto-test flow, and selectable scan results with a "USE SELECTED RECEIVERS" action. - Network scan interface selector: scan a chosen interface/subnet instead of every local subnet. Oversized subnets (>/20, e.g. a docker /16) are disabled in the UI and rejected server-side, eliminating slow/hanging scans. Critical fix — server crash on receiver restart: - Receiver connection tasks were awaited inside main()'s top-level asyncio.gather. Restarting receivers cancels those tasks, and the resulting CancelledError propagated into the gather and killed the whole server process (every action after a restart then failed). Receiver tasks now run as independent background tasks; restart cancels and awaits them with return_exceptions=True so cancellation can never tear down the server. Also cache-bust admin.css/admin.js/pixel-editor.js (?v=) so updated assets load without a manual hard-refresh, and surface a clear message instead of a silent "Loading…" when the status endpoint is unavailable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -592,6 +592,99 @@ textarea {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* ===================================================================
|
||||
Receivers tab — status indicators & selectable scan results
|
||||
=================================================================== */
|
||||
.rx-section-label {
|
||||
font-family: 'Press Start 2P', monospace;
|
||||
font-size: 10px;
|
||||
color: #fcd444;
|
||||
margin: 22px 0 12px;
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid rgba(92, 148, 252, 0.3);
|
||||
}
|
||||
|
||||
.rx-summary {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
color: #b4d4ec;
|
||||
}
|
||||
|
||||
#receiver-status-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.rx-status-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid rgba(92, 148, 252, 0.4);
|
||||
border-radius: 6px;
|
||||
padding: 8px 12px;
|
||||
font-size: 13px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.rx-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 0 6px currentColor;
|
||||
}
|
||||
.rx-dot.green { background: #54fc54; color: #54fc54; }
|
||||
.rx-dot.yellow { background: #fcd444; color: #fcd444; }
|
||||
.rx-dot.red { background: #fc5454; color: #fc5454; }
|
||||
.rx-dot.gray { background: #888; color: #888; box-shadow: none; }
|
||||
|
||||
.rx-ip {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-weight: bold;
|
||||
color: #fcfcfc;
|
||||
min-width: 110px;
|
||||
}
|
||||
|
||||
.rx-label {
|
||||
font-family: 'Press Start 2P', monospace;
|
||||
font-size: 8px;
|
||||
}
|
||||
.rx-green { color: #54fc54; }
|
||||
.rx-yellow { color: #fcd444; }
|
||||
.rx-red { color: #fc5454; }
|
||||
.rx-gray { color: #888; }
|
||||
|
||||
.rx-detail {
|
||||
color: #b4d4ec;
|
||||
font-size: 11px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.rx-scan-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 6px 4px;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rgba(92, 148, 252, 0.2);
|
||||
}
|
||||
|
||||
.rx-scan-item input[type="checkbox"] {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
accent-color: #fcd444;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.rx-scan-ip {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-weight: bold;
|
||||
color: #fcfcfc;
|
||||
}
|
||||
|
||||
/* ===================================================================
|
||||
Pixel Editor
|
||||
=================================================================== */
|
||||
|
||||
Reference in New Issue
Block a user