feat(admin): per-unit live-monitoring (keepalive) toggle on /admin/slmm
Adds a "Live Monitoring (keepalive)" card listing each SLMM device with its
monitor_enabled state and an Enable/Disable toggle. Reads from /api/slmm/roster
(now includes monitor_enabled) and POSTs to /api/slmm/{unit}/monitor/{start,stop},
which persist the flag in SLMM (survives restarts; auto-started on boot). Shows a
reachability dot + 24/7 ON/OFF badge.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Live Monitoring (keepalive) -->
|
||||
<div class="rounded-xl bg-white dark:bg-slate-800 shadow-lg p-4 mb-6">
|
||||
<h2 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider mb-1">Live Monitoring (keepalive)</h2>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mb-3">
|
||||
Keepalive runs the 1 Hz DOD feed 24/7 (even with no viewer), which powers the live-chart
|
||||
trail and continuous threshold alerts. Toggling persists and survives restarts.
|
||||
</p>
|
||||
<div id="monitor-list" class="text-sm">
|
||||
<p class="text-gray-500 dark:text-gray-400">Loading…</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Raw API tester -->
|
||||
<div class="rounded-xl bg-white dark:bg-slate-800 shadow-lg p-4 mb-6">
|
||||
<h2 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider mb-3">Raw API Tester</h2>
|
||||
@@ -132,7 +144,60 @@ async function sendRaw() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadMonitors() {
|
||||
const el = document.getElementById('monitor-list');
|
||||
try {
|
||||
const r = await fetch('/api/slmm/roster');
|
||||
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||
const d = await r.json();
|
||||
const devices = d.devices || [];
|
||||
if (!devices.length) {
|
||||
el.innerHTML = '<p class="text-gray-500 dark:text-gray-400">No devices configured.</p>';
|
||||
return;
|
||||
}
|
||||
el.innerHTML = devices.map(dev => {
|
||||
const on = !!dev.monitor_enabled;
|
||||
const reach = dev.status ? dev.status.is_reachable : null;
|
||||
const reachDot = reach === false
|
||||
? '<span class="w-2 h-2 rounded-full bg-red-500 inline-block" title="unreachable"></span>'
|
||||
: '<span class="w-2 h-2 rounded-full bg-green-500 inline-block" title="reachable"></span>';
|
||||
return `
|
||||
<div class="flex items-center justify-between border-b border-gray-100 dark:border-gray-700 py-2">
|
||||
<div class="flex items-center gap-2">
|
||||
${reachDot}
|
||||
<span class="font-mono text-gray-900 dark:text-white">${_esc(dev.unit_id)}</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">${_esc(dev.host)}:${_esc(dev.tcp_port)}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-xs font-medium px-2 py-0.5 rounded ${on
|
||||
? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300'
|
||||
: 'bg-gray-100 text-gray-600 dark:bg-slate-700 dark:text-gray-400'}">${on ? '24/7 ON' : 'OFF'}</span>
|
||||
<button onclick="toggleMonitor('${_esc(dev.unit_id)}', ${!on})"
|
||||
class="px-3 py-1 text-xs rounded text-white ${on
|
||||
? 'bg-red-600 hover:bg-red-700' : 'bg-seismo-orange hover:bg-orange-600'}">
|
||||
${on ? 'Disable' : 'Enable'}
|
||||
</button>
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
} catch (e) {
|
||||
el.innerHTML = `<p class="text-red-600 dark:text-red-400">Failed to load devices: ${_esc(e.message)}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleMonitor(unitId, enable) {
|
||||
const action = enable ? 'start' : 'stop';
|
||||
try {
|
||||
const r = await fetch(`/api/slmm/${encodeURIComponent(unitId)}/monitor/${action}`, { method: 'POST' });
|
||||
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||
await loadMonitors();
|
||||
} catch (e) {
|
||||
alert('Toggle failed: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
loadSlmmOverview();
|
||||
setInterval(loadSlmmOverview, 30000);
|
||||
loadMonitors();
|
||||
setInterval(() => { loadSlmmOverview(); loadMonitors(); }, 30000);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user