Sanitized mirror from private repository - 2026-04-05 05:34:18 UTC
Some checks failed
Documentation / Build Docusaurus (push) Failing after 4m59s
Documentation / Deploy to GitHub Pages (push) Has been skipped

This commit is contained in:
Gitea Mirror Bot
2026-04-05 05:34:18 +00:00
commit 3406d7ce05
1390 changed files with 353978 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
"use client";
import { usePoll } from "@/lib/use-poll";
import { StatCard } from "@/components/stat-card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { StatusBadge } from "@/components/status-badge";
import { DataTable, Column } from "@/components/data-table";
interface AdGuardStats {
total_queries?: number;
num_dns_queries?: number;
blocked?: number;
num_blocked_filtering?: number;
avg_time?: number;
avg_processing_time?: number;
}
interface HeadscaleNode {
id: string;
name: string;
ip_addresses?: string[];
ip?: string;
online: boolean;
last_seen?: string;
}
interface DnsRewrite {
domain: string;
answer: string;
}
export default function NetworkPage() {
const { data: adguard } = usePoll<AdGuardStats>("/api/network/adguard", 60000);
const { data: nodesRaw } = usePoll<HeadscaleNode[] | { nodes: HeadscaleNode[] }>("/api/network/headscale", 30000);
const { data: rewritesRaw } = usePoll<DnsRewrite[] | { rewrites: DnsRewrite[] }>("/api/network/adguard/rewrites", 120000);
const nodes = Array.isArray(nodesRaw) ? nodesRaw : (nodesRaw?.nodes ?? []);
const rewrites = Array.isArray(rewritesRaw) ? rewritesRaw : (rewritesRaw?.rewrites ?? []);
const rewriteColumns: Column<DnsRewrite>[] = [
{
key: "domain",
label: "Domain",
render: (row) => <span className="font-medium text-foreground">{row.domain}</span>,
},
{ key: "answer", label: "Answer" },
];
return (
<div className="space-y-6">
<h1 className="text-lg font-semibold">Network</h1>
{/* Top row: AdGuard stats */}
<div className="grid grid-cols-1 sm:grid-cols-3 lg:grid-cols-3 gap-3 lg:gap-4">
<StatCard
label="Total Queries"
value={(() => { const v = adguard?.total_queries ?? adguard?.num_dns_queries; return v != null ? v.toLocaleString() : "\u2014"; })()}
sub="DNS queries"
/>
<StatCard
label="Blocked"
value={(() => { const v = adguard?.blocked ?? adguard?.num_blocked_filtering; return v != null ? v.toLocaleString() : "\u2014"; })()}
sub="blocked by filters"
/>
<StatCard
label="Avg Response"
value={(() => { const v = adguard?.avg_time ?? adguard?.avg_processing_time; return v != null ? `${(v * 1000).toFixed(1)}ms` : "\u2014"; })()}
sub="processing time"
/>
</div>
{/* Middle: Headscale nodes grid */}
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Headscale Nodes</CardTitle>
</CardHeader>
<CardContent>
{nodes.length === 0 ? (
<p className="text-xs text-muted-foreground">Loading...</p>
) : (
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3">
{nodes.map((node) => (
<Card key={node.id} className="overflow-hidden">
<CardContent className="pt-3 pb-3 px-4">
<div className="flex items-center gap-2 mb-1">
<span className={`w-2 h-2 rounded-full shrink-0 ${node.online ? "bg-green-500 glow-green" : "bg-red-500 glow-red"}`} />
<span className="text-sm font-medium text-foreground truncate">{node.name}</span>
</div>
<p className="text-[10px] text-muted-foreground font-mono">
{node.ip_addresses?.[0] ?? node.ip ?? "—"}
</p>
{node.last_seen && (
<p className="text-[10px] text-muted-foreground mt-0.5">
{new Date(node.last_seen).toLocaleString("en-US", {
month: "short", day: "numeric", hour: "2-digit", minute: "2-digit",
})}
</p>
)}
</CardContent>
</Card>
))}
</div>
)}
</CardContent>
</Card>
{/* Bottom: DNS rewrites table */}
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">DNS Rewrites</CardTitle>
</CardHeader>
<CardContent>
<DataTable<DnsRewrite>
data={rewrites}
columns={rewriteColumns}
searchKey="domain"
/>
</CardContent>
</Card>
</div>
);
}