5ba0f31767
- lib/state.py: per-subsystem collectors with versioned state store - daemon/server.py: state refresh on request, batch routing updates - webui/static/hoover/html.js: new html tag template helper via htm.js - webui/static/hoover/websocket.js: real-time state change notifications - webui/static/hoover/vdom.js: VDOM improvements for keyed diff - All frontend pages refactored to use html templates - Add tests for state management and polling - Update docs and AGENTS.md
53 lines
2.1 KiB
JavaScript
53 lines
2.1 KiB
JavaScript
import { html, PageHeader, definePage, getModel, renderGuard, ServiceStatus, StatCard } from '/static/hoover/index.js?v=7';
|
|
|
|
export default definePage({
|
|
init() {
|
|
return {
|
|
status: getModel('status'),
|
|
};
|
|
},
|
|
render(state) {
|
|
const guard = renderGuard(state.status, 'Dashboard', 'System overview', state.status.data);
|
|
if (guard) return guard;
|
|
|
|
const d = state.status.data;
|
|
const fwZones = (d.firewall?.zones) || {};
|
|
const net = d.net || {};
|
|
const nCount = Object.keys(net).length;
|
|
const upI = Object.values(net).filter(i => i.state === 'up');
|
|
const upC = upI.length;
|
|
const certs = d.certs || [];
|
|
const certW = certs.filter(c => c.expired || c.days_remaining <= 30);
|
|
const dmsk = d.dnsmasq?.status || {};
|
|
const wP = (d.wg || {}).peers || [];
|
|
|
|
const stats = html`<div class="grid grid-4">
|
|
<${StatCard} label="Active Zones" value=${Object.keys(fwZones).length}
|
|
meta=${Object.keys(fwZones).join(', ') || 'None'} />
|
|
<${StatCard} label="Interfaces Up" value=${upC + '/' + nCount}
|
|
meta=${upI.map(i => i.name).join(', ') || 'None up'} />
|
|
<${StatCard} label="WireGuard" value=${String(d.wg?.state || 'unknown')}
|
|
meta=${wP.length + ' peers'} />
|
|
<${StatCard} label="Certificates" value=${certs.length}
|
|
meta=${certW.length + ' expiring/expired'} />
|
|
</div>`;
|
|
|
|
const services = html`<div class="grid grid-2">
|
|
<div class="card">
|
|
<div class="card-header">Services</div>
|
|
<div class="card-body">
|
|
<ul class="service-list">
|
|
<li><${ServiceStatus} state=${dmsk.state || 'down'} label="Dnsmasq" /></li>
|
|
<li><${ServiceStatus} state=${d.wg?.state || 'down'} label="WireGuard" /></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
|
|
return [
|
|
PageHeader({ title: 'Dashboard', subtitle: 'System overview' }),
|
|
stats,
|
|
services,
|
|
];
|
|
},
|
|
}); |