Skip to content

Add traceroute-inferred links to map and detail panel#366

Merged
SimmerV merged 5 commits intoMeshAddicts:developfrom
SimmerV:feature-add
Mar 20, 2026
Merged

Add traceroute-inferred links to map and detail panel#366
SimmerV merged 5 commits intoMeshAddicts:developfrom
SimmerV:feature-add

Conversation

@SimmerV
Copy link
Copy Markdown
Collaborator

@SimmerV SimmerV commented Mar 20, 2026

Summary

  • Infer mesh topology links from traceroute hop data, supplementing the largely defunct NeighborInfo module (disabled/MQTT-only since Meshtastic firmware 2.5.13)
  • Draw traceroute-inferred links on the map in amber (#F59E0B), distinct from green/blue/purple neighbor links, across all three link display modes (Selected Node, All Nodes, My Node)
  • Deduplicate traceroute edges against existing neighbor edges so neighbor data takes priority when both exist
  • Add "Traceroute Links" section to the node details panel showing adjacent nodes and route counts
  • Compact the details panel layout: single-line position/status fields, shortened location (city, state) with full address on hover
  • Make node names in all detail panel tables (Neighbors Heard, Heard By, Traceroute Links) clickable to navigate to that node on the map — only styled as links when the target node has a map position

@SimmerV SimmerV self-assigned this Mar 20, 2026
@SimmerV SimmerV added this to meshinfo Mar 20, 2026
@SimmerV SimmerV added the enhancement New feature or request label Mar 20, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in meshinfo Mar 20, 2026
@daviesgeek daviesgeek requested a review from Copilot March 20, 2026 04:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds traceroute-derived topology links to the map/link layers and extends the node details panel to surface traceroute-adjacent nodes and make table node names navigable.

Changes:

  • Infer and render traceroute-based links (amber) alongside neighbor/heard-by links, with neighbor links intended to take priority when both exist.
  • Extend the node details panel with a “Traceroute Links” section and make node names in tables clickable for navigation.
  • Compact details panel layout (single-line fields, shortened location with full address on hover) and update the legend to include traceroute links.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
frontend/src/pages/map/detailsHtml.ts Adds traceroute link section, clickable node labels, ID normalization, and traceroute link GeoJSON builder.
frontend/src/pages/map/detailsDom.ts Adds wiring to handle clicks on data-select-node elements in injected HTML.
frontend/src/pages/map/MapLegend.tsx Adds legend entry for amber traceroute links.
frontend/src/pages/Map.tsx Fetches traceroutes, merges traceroute links into link layers across modes, and wires details-panel node navigation.
Comments suppressed due to low confidence (1)

frontend/src/pages/Map.tsx:1414

  • In the OpenLayers (OSM) provider path, selected-node rendering still draws only neighbor lines (green) and does not draw traceroute-inferred links, even though traceroutes are now passed into buildNodeDetailsHtml. If traceroute links are intended to appear in "Selected Node" mode for both providers, consider adding traceroute line rendering here (and using the same amber color / neighbor-edge dedupe as the Mapbox path).
      const { html } = buildNodeDetailsHtml({
        node: nodeLike,
        liveNodes: nodes,
        displayName,
        elsewhereLinks: config?.mesh?.elsewhere_links,
        traceroutes: traceroutesRef.current,
      });

      setDetailsPanelContent({
        title: node.longname ?? "",
        subtitle: node.shortname ?? "",
        html,
        onNodeSelect: (targetId) => {
          const targetNode = nodes[targetId];
          if (!targetNode?.map_position) return;
          void handleNodeDetails({
            id: targetId,
            shortname: targetNode.shortname,
            longname: targetNode.longname,
            last_seen: targetNode.last_seen,
            position: [targetNode.map_position[0], targetNode.map_position[1]] as Coordinate,
            online: Boolean(targetNode.online),
            neighbors: targetNode.neighbors,
          });
        },
      });

      // Draw neighbor lines
      node.neighbors?.forEach((neighbor) => {
        const nnode = nodes[neighbor.id];
        if (!nnode?.map_position) return;

        const points: Coordinate[] = [node.position, nnode.map_position];
        for (let i = 0; i < points.length; i++) {
          points[i] = transform(points[i], "EPSG:4326", "EPSG:3857");
        }

        const featureLine = new Feature({ geometry: new LineString(points) });
        const vectorLine = new Vector({});
        vectorLine.addFeature(featureLine);

        const vectorLineLayer = new VectorLayer({
          source: vectorLine,
          style: new Style({
            fill: new Fill({ color: "#66FF66" }),
            stroke: new Stroke({ color: "#66FF66", width: 4 }),
          }),
        });

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frontend/src/pages/Map.tsx Outdated
Comment thread frontend/src/pages/Map.tsx
Comment thread frontend/src/pages/Map.tsx
Comment thread frontend/src/pages/map/detailsHtml.ts Outdated
Comment thread frontend/src/pages/map/detailsHtml.ts Outdated
Comment thread frontend/src/pages/map/detailsHtml.ts Outdated
SimmerV and others added 2 commits March 19, 2026 22:17
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@SimmerV SimmerV merged commit 0da64da into MeshAddicts:develop Mar 20, 2026
5 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in meshinfo Mar 20, 2026
@daviesgeek daviesgeek requested a review from Copilot March 20, 2026 23:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +432 to +434
}),
liveNodes,
);
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In "mynode" mode, traceroute links are built without passing neighborEdgeKeys, so traceroute-inferred edges that overlap existing neighbor edges will still be emitted. This breaks the stated priority of neighbor data over traceroute data and can render duplicate/ambiguous links; consider reusing collectNeighborEdgeKeys(liveNodes) here and passing it as the third argument to buildTracerouteLinkFeatureCollection.

Copilot uses AI. Check for mistakes.
Comment on lines +912 to +914
}),
liveNodes,
);
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selected-node link rendering builds traceroute links without providing neighborEdgeKeys, so any traceroute segment that matches an existing neighbor edge will still be drawn (neighbor priority/deduplication won’t apply in this mode). Pass the same neighbor edge key set used elsewhere (e.g., collectNeighborEdgeKeys(liveNodes)) to buildTracerouteLinkFeatureCollection to suppress overlapping traceroute edges.

Copilot uses AI. Check for mistakes.
return (raw >>> 0).toString(16).toLowerCase();
}
let s = String(raw).trim();
if (/^\d+$/.test(s) && s.length > 6) {
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normNodeId treats any digit-only string with length > 6 as a decimal ID and converts it to hex. This will mis-normalize legitimate hex node IDs that happen to be digits-only (including zero-padded 8-char IDs like "00123456"), causing traceroute edges to fail to match liveNodes/neighborEdgeKeys and potentially linking the wrong nodes. Consider only applying the decimal-string conversion when the string length is greater than the expected hex width (e.g., > 8 for 32-bit node IDs), or otherwise making the decimal-vs-hex distinction explicit.

Suggested change
if (/^\d+$/.test(s) && s.length > 6) {
// Treat as decimal only if it's digit-only and longer than the max 32-bit hex width (8 chars)
if (/^\d+$/.test(s) && s.length > 8) {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants