Add fleet evolution: genetic breeding, atlas gossip, BGP router, seeder/miner, genealogy, court gates, APK scout, personas, WSUS mimic, and P2 test coverage
This commit is contained in:
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { api } from '../api/client';
|
||||
import { useModalAmbientDuck } from '../context/AmbientMusicContext';
|
||||
import { useWebSocket } from '../hooks/useWebSocket';
|
||||
import type { Agent, PathTraceHop } from '../types';
|
||||
import type { Agent, PathTraceHop, SpreadRouteRecommendation } from '../types';
|
||||
import { HelpTip } from '../components/HelpTip';
|
||||
import './PathTracerPage.css';
|
||||
|
||||
@@ -13,6 +13,7 @@ interface TraceStatus {
|
||||
ready: boolean;
|
||||
error?: string;
|
||||
hops: PathTraceHop[];
|
||||
spread_routes?: SpreadRouteRecommendation[];
|
||||
}
|
||||
|
||||
interface QRData {
|
||||
@@ -111,6 +112,7 @@ export default function PathTracerPage() {
|
||||
const [tracing, setTracing] = useState(false);
|
||||
const [qr, setQR] = useState<QRData | null>(null);
|
||||
const [showQR, setShowQR] = useState(false);
|
||||
const [spreadRoutes, setSpreadRoutes] = useState<SpreadRouteRecommendation[]>([]);
|
||||
|
||||
const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
const [autoEndCountdown, setAutoEndCountdown] = useState<number | null>(null);
|
||||
@@ -146,6 +148,7 @@ export default function PathTracerPage() {
|
||||
setTracing(true);
|
||||
setHops([]);
|
||||
setQR(null);
|
||||
setSpreadRoutes([]);
|
||||
try {
|
||||
const res = await api.startTrace(selected);
|
||||
setSessionID(res.session_id);
|
||||
@@ -165,6 +168,9 @@ export default function PathTracerPage() {
|
||||
try {
|
||||
const status: TraceStatus = await api.getTraceStatus(sid);
|
||||
setHops(status.hops);
|
||||
if (status.spread_routes?.length) {
|
||||
setSpreadRoutes(status.spread_routes);
|
||||
}
|
||||
if (status.error) {
|
||||
setError(status.error);
|
||||
clearInterval(pollRef.current!);
|
||||
@@ -205,6 +211,7 @@ export default function PathTracerPage() {
|
||||
setTracing(false);
|
||||
setQR(null);
|
||||
setSelected([]);
|
||||
setSpreadRoutes([]);
|
||||
setError('');
|
||||
}, [sessionID]);
|
||||
|
||||
@@ -418,6 +425,21 @@ export default function PathTracerPage() {
|
||||
✓ All hops ready — tunnel is active.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{spreadRoutes.length > 0 && (
|
||||
<div className="pt-route-hints" style={{ marginTop: '0.75rem' }}>
|
||||
<div className="pt-chain-title">Spread Routes</div>
|
||||
<ul style={{ margin: '0.35rem 0 0', paddingLeft: '1rem', fontSize: '0.65rem', fontFamily: 'monospace', color: '#00ffaa99' }}>
|
||||
{spreadRoutes.map((route) => (
|
||||
<li key={`${route.target_subnet}-${route.seed_agent_id}`}>
|
||||
{route.target_subnet} → {route.seed_agent_name ?? route.seed_agent_id.slice(0, 8)}
|
||||
{route.join_lane ? ` (${route.join_lane})` : ''}
|
||||
{route.score ? ` · ${route.score.toFixed(2)}` : ''}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user