refactor: harden diagnostics and consolidate runtime code

This commit is contained in:
Mikhail Chusavitin
2026-09-01 13:01:28 +03:00
parent ac4bc0b2b7
commit 0a6ca8ba0f
49 changed files with 1441 additions and 837 deletions
+67 -6
View File
@@ -150,8 +150,9 @@ setInterval(function(){
return b.String()
}
// renderTimeSyncCard shows the server's current time and a button that syncs
// the host clock and timezone to whatever the client's browser reports.
// renderTimeSyncCard shows the server's current clock and timezone next to the
// browser's own, highlights any drift, and offers a button that syncs the host
// clock and timezone to whatever the client's browser reports.
func renderTimeSyncCard() string {
return `<div class="card" style="margin-bottom:16px">
<div class="card-head card-head-actions">
@@ -161,11 +162,66 @@ func renderTimeSyncCard() string {
</div>
</div>
<div class="card-body">
<table style="font-size:13px;border-collapse:collapse">
<tr><td style="padding:2px 16px 2px 0;color:var(--muted)">Server</td>
<td style="padding:2px 24px 2px 0" id="time-server-clock">—</td>
<td style="padding:2px 0" id="time-server-tz">—</td></tr>
<tr><td style="padding:2px 16px 2px 0;color:var(--muted)">Browser</td>
<td style="padding:2px 24px 2px 0" id="time-browser-clock">—</td>
<td style="padding:2px 0" id="time-browser-tz">—</td></tr>
</table>
<div id="time-drift-note" style="font-size:13px;margin-top:8px"></div>
<span id="time-sync-status" style="font-size:13px;color:var(--muted)"></span>
</div>
</div>
<script>
function timeSyncRun() {
(function(){
var CRIT = 'var(--crit-fg,#9f3a38)';
var OK = 'var(--ok-fg,#2c662d)';
var refreshPending = false;
function refreshTime() {
var browserTz = Intl.DateTimeFormat().resolvedOptions().timeZone || '';
document.getElementById('time-browser-clock').textContent = new Date().toLocaleString();
document.getElementById('time-browser-tz').textContent = browserTz;
if (refreshPending) return Promise.resolve();
refreshPending = true;
return fetch('/api/system/time', {cache: 'no-store'})
.then(function(r){ if(!r.ok) throw new Error(r.statusText); return r.json(); })
.then(function(d){
var serverMs = d.epoch_ms;
var serverTz = d.timezone || '';
var skewMs = Math.abs(Date.now() - serverMs);
document.getElementById('time-server-clock').textContent = d.local_time || new Date(serverMs).toISOString();
document.getElementById('time-server-tz').textContent = serverTz;
var clockBad = skewMs > 60000;
var tzBad = serverTz !== browserTz;
document.getElementById('time-server-clock').style.color = clockBad ? CRIT : '';
document.getElementById('time-browser-clock').style.color = clockBad ? CRIT : '';
document.getElementById('time-server-tz').style.color = tzBad ? CRIT : '';
document.getElementById('time-browser-tz').style.color = tzBad ? CRIT : '';
var note = document.getElementById('time-drift-note');
if (clockBad || tzBad) {
var parts = [];
if (clockBad) parts.push('clock differs by ' + Math.round(skewMs/1000) + 's');
if (tzBad) parts.push('timezone mismatch');
note.style.color = CRIT;
note.textContent = '⚠ ' + parts.join(', ') + ' — click "Sync with this browser"';
} else {
note.style.color = OK;
note.textContent = '✓ server clock and timezone match this browser';
}
})
.catch(function(){
document.getElementById('time-server-clock').textContent = 'unavailable';
})
.finally(function(){ refreshPending = false; });
}
window.timeSyncRun = function() {
var btn = document.getElementById('time-sync-btn');
var status = document.getElementById('time-sync-status');
btn.disabled = true;
@@ -177,15 +233,20 @@ function timeSyncRun() {
})
.then(function(r) { if (!r.ok) return r.text().then(function(t){throw new Error(t || r.statusText);}); return r.json(); })
.then(function(d) {
status.style.color = 'var(--ok-fg,#2c662d)';
status.style.color = OK;
status.textContent = '✓ Synced to ' + tz + ' at ' + new Date().toLocaleString();
refreshTime();
})
.catch(function(err) {
status.style.color = 'var(--crit-fg,#9f3a38)';
status.style.color = CRIT;
status.textContent = '✗ Sync failed: ' + err.message;
})
.finally(function() { btn.disabled = false; });
}
};
refreshTime();
setInterval(refreshTime, 5000);
})();
</script>`
}