BillTracker/public/js/status.js

104 lines
3.5 KiB
JavaScript

/* ── Status page ── */
const StatusPage = (() => {
async function init(container) {
container.innerHTML = `
<div class="page-header">
<h1 class="page-title">Server Status</h1>
<button class="btn btn-ghost btn-sm" id="status-refresh">&#8635; Refresh</button>
</div>
<div id="status-body"><div class="loading">Loading...</div></div>
`;
document.getElementById('status-refresh').onclick = () => load(container);
load(container);
}
async function load(container) {
const body = document.getElementById('status-body');
try {
const res = await fetch('/api/status');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const d = await res.json();
body.innerHTML = render(d);
} catch (e) {
body.innerHTML = `<div class="empty-state"><p>Failed to load status: ${e.message}</p></div>`;
}
}
function fmtUptime(seconds) {
const d = Math.floor(seconds / 86400);
const h = Math.floor((seconds % 86400) / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = seconds % 60;
if (d > 0) return `${d}d ${h}h ${m}m`;
if (h > 0) return `${h}h ${m}m ${s}s`;
if (m > 0) return `${m}m ${s}s`;
return `${s}s`;
}
function fmtBytes(bytes) {
if (bytes === 0) return '0 B';
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / 1048576).toFixed(2)} MB`;
}
function row(label, value, note = '') {
return `
<div class="stat-row">
<span class="stat-label">${label}</span>
<span class="stat-value">${value}${note ? `<span class="stat-note">${note}</span>` : ''}</span>
</div>`;
}
function render(d) {
const dbOk = d.database.status === 'connected';
return `
<div class="status-grid">
<div class="status-card">
<div class="status-card-header">
<span class="status-card-title">Application</span>
<span class="status-dot dot-green" title="Online"></span>
</div>
${row('Version', `v${d.app.version}`)}
${row('Environment', d.app.environment)}
${row('Uptime', fmtUptime(d.app.uptime_seconds))}
</div>
<div class="status-card">
<div class="status-card-header">
<span class="status-card-title">Runtime</span>
</div>
${row('Node.js', d.runtime.node_version)}
${row('Platform', `${d.runtime.platform} / ${d.runtime.arch}`)}
${row('Memory', `${d.runtime.memory_mb} MB`)}
</div>
<div class="status-card">
<div class="status-card-header">
<span class="status-card-title">Database</span>
<span class="status-dot ${dbOk ? 'dot-green' : 'dot-red'}" title="${d.database.status}"></span>
</div>
${row('Status', dbOk ? 'Connected' : 'Error')}
${row('Size', fmtBytes(d.database.size_bytes))}
${row('File', `<code style="font-size:11px">${d.database.path}</code>`)}
</div>
<div class="status-card">
<div class="status-card-header">
<span class="status-card-title">Statistics</span>
</div>
${row('Active Bills', d.stats.active_bills)}
${row('Total Payments', d.stats.total_payments)}
${row('Users', d.stats.users)}
${row('Active Sessions', d.stats.active_sessions)}
</div>
</div>
`;
}
return { init };
})();