// Health monitoring UI functions let healthData = null; let healthUpdateInterval = null; const SERVICE_DEFS = [ { key: 'dns', name: 'DNS Service', icon: 'fa-globe' }, { key: 'proxy', name: 'Proxy Service', icon: 'fa-shield-halved' }, { key: 'swarm', name: 'Swarm', icon: 'fa-diagram-project' }, { key: 'corestore', name: 'Corestore', icon: 'fa-hard-drive' } ]; // Fetch health data async function fetchHealth() { try { const response = await fetch('/api/health'); if (!response.ok) { throw new Error('Failed to fetch health data'); } healthData = await response.json(); return healthData; } catch (err) { console.error('Failed to fetch health:', err); if (window.showNotification) window.showNotification('Failed to load health data', 'error'); return null; } } // Render health dashboard (HTTP only when no WS data yet) async function renderHealth() { if (healthData) { applyHealthPayload(healthData); return; } const data = await fetchHealth(); if (!data) return; applyHealthPayload(data); } // Apply health payload (HTTP initial or WebSocket) function applyHealthPayload(data) { const incoming = normalizeHealthPayload(data); if (!incoming) return; healthData = mergeHealthPayload(healthData, incoming); updateHealthStatus(healthData); renderServiceCards(healthData); updateHealthHistory(healthData); } // Update health status display function updateHealthStatus(data) { const statusEl = document.getElementById('health-status'); if (statusEl) { statusEl.textContent = data.status === 'healthy' ? 'Healthy' : 'Degraded'; statusEl.className = data.status === 'healthy' ? 'stats-metric-value stats-health-status stats-health-status--ok' : 'stats-metric-value stats-health-status stats-health-status--warn'; } const uptimeEl = document.getElementById('health-uptime'); if (uptimeEl && data.uptime) { uptimeEl.textContent = window.formatUptime ? window.formatUptime(data.uptime) : `${Math.floor(data.uptime / 1000)}s`; } } function getServiceData(data, key) { return data.services?.[key] || data.dependencies?.[key] || null; } function normalizeHealthPayload(data) { if (!data) return null; return { status: data.status, timestamp: data.timestamp, uptime: data.uptime, services: data.services, dependencies: data.dependencies }; } function mergeServiceData(existing, incoming) { if (!incoming) return existing || null; if (!existing) return incoming; const merged = { ...existing, ...incoming }; if (incoming.details != null) { merged.details = { ...(existing.details || {}), ...incoming.details }; } else if (existing.details) { merged.details = existing.details; } return merged; } function mergeHealthPayload(prev, next) { if (!next) return prev; if (!prev) return next; const merged = { ...prev, ...next, services: { ...(prev.services || {}) }, dependencies: { ...(prev.dependencies || {}) } }; for (const [key, val] of Object.entries(next.services || {})) { merged.services[key] = mergeServiceData(prev.services?.[key], val); } for (const [key, val] of Object.entries(next.dependencies || {})) { merged.dependencies[key] = mergeServiceData(prev.dependencies?.[key], val); } return merged; } function formatDetailEntries(details) { if (!details || typeof details !== 'object') return []; return Object.entries(details).map(([key, value]) => ({ key, value: String(value) })); } function ensureServiceCards(container) { if (container.dataset.initialized === '3') return; container.dataset.initialized = '3'; container.innerHTML = SERVICE_DEFS.map((service) => `
—