diff --git a/public/index.html b/public/index.html index 3f8b6cb4..303514a4 100644 --- a/public/index.html +++ b/public/index.html @@ -85,16 +85,16 @@ - + - + - + diff --git a/public/live.js b/public/live.js index f35b4b7d..f9b2a273 100644 --- a/public/live.js +++ b/public/live.js @@ -1169,9 +1169,10 @@ `; if (observers.length) { - html += `

Heard By

+ const regions = [...new Set(observers.map(o => o.iata).filter(Boolean))]; + html += `

Heard By${regions.length ? ' — Regions: ' + regions.join(', ') : ''}

` + - observers.map(o => `
${escapeHtml(o.observer_name || o.observer_id.slice(0, 12))} — ${o.packetCount || o.count || 0} pkts
`).join('') + + observers.map(o => `
${escapeHtml(o.observer_name || o.observer_id.slice(0, 12))}${o.iata ? ' (' + escapeHtml(o.iata) + ')' : ''} — ${o.packetCount || o.count || 0} pkts
`).join('') + '
'; } diff --git a/public/nodes.js b/public/nodes.js index a318ecfb..1a6910a0 100644 --- a/public/nodes.js +++ b/public/nodes.js @@ -143,12 +143,14 @@ ${observers.length ? `
+ ${(() => { const regions = [...new Set(observers.map(o => o.iata).filter(Boolean))]; return regions.length ? `
Regions: ${regions.map(r => '' + escapeHtml(r) + '').join(' ')}
` : ''; })()}

Heard By (${observers.length} observer${observers.length > 1 ? 's' : ''})

- + ${observers.map(o => ` + @@ -518,10 +520,11 @@ ${observers.length ? `
+ ${(() => { const regions = [...new Set(observers.map(o => o.iata).filter(Boolean))]; return regions.length ? `
Regions: ${regions.join(', ')}
` : ''; })()}

Heard By (${observers.length} observer${observers.length > 1 ? 's' : ''})

${observers.map(o => `
- ${escapeHtml(o.observer_name || o.observer_id)} + ${escapeHtml(o.observer_name || o.observer_id)}${o.iata ? ' ' + escapeHtml(o.iata) + '' : ''} ${o.packetCount} pkts · ${o.avgSnr != null ? 'SNR ' + o.avgSnr.toFixed(1) + 'dB' : ''}${o.avgRssi != null ? ' · RSSI ' + o.avgRssi.toFixed(0) : ''}
`).join('')}
diff --git a/public/packets.js b/public/packets.js index 032772be..6724e9d9 100644 --- a/public/packets.js +++ b/public/packets.js @@ -9,7 +9,8 @@ function obsName(id) { if (!id) return '—'; const o = observers.find(ob => ob.id === id); - return o?.name || id; + if (!o) return id; + return o.iata ? `${o.name} (${o.iata})` : o.name; } let selectedId = null; let groupByHash = true; @@ -1331,11 +1332,16 @@ const hopName = hopEntry ? (typeof hopEntry === 'string' ? hopEntry : hopEntry.name) : null; const hopPubkey = hopEntry?.pubkey || pathHops[i]; const conflicts = hopEntry?.conflicts || []; + const distInfo = conflicts.length === 1 && conflicts[0].distKm != null + ? ` (${Math.round(conflicts[0].distKm)}km)` + : conflicts.length > 1 && conflicts.find(c => c.distKm != null) + ? ` (${Math.round(conflicts.find(c => c.distKm != null).distKm)}km)` + : ''; const conflictInfo = conflicts.length > 1 - ? ` ⚠${conflicts.length}` + ? ` ⚠${conflicts.length}` : ''; const nameHtml = hopName - ? `${escapeHtml(hopName)}${conflictInfo}` + ? `${escapeHtml(hopName)}${distInfo}${conflictInfo}` : ''; const label = hopName ? `Hop ${i} — ${nameHtml}` : `Hop ${i}`; rows += fieldRow(off + i * hashSize, label, pathHops[i], ''); diff --git a/server.js b/server.js index f7366ad5..656ba8e8 100644 --- a/server.js +++ b/server.js @@ -2470,9 +2470,15 @@ app.get('/api/nodes/:pubkey/health', (req, res) => { } } + // Build observer iata lookup + const allObservers = db.getObservers(); + const obsIataMap = {}; + for (const obs of allObservers) { if (obs.iata) obsIataMap[obs.id] = obs.iata; } + const observers = Object.entries(obsMap).map(([observer_id, o]) => ({ observer_id, observer_name: o.observer_name, packetCount: o.packetCount, - avgSnr: o.snrN ? o.snrSum / o.snrN : null, avgRssi: o.rssiN ? o.rssiSum / o.rssiN : null + avgSnr: o.snrN ? o.snrSum / o.snrN : null, avgRssi: o.rssiN ? o.rssiSum / o.rssiN : null, + iata: obsIataMap[observer_id] || null })).sort((a, b) => b.packetCount - a.packetCount); const recentPackets = packets.slice(0, 20);
ObserverPacketsAvg SNRAvg RSSI
ObserverRegionPacketsAvg SNRAvg RSSI
${escapeHtml(o.observer_name || o.observer_id)}${o.iata ? escapeHtml(o.iata) : '—'} ${o.packetCount} ${o.avgSnr != null ? o.avgSnr.toFixed(1) + ' dB' : '—'} ${o.avgRssi != null ? o.avgRssi.toFixed(0) + ' dBm' : '—'}