Feat: add SLM live monitoring improvements #60
@@ -42,6 +42,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 -->
|
<!-- Raw API tester -->
|
||||||
<div class="rounded-xl bg-white dark:bg-slate-800 shadow-lg p-4 mb-6">
|
<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>
|
<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();
|
loadSlmmOverview();
|
||||||
setInterval(loadSlmmOverview, 30000);
|
loadMonitors();
|
||||||
|
setInterval(() => { loadSlmmOverview(); loadMonitors(); }, 30000);
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user