import { el, mount } from '../dom.js'; import { api } from '../api.js'; import { littleblueAvatar } from '../components/littleblue_avatar.js'; import { serviceTile } from '../components/service_tile.js'; const TITLE = { agents: 'Agents', infrastructure: 'Infrastructure', media: 'Media', other: 'Other' }; let host, timer, scanning = false; async function promote(id) { try { await api.patch('/api/health/services/' + id, { enabled: true }); load(); } catch { /* */ } } function scan() { if (scanning) return; scanning = true; load(); // reflect "Scanning…" api.post('/api/health/discover', {}).catch(() => { /* */ }); setTimeout(() => { scanning = false; load(); }, 30000); // LAN sweep ~25s } // Owner-only; returns a section element or null (skipped for non-owner / none). async function discoveredSection() { let cand; try { cand = await api.get('/api/health/services/discovered'); } catch { return null; } if (!cand || !cand.length) return null; return el('div', { class: 'lb-section' }, el('div', { class: 'lb-group' }, el('span', { class: 'gname' }, 'Discovered'), el('span', { class: 'gcount' }, `${cand.length} new`), el('span', { class: 'line' })), el('div', { class: 'tiles' }, cand.map(c => el('div', { class: 'tile disc' }, el('div', { class: 'tile-main' }, el('div', { class: 'tile-nm' }, c.name), el('div', { class: 'tile-host' }, c.url)), el('button', { class: 'disc-add', title: 'Add to the band', onclick: () => promote(c.id) }, '+'))))); } async function load() { if (!host) return; try { const groups = await api.get('/api/health/services'); const sections = groups.map(g => el('div', { class: 'lb-section' }, el('div', { class: 'lb-group' }, el('span', { class: 'gname' }, TITLE[g.category] || g.category), el('span', { class: 'gcount' }, `${g.healthy}/${g.total} healthy`), el('span', { class: 'line' })), el('div', { class: 'tiles' }, g.services.map(serviceTile)))); const disc = await discoveredSection(); mount(host, el('div', { class: 'lbwrap' }, littleblueAvatar(), el('div', { style: { flex: 1 } }, el('div', { class: 'lb-name' }, 'Little Blue'), el('div', { class: 'lb-sub' }, 'Health & Uptime of the lab')), el('button', { class: 'lb-scan', title: 'Scan the LAN for services', onclick: scan }, scanning ? 'Scanning…' : 'Scan')), sections, disc); } catch { mount(host, el('span', { class: 'muted' }, 'Health band unavailable')); } } export function renderHealthBand(el_) { host = el_; load(); timer = setInterval(load, 60000); } export function stopHealthBand() { clearInterval(timer); host = null; }