// Endpoints table const { useMemo: useTblMemo, useState: useTblState } = React; function NodesTable({ nodes, onSelect, selectedId }) { const [sort, setSort] = useTblState({ key: 'hostname', dir: 1 }); const [groupBy, setGroupBy] = useTblState('group'); const sorted = useTblMemo(() => { const arr = [...nodes]; arr.sort((a, b) => { const k = sort.key; const av = a[k], bv = b[k]; if (typeof av === 'number') return (av - bv) * sort.dir; return String(av).localeCompare(String(bv)) * sort.dir; }); return arr; }, [nodes, sort]); const groups = useTblMemo(() => { if (groupBy === 'none') return [{ label: null, items: sorted }]; const map = {}; for (const n of sorted) { const k = n[groupBy]; if (!map[k]) map[k] = []; map[k].push(n); } return Object.entries(map).map(([label, items]) => ({ label, items })); }, [sorted, groupBy]); function toggleSort(key) { setSort(s => s.key === key ? { key, dir: -s.dir } : { key, dir: 1 }); } const SortHdr = ({ k, children, className }) => (
| Proto | Path | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| {groupBy} · {g.label} · {g.items.length} | |||||||||||
| {n.hostname} | {n.status === 'ok' ? 'up' : n.status === 'off' ? 'offline' : n.status === 'maint' ? 'maint' : n.status === 'warn' ? 'warn' : 'down'} | {n.group} | {n.protocol}:{n.port} | {n.path} | = 500 ? 'var(--crit)' : n.httpCode >= 400 ? 'var(--warn)' : 'var(--ok)'}}> {n.httpCode === 0 ? '—' : n.httpCode} | 800 ? 'var(--crit)' : n.latency > 300 ? 'var(--warn)' : 'var(--text)'}}> {n.status === 'off' ? '—' : `${n.latency.toFixed(0)}ms`} | {n.status === 'off' ? '—' : `${n.netIn.toFixed(0)}`} | {n.status === 'off' ? '—' : `${n.netOut.toFixed(0)}`} | {n.sslDaysLeft}d | {n.status === 'off' ? '—' : window.fmtUptime(n.uptime)} | |