From 0e9bd59b4444c51b060c4cfdede9be3c0d521573 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Thu, 16 Apr 2026 11:59:35 -0700 Subject: [PATCH] Show learned path in routing override. Closes #195. --- .../components/ContactPathDiscoveryModal.tsx | 32 +++---------------- .../ContactRoutingOverrideModal.tsx | 22 +++---------- frontend/src/utils/pathUtils.ts | 31 ++++++++++++++++++ 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/frontend/src/components/ContactPathDiscoveryModal.tsx b/frontend/src/components/ContactPathDiscoveryModal.tsx index e85e60e..c5b5a6f 100644 --- a/frontend/src/components/ContactPathDiscoveryModal.tsx +++ b/frontend/src/components/ContactPathDiscoveryModal.tsx @@ -3,10 +3,9 @@ import { useMemo, useState } from 'react'; import type { Contact, PathDiscoveryResponse, PathDiscoveryRoute } from '../types'; import { findContactsByPrefix, + formatForcedRouteSummary, + formatLearnedRouteSummary, formatRouteLabel, - getDirectContactRoute, - getEffectiveContactRoute, - hasRoutingOverride, parsePathHops, } from '../utils/pathUtils'; import { Button } from './ui/button'; @@ -99,30 +98,9 @@ export function ContactPathDiscoveryModal({ const [error, setError] = useState(null); const [result, setResult] = useState(null); - const effectiveRoute = useMemo(() => getEffectiveContactRoute(contact), [contact]); - const directRoute = useMemo(() => getDirectContactRoute(contact), [contact]); - const hasForcedRoute = hasRoutingOverride(contact); - const learnedRouteSummary = useMemo(() => { - if (!directRoute) { - return 'Flood'; - } - const hops = parsePathHops(directRoute.path, directRoute.path_len); - return hops.length > 0 - ? `${formatRouteLabel(directRoute.path_len, true)} (${hops.join(' -> ')})` - : formatRouteLabel(directRoute.path_len, true); - }, [directRoute]); - const forcedRouteSummary = useMemo(() => { - if (!hasForcedRoute) { - return null; - } - if (effectiveRoute.pathLen === -1) { - return 'Flood'; - } - const hops = parsePathHops(effectiveRoute.path, effectiveRoute.pathLen); - return hops.length > 0 - ? `${formatRouteLabel(effectiveRoute.pathLen, true)} (${hops.join(' -> ')})` - : formatRouteLabel(effectiveRoute.pathLen, true); - }, [effectiveRoute, hasForcedRoute]); + const learnedRouteSummary = useMemo(() => formatLearnedRouteSummary(contact), [contact]); + const forcedRouteSummary = useMemo(() => formatForcedRouteSummary(contact), [contact]); + const hasForcedRoute = forcedRouteSummary !== null; const forwardChain = result ? renderRouteNodes( diff --git a/frontend/src/components/ContactRoutingOverrideModal.tsx b/frontend/src/components/ContactRoutingOverrideModal.tsx index fd1badc..9e190c0 100644 --- a/frontend/src/components/ContactRoutingOverrideModal.tsx +++ b/frontend/src/components/ContactRoutingOverrideModal.tsx @@ -3,10 +3,9 @@ import { useEffect, useMemo, useState } from 'react'; import { api } from '../api'; import type { Contact } from '../types'; import { - formatRouteLabel, + formatForcedRouteSummary, + formatLearnedRouteSummary, formatRoutingOverrideInput, - getDirectContactRoute, - hasRoutingOverride, } from '../utils/pathUtils'; import { Button } from './ui/button'; import { @@ -28,18 +27,6 @@ interface ContactRoutingOverrideModalProps { onError: (message: string) => void; } -function summarizeLearnedRoute(contact: Contact): string { - return formatRouteLabel(getDirectContactRoute(contact)?.path_len ?? -1, true); -} - -function summarizeForcedRoute(contact: Contact): string | null { - if (!hasRoutingOverride(contact)) { - return null; - } - const routeOverrideLen = contact.route_override_len; - return routeOverrideLen == null ? null : formatRouteLabel(routeOverrideLen, true); -} - export function ContactRoutingOverrideModal({ open, onClose, @@ -59,7 +46,8 @@ export function ContactRoutingOverrideModal({ setError(null); }, [contact, open]); - const forcedRouteSummary = useMemo(() => summarizeForcedRoute(contact), [contact]); + const learnedRouteSummary = useMemo(() => formatLearnedRouteSummary(contact), [contact]); + const forcedRouteSummary = useMemo(() => formatForcedRouteSummary(contact), [contact]); const saveRoute = async (value: string) => { setSaving(true); @@ -98,7 +86,7 @@ export function ContactRoutingOverrideModal({
{contact.name || contact.public_key.slice(0, 12)}
- Current learned route: {summarizeLearnedRoute(contact)} + Current learned route: {learnedRouteSummary}
{forcedRouteSummary && (
diff --git a/frontend/src/utils/pathUtils.ts b/frontend/src/utils/pathUtils.ts index 547f559..ed4dcfc 100644 --- a/frontend/src/utils/pathUtils.ts +++ b/frontend/src/utils/pathUtils.ts @@ -209,6 +209,37 @@ export function formatRouteLabel(pathLen: number, capitalize: boolean = false): return capitalize ? label.charAt(0).toUpperCase() + label.slice(1) : label; } +/** + * Format the learned direct route for display in route-editing dialogs, + * e.g. "2 hops (AE -> F1)", "Direct", or "Flood". + */ +export function formatLearnedRouteSummary(contact: Contact): string { + const directRoute = getDirectContactRoute(contact); + if (!directRoute) { + return formatRouteLabel(-1, true); + } + const hops = parsePathHops(directRoute.path, directRoute.path_len); + const label = formatRouteLabel(directRoute.path_len, true); + return hops.length > 0 ? `${label} (${hops.join(' -> ')})` : label; +} + +/** + * Format the forced (override) route for display in route-editing dialogs, + * matching the learned-route format. Returns null when no override is set. + */ +export function formatForcedRouteSummary(contact: Contact): string | null { + if (!hasRoutingOverride(contact)) { + return null; + } + const effectiveRoute = getEffectiveContactRoute(contact); + if (effectiveRoute.pathLen === -1) { + return formatRouteLabel(-1, true); + } + const hops = parsePathHops(effectiveRoute.path, effectiveRoute.pathLen); + const label = formatRouteLabel(effectiveRoute.pathLen, true); + return hops.length > 0 ? `${label} (${hops.join(' -> ')})` : label; +} + export function formatRoutingOverrideInput(contact: Contact): string { const routeOverride = getRouteOverride(contact); if (!routeOverride) {