Files
appRobotConfig/public/js/status.js
Kendel Christoph 90d55cad7e Initial commit
2025-12-27 20:13:26 +01:00

116 lines
4.2 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Simple status dashboard
const DATA_URL = 'data/status.json';
let autoRefresh = true;
let refreshTimer = null;
function formatMB(mb) {
return `${mb.toFixed(2)} MB`;
}
function formatPercent(p) {
return `${p.toFixed(2)}%`;
}
function setRing(el, percent) {
const deg = Math.min(100, Math.max(0, percent)) * 3.6; // 100% -> 360deg
el.style.setProperty('--deg', `${deg}deg`);
}
function renderSystem(system) {
const cpuPercent = system?.cpu?.percent ?? 0;
const ring = document.getElementById('cpu-ring');
setRing(ring, cpuPercent);
document.getElementById('cpu-percent').textContent = formatPercent(cpuPercent);
const la = system?.cpu?.load_avg ?? {};
document.getElementById('load-1m').textContent = (la['1m'] ?? '');
document.getElementById('load-5m').textContent = (la['5m'] ?? '');
document.getElementById('load-15m').textContent = (la['15m'] ?? '');
const mem = system?.memory ?? {};
const pct = mem.percent ?? 0;
document.getElementById('mem-bar').style.width = `${pct}%`;
document.getElementById('mem-percent').textContent = formatPercent(pct);
document.getElementById('mem-used').textContent = formatMB(mem.used_mb ?? 0);
document.getElementById('mem-total').textContent = formatMB(mem.total_mb ?? 0);
}
function portBadge(p) {
const host = p.host_ip ? `${p.host_ip}` : '';
const hostPort = p.host_port ? `:${p.host_port}` : '';
const container = p.container_port || '';
const text = `${host}${hostPort}${container}`.trim();
return `<span class="port">${text || '—'}</span>`;
}
function renderContainers(list) {
const q = document.getElementById('search').value.toLowerCase();
const root = document.getElementById('container-list');
root.innerHTML = '';
const filtered = list.filter(c => {
const s = `${c.name} ${c.image}`.toLowerCase();
return s.includes(q);
});
document.getElementById('container-count').textContent = `${filtered.length} / ${list.length} shown`;
filtered.forEach(c => {
const statusClass = (c.status === 'running') ? 'status' : 'status stopped';
const ports = (c.openPorts && c.openPorts.length) ? c.openPorts.map(portBadge).join('') : '<span class="muted">No published ports</span>';
const cpu = c.resources?.cpu_percent ?? 0;
const memMb = c.resources?.memory_mb ?? 0;
const memPct = c.resources?.memory_percent ?? 0;
const row = document.createElement('div');
row.className = 'row';
row.innerHTML = `
<div class="name">${c.name}<div class="muted">${c.image}</div></div>
<div><span class="${statusClass}">${c.status}</span></div>
<div class="ports">${ports}</div>
<div>
<span class="badge">CPU: ${formatPercent(cpu)}</span>
<span class="badge">Mem: ${formatMB(memMb)} (${formatPercent(memPct)})</span>
</div>
<div class="muted small">${c.id.slice(0,12)}</div>
`;
root.appendChild(row);
});
}
async function loadStatus() {
try {
const res = await fetch(`${DATA_URL}?t=${Date.now()}`, { cache: 'no-store' });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
document.getElementById('last-update').textContent = new Date(data.timestamp).toLocaleString();
renderSystem(data.system);
renderContainers(data.containers || []);
} catch (err) {
console.error('Failed to load status:', err);
document.getElementById('last-update').textContent = 'failed';
}
}
function startAutoRefresh() {
if (refreshTimer) clearInterval(refreshTimer);
refreshTimer = setInterval(() => {
if (autoRefresh) loadStatus();
}, 5000);
}
// Events
window.addEventListener('DOMContentLoaded', () => {
document.getElementById('toggle-refresh').addEventListener('click', () => {
autoRefresh = !autoRefresh;
document.getElementById('toggle-refresh').textContent = autoRefresh ? 'Pause' : 'Resume';
document.getElementById('refresh-state').textContent = autoRefresh ? 'on' : 'paused';
if (autoRefresh) loadStatus();
});
document.getElementById('search').addEventListener('input', () => {
// Re-render list using current data in memory by fetching again (cheap)
loadStatus();
});
loadStatus();
startAutoRefresh();
});