fix: add missing renderResilienceScore + renderRouteLeak functions
These were called in doLookup but never defined anywhere, causing: 'Error: renderResilienceScore is not defined' This JS error aborted the entire render pipeline after the lookup completed — meaning WHOIS, health report, ASPA, bgproutes all never loaded because the catch block fired instead. Also added AbortController timeouts to all 5 new feature card loaders.
This commit is contained in:
parent
969595b9b4
commit
2db994da7f
@ -23,3 +23,4 @@
|
|||||||
{"d":"2026-04-09","t":"FIX","m":"doLookup: add 15s AbortController on initial fetch — skeleton no longer spins indefinitely on slow/failed lookups"}
|
{"d":"2026-04-09","t":"FIX","m":"doLookup: add 15s AbortController on initial fetch — skeleton no longer spins indefinitely on slow/failed lookups"}
|
||||||
{"d":"2026-04-09","t":"FIX","m":"aspath/rpki-history/looking-glass/communities: fetchJSONWithRetry with 15-20s timeouts replaced by fetchJSON 5-6s — was causing 40-72s hangs"}
|
{"d":"2026-04-09","t":"FIX","m":"aspath/rpki-history/looking-glass/communities: fetchJSONWithRetry with 15-20s timeouts replaced by fetchJSON 5-6s — was causing 40-72s hangs"}
|
||||||
{"d":"2026-04-09","t":"FIX","m":"loadCommunities/loadIrrAudit/loadRpkiHistory/loadAspath/loadHijackMonitor: add AbortController 8-10s — cards no longer spin forever"}
|
{"d":"2026-04-09","t":"FIX","m":"loadCommunities/loadIrrAudit/loadRpkiHistory/loadAspath/loadHijackMonitor: add AbortController 8-10s — cards no longer spin forever"}
|
||||||
|
{"d":"2026-04-09","t":"FIX","m":"renderResilienceScore + renderRouteLeak: functions were called but never defined — caused JS crash 'is not defined' breaking entire doLookup render"}
|
||||||
|
|||||||
@ -4224,6 +4224,66 @@ function renderContacts(d) {
|
|||||||
card.classList.remove('hidden');
|
card.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Resilience Score ───────────────────────────────────────────
|
||||||
|
function renderResilienceScore(rs) {
|
||||||
|
const card = document.getElementById('resilienceCard');
|
||||||
|
const el = document.getElementById('resilienceContent');
|
||||||
|
if (!card || !el || !rs) return;
|
||||||
|
card.style.display = '';
|
||||||
|
const score = rs.score || 0;
|
||||||
|
const color = score >= 7 ? 'var(--green)' : score >= 4 ? 'var(--orange)' : 'var(--red)';
|
||||||
|
const bd = rs.breakdown || {};
|
||||||
|
const labels = { transit_diversity: 'Transit Diversity', peering_breadth: 'Peering Breadth', ixp_presence: 'IXP Presence', path_redundancy: 'Path Redundancy' };
|
||||||
|
let h = '<div style="display:flex;align-items:baseline;gap:.5rem;margin-bottom:.75rem">';
|
||||||
|
h += '<span style="font-size:2rem;font-weight:700;font-family:var(--mono);color:' + color + '">' + score.toFixed(1) + '</span>';
|
||||||
|
h += '<span style="font-size:.75rem;color:var(--muted);font-family:var(--mono)">/10</span></div>';
|
||||||
|
h += '<div style="display:flex;flex-direction:column;gap:.35rem">';
|
||||||
|
Object.keys(bd).forEach(function(k) {
|
||||||
|
const item = bd[k];
|
||||||
|
const pct = Math.round((item.raw || 0) * 10);
|
||||||
|
const c = pct >= 70 ? 'var(--green)' : pct >= 40 ? 'var(--orange)' : 'var(--red)';
|
||||||
|
h += '<div style="display:grid;grid-template-columns:130px 1fr 45px;align-items:center;gap:.5rem">';
|
||||||
|
h += '<span style="font-family:var(--mono);font-size:.68rem;color:var(--muted)">' + (labels[k] || k) + '</span>';
|
||||||
|
h += '<div style="height:5px;background:var(--border);border-radius:3px"><div style="height:5px;width:' + pct + '%;background:' + c + ';border-radius:3px"></div></div>';
|
||||||
|
h += '<span style="font-family:var(--mono);font-size:.68rem;color:' + c + ';text-align:right">' + (item.raw || 0) + '/10</span>';
|
||||||
|
h += '</div>';
|
||||||
|
});
|
||||||
|
h += '</div>';
|
||||||
|
if (rs._provenance) {
|
||||||
|
const prov = rs._provenance;
|
||||||
|
const badge = document.getElementById('resilienceProvBadge');
|
||||||
|
if (badge) badge.innerHTML = '<span style="font-family:var(--mono);font-size:.6rem;color:var(--dim)" title="' + escHtml(prov.note || '') + '">' + escHtml(prov.confidence || '') + ' · ' + escHtml(prov.validation || '') + '</span>';
|
||||||
|
}
|
||||||
|
el.innerHTML = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Route Leak Detection ───────────────────────────────────────
|
||||||
|
function renderRouteLeak(rl) {
|
||||||
|
const card = document.getElementById('routeLeakCard');
|
||||||
|
const el = document.getElementById('routeLeakContent');
|
||||||
|
if (!card || !el || !rl) return;
|
||||||
|
card.style.display = '';
|
||||||
|
const detected = rl.detected;
|
||||||
|
const color = detected ? 'var(--red)' : 'var(--green)';
|
||||||
|
let h = '<div style="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem">';
|
||||||
|
h += '<span style="font-family:var(--mono);font-size:.85rem;font-weight:700;color:' + color + '">' + (detected ? '⚠ LEAK DETECTED' : '✓ No Leaks Detected') + '</span></div>';
|
||||||
|
if (rl.patterns && rl.patterns.length) {
|
||||||
|
h += '<div style="font-family:var(--mono);font-size:.7rem;color:var(--muted);margin-bottom:.4rem">Patterns:</div>';
|
||||||
|
rl.patterns.forEach(function(p) {
|
||||||
|
h += '<div style="font-family:var(--mono);font-size:.68rem;color:var(--red);padding:.2rem 0">' + escHtml(String(p)) + '</div>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
h += '<div style="font-family:var(--mono);font-size:.65rem;color:var(--dim);margin-top:.4rem">';
|
||||||
|
h += 'Tier-1 upstreams: ' + (rl.tier1_upstream_count || 0) + ' · Tier-1 downstreams: ' + (rl.tier1_downstream_count || 0);
|
||||||
|
h += '</div>';
|
||||||
|
if (rl._provenance) {
|
||||||
|
const prov = rl._provenance;
|
||||||
|
const badge = document.getElementById('routeLeakProvBadge');
|
||||||
|
if (badge) badge.innerHTML = '<span style="font-family:var(--mono);font-size:.6rem;color:var(--dim)" title="' + escHtml(prov.note || '') + '">' + escHtml(prov.confidence || '') + ' · ' + escHtml(prov.validation || '') + '</span>';
|
||||||
|
}
|
||||||
|
el.innerHTML = h;
|
||||||
|
}
|
||||||
|
|
||||||
// ── Data Sources Timing ────────────────────────────────────────
|
// ── Data Sources Timing ────────────────────────────────────────
|
||||||
function renderSourceTiming(d) {
|
function renderSourceTiming(d) {
|
||||||
const card = document.getElementById('sourceTimingCard');
|
const card = document.getElementById('sourceTimingCard');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user