()
| 10253 | if (d && d.missing_tool) extra = ' <button onclick="installNetTool(\'tcpdump\', this, runEigrpWatch)" class="ml-2 underline text-cyan-400">Install tcpdump</button>'; |
| 10254 | out.innerHTML = '<p class="text-sm text-red-400">Error: ' + escapeHtml(msg) + extra + '</p>'; |
| 10255 | return; |
| 10256 | } |
| 10257 | const [cls, label] = _EIGRP_VERDICT_STYLE[d.verdict] || _EIGRP_VERDICT_STYLE.unknown; |
| 10258 | let html = `<div class="mb-2 px-3 py-2 rounded border ${cls} text-sm">${label}</div>`; |
| 10259 | html += `<p class="text-xs text-gray-500 mb-2">Interface: ${escapeHtml(d.interface || '—')} · ${d.seconds}s · ${d.packet_count} EIGRP pkts, ${d.router_count} router(s), ${d.prefix_count} prefix(es) @ ${d.rate}/s${d.learned ? ' · <span class="text-gray-400">baseline learned now</span>' : ''}</p>`; |
| 10260 | if ((d.routers || []).length) { |
| 10261 | html += '<p class="text-xs uppercase text-gray-400 mt-2 mb-1">EIGRP routers (' + d.routers.length + ')</p>' + |
| 10262 | '<table class="min-w-full text-xs text-gray-300 whitespace-nowrap"><thead>' + |
| 10263 | '<tr class="text-left text-gray-500"><th class="px-2 py-1">Router</th><th class="px-2 py-1">AS</th><th class="px-2 py-1">AF</th><th class="px-2 py-1">Auth</th><th class="px-2 py-1">Status</th></tr>' + |
| 10264 | '</thead><tbody>' + |
| 10265 | d.routers.map(r => { |
| 10266 | const badge = r.baseline ? '<span class="text-green-400">✓ known</span>' : '<span class="text-amber-300">? new</span>'; |
| 10267 | const auth = r.auth ? '<span class="text-green-400">yes</span>' : '<span class="text-amber-300">none</span>'; |
| 10268 | return `<tr class="border-t border-slate-800"> |
| 10269 | <td class="px-2 py-1 font-mono ${r.baseline ? '' : 'text-amber-300'}">${escapeHtml(r.src)}</td> |
| 10270 | <td class="px-2 py-1 font-mono">${(r.as || []).join(', ') || '?'}</td> |
| 10271 | <td class="px-2 py-1 text-gray-400">${escapeHtml(r.af)}</td> |
| 10272 | <td class="px-2 py-1">${auth}</td> |
| 10273 | <td class="px-2 py-1">${badge}</td> |
| 10274 | </tr>`; |
| 10275 | }).join('') + |
| 10276 | '</tbody></table>'; |
| 10277 | } |
| 10278 | if ((d.prefixes || []).length) { |
| 10279 | html += '<p class="text-xs uppercase text-gray-400 mt-2 mb-1">Advertised prefixes (' + d.prefixes.length + ')</p>' + |
| 10280 | '<table class="min-w-full text-xs text-gray-300 whitespace-nowrap"><thead>' + |
| 10281 | '<tr class="text-left text-gray-500"><th class="px-2 py-1">Prefix</th><th class="px-2 py-1">Next-hop</th><th class="px-2 py-1">Origin</th><th class="px-2 py-1">Kind</th><th class="px-2 py-1">Status</th></tr>' + |
| 10282 | '</thead><tbody>' + |
| 10283 | d.prefixes.map(p => { |
| 10284 | const bad = (p.status === 'new' || p.status === 'nexthop-changed'); |
| 10285 | const st = bad ? `<span class="text-red-300">${escapeHtml(p.status)}</span>` : `<span class="text-gray-500">${escapeHtml(p.status)}</span>`; |
| 10286 | return `<tr class="border-t border-slate-800"> |
| 10287 | <td class="px-2 py-1 font-mono ${bad ? 'text-red-300' : ''}">${escapeHtml(p.prefix)}</td> |
| 10288 | <td class="px-2 py-1 font-mono">${escapeHtml(p.nexthop)}</td> |
| 10289 | <td class="px-2 py-1 font-mono text-gray-400">${escapeHtml(p.origin)}</td> |
| 10290 | <td class="px-2 py-1 text-gray-400">${escapeHtml(p.kind)}</td> |
| 10291 | <td class="px-2 py-1">${st}</td> |
| 10292 | </tr>`; |
| 10293 | }).join('') + |
| 10294 | '</tbody></table>'; |
| 10295 | } |
| 10296 | if (d.reasons && d.reasons.length) { |
| 10297 | html += '<ul class="text-xs text-gray-400 mt-2 list-disc pl-5">' + |
| 10298 | d.reasons.map(r => '<li>' + escapeHtml(r) + '</li>').join('') + '</ul>'; |
| 10299 | } |
| 10300 | (d.advisories || []).forEach(a => { |
nothing calls this directly
no test coverage detected