From 6d5b1992b5efde77ebb1964c211687acab42ce07 Mon Sep 17 00:00:00 2001 From: Hermes Date: Fri, 24 Jul 2026 22:59:22 -0700 Subject: [PATCH] [grade=A] refactor: remove stale nested monitoring widget --- dashcaddy-api/status/js/monitoring-widgets.js | 335 ------------------ 1 file changed, 335 deletions(-) delete mode 100644 dashcaddy-api/status/js/monitoring-widgets.js diff --git a/dashcaddy-api/status/js/monitoring-widgets.js b/dashcaddy-api/status/js/monitoring-widgets.js deleted file mode 100644 index 60fc646..0000000 --- a/dashcaddy-api/status/js/monitoring-widgets.js +++ /dev/null @@ -1,335 +0,0 @@ -// ========== MONITORING WIDGETS ========== -// Embeds a compact system-resource + health summary panel directly on the -// main dashboard. Replaces the need for a separate monitoring-dashboard.html -// page β€” quick at-a-glance stats where you already are. -(function () { - - // ----- Style injection (scoped to .dc-monitor so it doesn't leak) ----- - const styleEl = document.createElement('style'); - styleEl.textContent = ` - .dc-monitor { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); - gap: 12px; - margin-bottom: 16px; - padding: 12px 16px; - background: var(--card-base); - border: 1px solid var(--border); - border-radius: var(--radius); - } - .dc-monitor-card { - padding: 10px 12px; - background: var(--card-bg, rgba(255,255,255,0.04)); - border-radius: 8px; - border: 1px solid var(--border); - } - .dc-monitor-label { - font-size: 0.7rem; - color: var(--muted); - text-transform: uppercase; - letter-spacing: 0.5px; - margin-bottom: 4px; - } - .dc-monitor-value { - font-size: 1.4rem; - font-weight: 600; - color: var(--fg); - } - .dc-monitor-sub { - font-size: 0.7rem; - color: var(--muted); - margin-top: 4px; - } - .dc-monitor-bar { - margin-top: 6px; - width: 100%; - height: 4px; - background: color-mix(in srgb, var(--muted) 20%, transparent); - border-radius: 2px; - overflow: hidden; - } - .dc-monitor-bar-fill { - height: 100%; - width: 0%; - background: var(--ok-fg, #27ae60); - transition: width 0.3s ease, background 0.3s ease; - } - .dc-monitor-bar-fill.warn { background: #f39c12; } - .dc-monitor-bar-fill.bad { background: #e74c3c; } - .dc-monitor-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 8px; - } - .dc-monitor-title { - font-size: 0.85rem; - font-weight: 500; - color: var(--muted); - display: flex; - align-items: center; - gap: 6px; - } - .dc-monitor-pill { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 2px 8px; - border-radius: 999px; - font-size: 0.7rem; - font-weight: 500; - } - .dc-monitor-pill.ok { background: color-mix(in srgb, #27ae60 20%, transparent); color: #27ae60; } - .dc-monitor-pill.warn { background: color-mix(in srgb, #f39c12 20%, transparent); color: #f39c12; } - .dc-monitor-pill.bad { background: color-mix(in srgb, #e74c3c 20%, transparent); color: #e74c3c; } - .dc-monitor-refresh { - font-size: 0.7rem; - color: var(--muted); - opacity: 0.7; - } - `; - document.head.appendChild(styleEl); - - // ----- Container element (inserted above service-filter-bar) ----- - const filterBar = document.getElementById('service-filter-bar'); - if (!filterBar) return; - - const panel = document.createElement('div'); - panel.className = 'dc-monitor'; - panel.id = 'dc-monitor-panel'; - panel.innerHTML = ` -
-
πŸ“Š System Overview
- β€” -
-
-
Services
-
β€”
-
loading…
-
-
-
Containers Up
-
β€”
-
loading…
-
-
-
Avg CPU
-
β€”
-
-
-
-
Avg Memory
-
β€”
-
-
-
-
Health
-
β€”
-
β€”
-
- `; - // Insert ABOVE the filter bar - filterBar.parentNode.insertBefore(panel, filterBar); - - // ----- Helpers ----- - function setBar(id, pct) { - const el = document.getElementById(id); - if (!el) return; - const p = Math.max(0, Math.min(100, Number(pct) || 0)); - el.style.width = p + '%'; - el.classList.remove('warn', 'bad'); - if (p >= 85) el.classList.add('bad'); - else if (p >= 65) el.classList.add('warn'); - } - - function fmtPct(v) { - if (v == null || isNaN(v)) return 'β€”'; - return (Math.round(v * 10) / 10) + '%'; - } - - function fmtBytes(b) { - if (b == null || isNaN(b)) return 'β€”'; - const units = ['B', 'KB', 'MB', 'GB', 'TB']; - let i = 0; - while (b >= 1024 && i < units.length - 1) { b /= 1024; i++; } - return b.toFixed(1) + ' ' + units[i]; - } - - // ----- Robust services count ----- - // Read from multiple sources so we always have a number: - // 1. window.APPS (populated by grid.js after loadServices) - // 2. #cards .card elements (post-buildGrid) - // 3. live fetch /api/v1/services (last-resort fallback if grid hasn't run) - async function fetchServicesCount() { - // Source 1+2: window.APPS / DOM cards - if (Array.isArray(window.APPS) && window.APPS.length > 0) { - const up = document.querySelectorAll('#cards .card[data-status="on"]').length; - return { total: window.APPS.length, up, source: 'APPS' }; - } - const cards = document.querySelectorAll('#cards .card'); - if (cards.length > 0) { - const up = Array.from(cards).filter(c => c.dataset.status === 'on').length; - return { total: cards.length, up, source: 'DOM' }; - } - // Source 3: fetch live (endpoints may return {success, services:[...]} OR raw array) - try { - const r = await fetch('/api/v1/services', { cache: 'no-store' }); - if (!r.ok) return { total: 0, up: 0, source: 'fetch-fail' }; - const body = await r.json(); - const list = (body && Array.isArray(body.services)) ? body.services - : (Array.isArray(body)) ? body - : []; - // Persist for the grid so this fallback only fires once - if (Array.isArray(window.APPS) || typeof window.APPS === 'undefined') window.APPS = list; - const up = document.querySelectorAll('#cards .card[data-status="on"]').length; - return { total: list.length, up, source: 'fetch' }; - } catch (_) { - return { total: 0, up: 0, source: 'fetch-error' }; - } - } - - async function setServicesCard() { - const { total, up } = await fetchServicesCount(); - const el = document.getElementById('dc-monitor-services'); - const sub = document.getElementById('dc-monitor-services-sub'); - if (el) el.textContent = `${up} / ${total}`; - if (sub) sub.textContent = total === 0 - ? 'no services yet' - : `${up} online Β· ${total - up} offline`; - } - - function applyHealthSummary(data) { - const el = document.getElementById('dc-monitor-health'); - const sub = document.getElementById('dc-monitor-health-sub'); - if (!el) return; - if (!data || data.summary == null) { - el.textContent = 'β€”'; - if (sub) sub.textContent = 'no data'; - return; - } - const s = data.summary; - const healthy = s.healthy ?? s.up ?? 0; - const unhealthy = s.unhealthy ?? s.down ?? 0; - const total = s.total ?? (healthy + unhealthy); - el.textContent = `${healthy}/${total}`; - if (sub) { - if (unhealthy === 0) { - sub.innerHTML = '● all healthy'; - } else if (unhealthy <= 2) { - sub.innerHTML = `● ${unhealthy} degraded`; - } else { - sub.innerHTML = `● ${unhealthy} down`; - } - } - } - - // ----- Data fetches ----- - async function fetchStats() { - try { - const r = await fetch('/api/v1/monitoring/stats', { cache: 'no-store' }); - if (!r.ok) return null; - const data = await r.json(); - return (data && data.stats) ? data.stats : null; - } catch (_) { - return null; - } - } - - async function fetchHealth() { - try { - const r = await fetch('/api/v1/health-checks/status', { cache: 'no-store' }); - if (!r.ok) return null; - return await r.json(); - } catch (_) { - return null; - } - } - - function applyStats(stats) { - const containers = document.getElementById('dc-monitor-containers'); - const containersSub = document.getElementById('dc-monitor-containers-sub'); - const cpuEl = document.getElementById('dc-monitor-cpu'); - const memEl = document.getElementById('dc-monitor-mem'); - - if (!stats) { - if (containers) containers.textContent = 'β€”'; - if (cpuEl) cpuEl.textContent = 'β€”'; - if (memEl) memEl.textContent = 'β€”'; - return; - } - - const entries = Object.values(stats); - if (entries.length === 0) { - if (containers) containers.textContent = '0'; - if (containersSub) containersSub.textContent = 'no containers reporting'; - if (cpuEl) cpuEl.textContent = '0%'; - if (memEl) memEl.textContent = '0%'; - setBar('dc-monitor-cpu-bar', 0); - setBar('dc-monitor-mem-bar', 0); - return; - } - - let cpuSum = 0, memSum = 0, memBytes = 0, cpuCount = 0, memCount = 0; - entries.forEach(s => { - // CPU may be percentage (0-100) or fraction (0-1) β€” handle both - if (s.cpu != null) { - const cpu = Number(s.cpu); - if (!isNaN(cpu)) { - cpuSum += cpu > 1 ? cpu : cpu * 100; - cpuCount++; - } - } - if (s.memory != null) { - const mem = Number(s.memory); - if (!isNaN(mem)) { - memSum += mem; - memBytes += Number(s.memoryUsage || 0); - memCount++; - } - } - }); - - const avgCpu = cpuCount ? cpuSum / cpuCount : 0; - const avgMem = memCount ? memSum / memCount : 0; - - if (containers) containers.textContent = String(entries.length); - if (containersSub) { - const memTxt = memBytes ? ` Β· ${fmtBytes(memBytes)} RAM` : ''; - containersSub.textContent = `running${memTxt}`; - } - if (cpuEl) cpuEl.textContent = fmtPct(avgCpu); - if (memEl) memEl.textContent = fmtPct(avgMem); - setBar('dc-monitor-cpu-bar', avgCpu); - setBar('dc-monitor-mem-bar', avgMem); - } - - // ----- Public refresh function ----- - let inFlight = false; - async function refresh() { - if (inFlight) return; - inFlight = true; - try { - setServicesCard(); - const [stats, health] = await Promise.all([fetchStats(), fetchHealth()]); - applyStats(stats); - applyHealthSummary(health); - const stamp = document.getElementById('dc-monitor-refresh-stamp'); - if (stamp) { - const now = new Date(); - stamp.textContent = `updated ${now.toLocaleTimeString()}`; - } - } finally { - inFlight = false; - } - } - - // Expose for init.js to call once and re-call after each refreshAll cycle - window.refreshMonitoringWidgets = refresh; - - // Auto-refresh on the STATS interval (separate from full DASHBOARD refresh) - setInterval(refresh, (typeof DC !== 'undefined' && DC.POLL && DC.POLL.STATS) || 5000); - - // Refresh once on first script load (init.js also calls this; double-call is harmless) - setTimeout(refresh, 200); - -})();