diff --git a/public/index.html b/public/index.html index 740c9b7f..ff663798 100644 --- a/public/index.html +++ b/public/index.html @@ -84,7 +84,7 @@ - + diff --git a/public/packets.js b/public/packets.js index d5d9a720..fb12e22c 100644 --- a/public/packets.js +++ b/public/packets.js @@ -346,12 +346,34 @@ if (filters.observer) params.set('observer', filters.observer); if (filters.hash) params.set('hash', filters.hash); if (filters.node) params.set('node', filters.node); - if (groupByHash) params.set('groupByHash', 'true'); + params.set('groupByHash', 'true'); // always fetch grouped const data = await api('/packets?' + params.toString()); packets = data.packets || []; totalCount = data.total || packets.length; + // When ungrouped, fetch observations for all multi-obs packets and flatten + if (!groupByHash) { + const multiObs = packets.filter(p => (p.observation_count || p.count || 1) > 1); + await Promise.all(multiObs.map(async (p) => { + try { + const d = await api(`/packets/${p.hash}`); + if (d?.observations) p._children = d.observations.map(o => ({...d.packet, ...o, _isObservation: true})); + } catch {} + })); + // Flatten: replace grouped packets with individual observations + const flat = []; + for (const p of packets) { + if (p._children && p._children.length > 1) { + for (const c of p._children) flat.push(c); + } else { + flat.push(p); + } + } + packets = flat; + totalCount = flat.length; + } + // Pre-resolve all path hops to node names const allHops = new Set(); for (const p of packets) { @@ -780,7 +802,7 @@ const pathStr = renderPath(pathHops); const detail = getDetailPreview(decoded); - return `