first commit
This commit is contained in:
36
frontend/components/Shell.tsx
Normal file
36
frontend/components/Shell.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
|
||||
export default function Shell({ children }: { children: React.ReactNode }) {
|
||||
const [me, setMe] = useState<{email:string, role:string} | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
apiFetch("/auth/me").then(setMe).catch(() => setMe(null));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex">
|
||||
<aside className="w-64 shrink-0 border-r border-zinc-800 min-h-screen p-4">
|
||||
<div className="text-lg font-semibold">mt-traffic</div>
|
||||
<div className="mt-4 space-y-2 text-sm">
|
||||
<Link className="block hover:text-white text-zinc-300" href="/dashboards">Dashboards</Link>
|
||||
<Link className="block hover:text-white text-zinc-300" href="/admin">Admin</Link>
|
||||
</div>
|
||||
<div className="mt-6 text-xs text-zinc-400">
|
||||
{me ? (
|
||||
<div>
|
||||
<div>{me.email}</div>
|
||||
<div className="uppercase">{me.role}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>Not logged in</div>
|
||||
)}
|
||||
</div>
|
||||
</aside>
|
||||
<main className="flex-1 p-6">{children}</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
31
frontend/components/TrafficChart.tsx
Normal file
31
frontend/components/TrafficChart.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
"use client";
|
||||
|
||||
import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer, Legend } from "recharts";
|
||||
|
||||
type Point = { t: string } & Record<string, number>;
|
||||
|
||||
function fmtBps(v: number) {
|
||||
const units = ["bps","Kbps","Mbps","Gbps"];
|
||||
let val = v, i = 0;
|
||||
while (val >= 1000 && i < units.length-1) { val /= 1000; i++; }
|
||||
const digits = val < 10 && i > 0 ? 2 : 0;
|
||||
return `${val.toFixed(digits)} ${units[i]}`;
|
||||
}
|
||||
|
||||
export default function TrafficChart({ data, series }: { data: Point[]; series: string[] }) {
|
||||
return (
|
||||
<div className="h-64 w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<LineChart data={data}>
|
||||
<XAxis dataKey="t" tick={{ fontSize: 12 }} />
|
||||
<YAxis tick={{ fontSize: 12 }} tickFormatter={(v)=>fmtBps(Number(v))} />
|
||||
<Tooltip formatter={(v:any)=>fmtBps(Number(v))} />
|
||||
<Legend />
|
||||
{series.map((s) => (
|
||||
<Line key={s} type="monotone" dataKey={s} dot={false} strokeWidth={2} />
|
||||
))}
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user