104 lines
3.5 KiB
JavaScript
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">↻ 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 };
|
|
})();
|