Merge branch 'main' into dev

Signed-off-by: MrAlders0n <55921894+MrAlders0n@users.noreply.github.com>
This commit is contained in:
MrAlders0n
2026-07-14 23:17:55 -04:00
committed by GitHub
4 changed files with 16 additions and 36 deletions
-1
View File
@@ -15,7 +15,6 @@ export interface NodeSummary {
defaultScope?: string; // most recently matched transport scope name, e.g. "#bc"
iatas: NodeIATA[];
knownNeighborCount: number; // distinct first-hop neighbors we've resolved for this node
neighborIds?: string[]; // first-hop neighbor node ids; only present when the list request opts in (?neighbors)
// Set when this node also runs as an observer (watches traffic for uplink). isObserver drives the
// map's observer-pip marker variant; observerId, when present, links to that observer's detail.
isObserver?: boolean;
+1 -1
View File
@@ -1,6 +1,6 @@
import { useMemo } from "react";
import { formatCount } from "../../lib/formatters";
import { useChartColors, nodeTypeColor } from "./chartTheme";
import { useChartColors, type ChartColors } from "./chartTheme";
import { useStatsOverview, useStatsObservations, usePayloadBreakdown, useTopNodes, useTopObservers, useRadioPresets, useScopes, useNodeTypes } from "./useStats";
import { observationsAreaOption, leaderboardOption, typeBarOption, donutOption, presetBarsOption } from "./chartOptions";
import { Card, ChartCard, StatCard } from "./cards";
+14 -33
View File
@@ -59,40 +59,21 @@ interface Props {
}
export function StatsSubHeader({ tab, onTabChange, range, onRangeChange }: Props) {
const isMobile = useIsMobile();
return (
<div className="flex shrink-0 flex-wrap items-center justify-between gap-2 border-b border-border bg-bg-surface px-4 py-2.5">
{/* pills don't scale on a phone as sections grow — swap to a compact dropdown there */}
{isMobile ? (
<SelectDropdown
label="Section"
hideAll
align="left"
options={TAB_SELECT_OPTIONS}
value={tab}
onChange={(v) => onTabChange(v as StatsTab)}
/>
) : (
<div className="min-w-0 max-w-full overflow-x-auto">
<Segmented
options={TAB_OPTIONS}
value={tab}
onChange={(v) => onTabChange(v as StatsTab)}
ariaLabel="Stats section"
size="md"
/>
</div>
)}
{/* the graph is topology, not time-series — no range to pick */}
{tab !== "graph" && (
<Segmented
className="shrink-0"
options={RANGE_OPTIONS}
value={range}
onChange={(v) => onRangeChange(v as StatsRange)}
ariaLabel="Time range"
/>
)}
<div className="flex shrink-0 items-center justify-between border-b border-border bg-bg-surface px-4 py-2.5">
<Segmented
options={TAB_OPTIONS}
value={tab}
onChange={(v) => onTabChange(v as StatsTab)}
ariaLabel="Stats section"
size="md"
/>
<Segmented
options={RANGE_OPTIONS}
value={range}
onChange={(v) => onRangeChange(v as StatsRange)}
ariaLabel="Time range"
/>
</div>
);
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { getPackets, getNodesPage, getObserversPage, getScopes, getKnownRoutesPage, searchKnownRoutes, getChannels, getChannelMessagesPage, getTraces, getTraceDetail, getStatsOverview, getTopObservers, getStatsNodeTypes } from "../../src/api/client";
import { getNodesPage, getObserversPage, getScopes, getKnownRoutesPage, searchKnownRoutes, getChannels, getChannelMessagesPage, getTraces, getTraceDetail, getStatsOverview, getTopObservers, getStatsNodeTypes } from "../../src/api/client";
import type { NodeSummary } from "../../src/features/nodes/types";
import type { ObserverSummary } from "../../src/features/observers/types";
import type { ChannelMessage, ChannelSummary } from "../../src/features/channels/types";