Add statistics

This commit is contained in:
Jack Kingsman
2026-03-07 23:17:10 -08:00
parent 20af50585b
commit b3625b4937
6 changed files with 189 additions and 1 deletions
@@ -3,6 +3,10 @@ import { Separator } from '../ui/separator';
import { api } from '../../api';
import type { StatisticsResponse } from '../../types';
function formatPercent(value: number): string {
return `${value.toFixed(1)}%`;
}
export function SettingsStatisticsSection({ className }: { className?: string }) {
const [stats, setStats] = useState<StatisticsResponse | null>(null);
const [statsLoading, setStatsLoading] = useState(false);
@@ -34,7 +38,9 @@ export function SettingsStatisticsSection({ className }: { className?: string })
return (
<div className={className}>
{statsLoading && !stats ? (
<div className="py-8 text-center text-muted-foreground">Loading statistics...</div>
<div className="py-8 text-center text-muted-foreground">
Loading statistics... this can take a while if you have a lot of stored packets.
</div>
) : stats ? (
<div className="space-y-6">
{/* Network */}
@@ -100,6 +106,39 @@ export function SettingsStatisticsSection({ className }: { className?: string })
<Separator />
<div>
<h4 className="text-sm font-medium mb-2">Path Hash Width (24h)</h4>
<div className="mb-2 text-xs text-muted-foreground">
Parsed stored raw packets from the last 24 hours:{' '}
{stats.path_hash_width_24h.total_packets}
</div>
<div className="space-y-2">
<div className="flex justify-between items-center text-sm">
<span>1-byte hops</span>
<span className="text-muted-foreground">
{stats.path_hash_width_24h.single_byte} (
{formatPercent(stats.path_hash_width_24h.single_byte_pct)})
</span>
</div>
<div className="flex justify-between items-center text-sm">
<span>2-byte hops</span>
<span className="text-muted-foreground">
{stats.path_hash_width_24h.double_byte} (
{formatPercent(stats.path_hash_width_24h.double_byte_pct)})
</span>
</div>
<div className="flex justify-between items-center text-sm">
<span>3-byte hops</span>
<span className="text-muted-foreground">
{stats.path_hash_width_24h.triple_byte} (
{formatPercent(stats.path_hash_width_24h.triple_byte_pct)})
</span>
</div>
</div>
</div>
<Separator />
{/* Activity */}
<div>
<h4 className="text-sm font-medium mb-2">Activity</h4>
+26
View File
@@ -378,6 +378,15 @@ describe('SettingsModal', () => {
total_outgoing: 30,
contacts_heard: { last_hour: 2, last_24_hours: 7, last_week: 10 },
repeaters_heard: { last_hour: 1, last_24_hours: 3, last_week: 3 },
path_hash_width_24h: {
total_packets: 120,
single_byte: 60,
double_byte: 36,
triple_byte: 24,
single_byte_pct: 50,
double_byte_pct: 30,
triple_byte_pct: 20,
},
};
vi.spyOn(globalThis, 'fetch').mockResolvedValue(
@@ -405,6 +414,14 @@ describe('SettingsModal', () => {
expect(screen.getByText('Total stored')).toBeInTheDocument();
expect(screen.getByText('Decrypted')).toBeInTheDocument();
expect(screen.getByText('Undecrypted')).toBeInTheDocument();
expect(screen.getByText('Path Hash Width (24h)')).toBeInTheDocument();
expect(
screen.getByText(/Parsed stored raw packets from the last 24 hours: 120/)
).toBeInTheDocument();
expect(screen.getByText('1-byte hops')).toBeInTheDocument();
expect(screen.getByText('60 (50.0%)')).toBeInTheDocument();
expect(screen.getByText('36 (30.0%)')).toBeInTheDocument();
expect(screen.getByText('24 (20.0%)')).toBeInTheDocument();
expect(screen.getByText('Contacts heard')).toBeInTheDocument();
expect(screen.getByText('Repeaters heard')).toBeInTheDocument();
@@ -427,6 +444,15 @@ describe('SettingsModal', () => {
total_outgoing: 30,
contacts_heard: { last_hour: 2, last_24_hours: 7, last_week: 10 },
repeaters_heard: { last_hour: 1, last_24_hours: 3, last_week: 3 },
path_hash_width_24h: {
total_packets: 120,
single_byte: 60,
double_byte: 36,
triple_byte: 24,
single_byte_pct: 50,
double_byte_pct: 30,
triple_byte_pct: 20,
},
};
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
+9
View File
@@ -398,4 +398,13 @@ export interface StatisticsResponse {
total_outgoing: number;
contacts_heard: ContactActivityCounts;
repeaters_heard: ContactActivityCounts;
path_hash_width_24h: {
total_packets: number;
single_byte: number;
double_byte: number;
triple_byte: number;
single_byte_pct: number;
double_byte_pct: number;
triple_byte_pct: number;
};
}