diff --git a/meshexplorer/src/app/(app)/meshcore/node/[publicKey]/page.tsx b/meshexplorer/src/app/(app)/meshcore/node/[publicKey]/page.tsx index f4aaa8f..ba97c2d 100644 --- a/meshexplorer/src/app/(app)/meshcore/node/[publicKey]/page.tsx +++ b/meshexplorer/src/app/(app)/meshcore/node/[publicKey]/page.tsx @@ -9,7 +9,7 @@ import { formatPublicKey } from "@/lib/meshcore"; import { getNameIconLabel } from "@/lib/meshcore-map-nodeutils"; import AdvertDetails from "@/components/AdvertDetails"; import ContactQRCode from "@/components/ContactQRCode"; -import { useConfig, LAST_SEEN_OPTIONS } from "@/components/ConfigContext"; +import { useConfig, LAST_SEEN_OPTIONS, neighborMinConfidenceOf } from "@/components/ConfigContext"; import { useNeighbors, type Neighbor } from "@/hooks/useNeighbors"; import { useNodeData, type NodeData, type NodeInfo, type Advert, type LocationHistory, type MqttInfo, type NodeError } from "@/hooks/useNodeData"; import { ArrowRightEndOnRectangleIcon, ArrowRightStartOnRectangleIcon } from "@heroicons/react/24/outline"; @@ -54,6 +54,34 @@ export default function MeshcoreNodePage() { enabled: !!publicKey }); + // Inferred neighbors from the unified neighbor graph (path/anchor derived), filtered by the user's + // global confidence preference. Exclude 'direct' (already shown above) and any neighbor already in + // the direct list, so this section only adds genuinely inferred links. + const { + data: allEdges = [], + isLoading: inferredLoading + } = useNeighbors({ + nodeId: publicKey, + lastSeen: config.lastSeen, + mode: 'all', + minConfidence: neighborMinConfidenceOf(config), + enabled: !!publicKey + }); + const directKeys = new Set(neighbors.map(n => n.public_key)); + const inferredNeighbors = allEdges.filter(n => n.method !== 'direct' && !directKeys.has(n.public_key)); + const methodLabel = (m?: string) => + m === 'anchor-gateway' || m === 'anchor-origin' ? 'Anchored' + : m === 'path-uniq-3b' ? 'Path (3-byte)' + : m === 'path-uniq-2b' ? 'Path (2-byte)' + : m === 'path-uniq-1b' ? 'Path (1-byte)' + : 'Inferred'; + // One list: directly-heard neighbors first, then inferred ones, each flagged so the card can show + // either direction arrows (direct) or an inference indicator (inferred). + const combinedNeighbors = [ + ...neighbors.map(n => ({ ...n, inferred: false })), + ...inferredNeighbors.map(n => ({ ...n, inferred: true })), + ]; + // Extract error information from TanStack Query error const error = queryError?.error || null; const errorCode = queryError?.code || null; @@ -406,10 +434,10 @@ export default function MeshcoreNodePage() {
- Nodes heard directly by this node + Heard directly, or inferred from routing paths & adverts {config.lastSeen !== null && ( Last {(() => { @@ -421,18 +449,18 @@ export default function MeshcoreNodePage() {
+ Minimum confidence for inferred neighbor links (map & node pages) +
- Higher tiers show only the most trustworthy links (MQTT-direct, then anchored / extended-hash) -
-