Files
B.Tech-Project-III/thirdeye/dashboard/app/agents/AgentStats.tsx
2026-04-05 00:43:23 +05:30

105 lines
3.2 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { fetchGroups, fetchAllSignals, Group, Signal } from "../lib/api";
export default function AgentStats() {
const [groups, setGroups] = useState<Group[]>([]);
const [signals, setSignals] = useState<Signal[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function load() {
try {
const [grps, all] = await Promise.all([fetchGroups(), fetchAllSignals()]);
setGroups(grps);
setSignals(all.flatMap((g) => g.signals));
} catch {
// ignore
} finally {
setLoading(false);
}
}
load();
}, []);
const totalSignals = groups.reduce((acc, g) => acc + g.signal_count, 0);
const activeGroups = groups.filter((g) => g.signal_count > 0).length;
const criticalSignals = signals.filter(
(s) => s.metadata.severity === "critical" || s.metadata.severity === "high"
).length;
const errorRate =
totalSignals > 0
? `${((criticalSignals / totalSignals) * 100).toFixed(2)}%`
: "0.00%";
const stats = [
{
title: "Active Groups",
value: loading ? "—" : `${activeGroups} / ${groups.length}`,
icon: "memory",
iconColor: "#a88cfb",
},
{
title: "Total Signals",
value: loading ? "—" : totalSignals >= 1000 ? `${(totalSignals / 1000).toFixed(1)}k` : String(totalSignals),
icon: "speed",
iconColor: "#00daf3",
},
{
title: "High Priority",
value: loading ? "—" : `${criticalSignals}`,
icon: "warning",
iconColor: criticalSignals > 0 ? "#ff6f78" : "#10b981",
},
{
title: "Lens Coverage",
value: loading ? "—" : `${[...new Set(groups.map((g) => g.lens).filter(Boolean))].length} types`,
icon: "verified",
iconColor: "#10b981",
},
];
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 animate-fade-in-scale mb-8">
{stats.map((stat, idx) => (
<div
key={idx}
className="glass p-5 rounded-2xl border border-white/5 relative overflow-hidden group card-interactive flex flex-col justify-between"
style={{
minHeight: "100px",
background: "rgba(20,20,25,0.4)",
backdropFilter: "blur(12px)",
}}
>
<p className="text-[10px] uppercase tracking-widest text-zinc-500 font-mono-data mb-3">
{stat.title}
</p>
<div className="flex flex-row items-end justify-between">
<h3 className="text-2xl font-light tracking-wide text-zinc-200 font-mono-data drop-shadow">
{stat.value.split(" ").map((part, i) => (
<span
key={i}
className={
i % 2 !== 0 && part.match(/[a-zA-Z]/)
? "text-sm ml-1 text-zinc-500"
: ""
}
>
{part}{" "}
</span>
))}
</h3>
<span
className="material-symbols-outlined text-[24px] opacity-90 drop-shadow-md"
style={{ color: stat.iconColor }}
>
{stat.icon}
</span>
</div>
</div>
))}
</div>
);
}