import { h, PageHeader, Badge, StatusDot, Empty, Card, esc, enc, att_esc, $val, apiFetch, toast, dismissToast, openModal, closeModal, formModal, definePage, hComp, connect, reactive, requestUpdate, Link, createRouter, ToastContainer, render, parseZones } from '/static/hoover/index.js'; export default definePage({ init() { return { data: null, loading: true, error: null }; }, subscribe: ['*'], async load(state) { try { const res = await apiFetch('/api/status/all'); if (res.ok) state.data = res.data; else state.error = res.error; } catch (e) { state.error = String(e); } state.loading = false; }, render(state) { if (state.loading) { return [ PageHeader({ title: 'Dashboard', subtitle: 'System overview' }), h('div', { class: 'card', key: 'loading' }, h('div', { class: 'card-body loading' }, 'Loading...'), ), ]; } if (state.error) { return [ PageHeader({ title: 'Dashboard', subtitle: 'System overview' }), h('div', { class: 'card', key: 'error' }, h('div', { class: 'card-body error-msg' }, state.error), ), ]; } const d = state.data; if (!d) { return [ PageHeader({ title: 'Dashboard', subtitle: 'System overview' }), h('div', { class: 'card', key: 'no-data' }, h('div', { class: 'card-body loading' }, 'No data available'), ), ]; } 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 dmskUp = dmsk.state === 'up'; const wUp = (d.wg?.state || 'down') === 'up'; const wP = (d.wg || {}).peers || []; return [ PageHeader({ title: 'Dashboard', subtitle: 'System overview' }), h('div', { class: 'grid grid-4' }, h('div', { class: 'stat-card' }, h('div', { class: 'label' }, 'Active Zones'), h('div', { class: 'value' }, Object.keys(fwZones).length), h('div', { class: 'meta' }, Object.keys(fwZones).join(', ') || 'None'), ), h('div', { class: 'stat-card' }, h('div', { class: 'label' }, 'Interfaces Up'), h('div', { class: 'value' }, upC + '/' + nCount), h('div', { class: 'meta' }, upI.map(i => i.name).join(', ') || 'None up'), ), h('div', { class: 'stat-card' }, h('div', { class: 'label' }, 'WireGuard'), h('div', { class: 'value' }, String(d.wg?.state || 'unknown')), h('div', { class: 'meta' }, wP.length + ' peers'), ), h('div', { class: 'stat-card' }, h('div', { class: 'label' }, 'Certificates'), h('div', { class: 'value' }, certs.length), h('div', { class: 'meta' }, certW.length + ' expiring/expired'), ), ), h('div', { class: 'grid grid-2' }, h('div', { class: 'card' }, h('div', { class: 'card-header' }, 'Services'), h('div', { class: 'card-body' }, h('ul', { class: 'service-list' }, h('li', null, StatusDot({ status: dmskUp ? 'success' : 'danger' }), ' Dnsmasq ', Badge({ text: dmsk.state || 'down', variant: dmskUp ? 'success' : 'danger' }), ), h('li', null, StatusDot({ status: wUp ? 'success' : 'danger' }), ' WireGuard ', Badge({ text: String(d.wg?.state || 'down'), variant: wUp ? 'success' : 'danger' }), ), ), ), ), ), ]; }, });