()
| 7650 | `<div class="text-xs opacity-75 mt-1">🌐 ${escapeHtml(ip)} — ${escapeHtml(a.country || '?')}${a.as_org ? ' · ' + escapeHtml(a.as_org) : ''}${a.classification && a.classification !== 'unknown' ? ' · ' + escapeHtml(a.classification) : ''}${a.abuse_email ? ' · abuse: ' + escapeHtml(a.abuse_email) : ''}</div>` |
| 7651 | ).join('')} |
| 7652 | </div>`; |
| 7653 | }).join(''); |
| 7654 | } |
| 7655 | async function refreshIncidents(elId, minSev) { |
| 7656 | const q = '/api/net/incidents?limit=6' + (minSev ? '&min_severity=' + encodeURIComponent(minSev) : ''); |
| 7657 | try { |
| 7658 | const d = await fetchAPI(q); |
| 7659 | renderIncidents((d && d.incidents) || [], elId, elId === 'dash-incidents' ? 3 : 6); |
| 7660 | } catch (e) { /* offline — leave as-is */ } |
| 7661 | } |
| 7662 | function renderWatchtower(d) { |
| 7663 | const sumEl = document.getElementById('watchtower-summary'); |
| 7664 | const srcEl = document.getElementById('watchtower-sources'); |
| 7665 | const listEl = document.getElementById('watchtower-alerts'); |
| 7666 | if (!sumEl || !listEl) return; |
| 7667 | if (!d || d.success === false) { sumEl.innerHTML = ''; listEl.innerHTML = ''; return; } |
| 7668 | if (!d.enabled) { |
| 7669 | sumEl.innerHTML = '<span class="text-xs text-gray-500">Watchtower is off — enable it to aggregate the standalone watchers into this pane.</span>'; |
| 7670 | if (srcEl) srcEl.textContent = ''; |
| 7671 | listEl.innerHTML = ''; |
| 7672 | return; |
| 7673 | } |
| 7674 | const s = d.summary || {}; |
| 7675 | const bySev = s.by_severity || {}; |
| 7676 | const chips = ['critical', 'high', 'medium', 'low', 'info'] |
| 7677 | .filter(k => bySev[k]).map(k => _wtSevChip(k, bySev[k])); |
| 7678 | const when = s.newest_ts ? new Date(s.newest_ts * 1000).toLocaleString() : '—'; |
| 7679 | sumEl.innerHTML = (chips.length ? chips.join(' ') : '<span class="text-xs text-green-400">✓ No alerts from any watcher</span>') |
| 7680 | + `<span class="text-xs text-gray-500 w-full mt-1">${s.total || 0} alert(s) held · newest: ${escapeHtml(when)}</span>`; |
| 7681 | // Source presence line: which watchers are actually logging. |
| 7682 | if (srcEl) { |
| 7683 | const srcs = (s.sources || []); |
| 7684 | if (srcs.length) { |
| 7685 | srcEl.innerHTML = srcs.map(x => |
| 7686 | `<span title="${x.present ? 'logging to ' + escapeHtml(x.path || '') : 'no log found — is the watcher running?'}" class="${x.present ? 'text-gray-400' : 'text-gray-600'}">${x.present ? '●' : '○'} ${escapeHtml(x.label || x.name)}</span>` |
| 7687 | ).join(' '); |
| 7688 | } else { srcEl.textContent = ''; } |
| 7689 | } |
nothing calls this directly
no test coverage detected