Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,23 @@ function AppInner() {
if (id === null) dropSelectionParam("observer");
}, [dropSelectionParam]);

// Jump from a node's detail panel to its location on the Map tab, framed close on that node.
// Bypasses handleTabChange (like handleViewObserverStats) so selectedNodeId survives the switch on
// mobile too — the point of this action is to keep the same node's panel open, now over the map.
const handleViewOnMap = useCallback(
(lat: number, lng: number) => {
setSearchParams((prev) => {
const next = new URLSearchParams(prev);
next.set("tab", "Map");
next.set("lat", lat.toFixed(5));
next.set("lng", lng.toFixed(5));
next.set("zoom", "14");
return next;
});
},
[setSearchParams],
);

// Jump from an observer's detail panel to its telemetry on the Stats tab (Stats → Observer, preselected).
const handleViewObserverStats = useCallback(
(id: string) => {
Expand Down Expand Up @@ -340,6 +357,7 @@ function AppInner() {
}}
onViewNode={setSelectedNodeId}
onAnalyzePacket={setOverlayPacketHash}
onViewOnMap={handleViewOnMap}
/>
)}
{overlayNodeId && (
Expand All @@ -351,6 +369,15 @@ function AppInner() {
setSelectedObserverId(observerId);
}}
onViewNode={setOverlayNodeId}
onViewOnMap={(lat, lng) => {
// handleViewOnMap bypasses handleTabChange (see its own comment), so the overlay
// won't be cleared as a side effect here the way onViewObserver's handleTabChange
// call clears it above — close it and promote the node into the shared selection
// explicitly, so NodeDetailPanel (not this overlay) is what reopens on the Map tab.
handleViewOnMap(lat, lng);
setSelectedNodeId(overlayNodeId);
setOverlayNodeId(null);
}}
/>
)}
{overlayPacketHash && (
Expand Down
5 changes: 3 additions & 2 deletions src/features/nodes/NodeDetailOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { ModalOverlay } from "../../components/ModalOverlay";

// Node detail shown as a modal over the packet analyzer: the panel sits where the packet drawer is
// (right side) and the rest dims, so a user can peek at a path hop's node and close back to the packet.
export function NodeDetailOverlay({ nodeId, onClose, onViewObserver, onViewNode }: {
export function NodeDetailOverlay({ nodeId, onClose, onViewObserver, onViewNode, onViewOnMap }: {
nodeId: string;
onClose: () => void;
onViewObserver: (observerId: string) => void;
onViewNode?: (nodeId: string) => void;
onViewOnMap?: (lat: number, lng: number) => void;
}) {
useEffect(() => {
function onKey(e: KeyboardEvent) {
Expand All @@ -20,7 +21,7 @@ export function NodeDetailOverlay({ nodeId, onClose, onViewObserver, onViewNode

return (
<ModalOverlay label="Node detail" onClose={onClose}>
<NodeDetailPanel nodeId={nodeId} onClose={onClose} onViewObserver={onViewObserver} onViewNode={onViewNode} />
<NodeDetailPanel nodeId={nodeId} onClose={onClose} onViewObserver={onViewObserver} onViewNode={onViewNode} onViewOnMap={onViewOnMap} />
</ModalOverlay>
);
}
16 changes: 15 additions & 1 deletion src/features/nodes/NodeDetailPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ interface NodeDetailPanelProps {
onViewObserver: (observerId: string) => void;
onViewNode?: (nodeId: string) => void;
onAnalyzePacket?: (hash: string) => void;
onViewOnMap?: (lat: number, lng: number) => void;
}

export function NodeDetailPanel({ nodeId, onClose, onViewObserver, onViewNode, onAnalyzePacket }: NodeDetailPanelProps) {
export function NodeDetailPanel({ nodeId, onClose, onViewObserver, onViewNode, onAnalyzePacket, onViewOnMap }: NodeDetailPanelProps) {
const { data: node, isLoading } = useQuery({
queryKey: ["node", nodeId],
queryFn: () => getNode(nodeId),
Expand Down Expand Up @@ -145,6 +146,19 @@ export function NodeDetailPanel({ nodeId, onClose, onViewObserver, onViewNode, o
{node.lng != null && <Field label="Lng" value={node.lng.toFixed(5)} />}
{node.locationSource && <Field label="Source" value={node.locationSource} />}
</div>
{hasLocation && onViewOnMap && (
<button
type="button"
onClick={() => onViewOnMap(node.lat!, node.lng!)}
className="mt-2 w-full flex items-center justify-center gap-1.5 rounded border border-border bg-bg-base px-3 py-1.5 text-[13px] font-mono text-text-normal hover:bg-text-normal/3 transition-colors"
>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" aria-hidden>
<path d="M9 5l-6 2v12l6-2 6 2 6-2V5l-6 2-6-2z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
<path d="M9 5v12M15 7v12" stroke="currentColor" strokeWidth="1.4" />
</svg>
View on map
</button>
)}
</Section>
)}

Expand Down