feat: (ui) first dynamic data

This commit is contained in:
syntaxbullet
2026-01-09 15:22:13 +01:00
parent 1b84dbd36d
commit 4a691ac71d
4 changed files with 117 additions and 12 deletions

View File

@@ -28,6 +28,7 @@ export function getClientStats(): ClientStats {
ping: AuroraClient.ws.ping,
cachedUsers: AuroraClient.users.cache.size,
commandsRegistered: AuroraClient.commands.size,
commandsKnown: AuroraClient.knownCommands.size,
uptime: process.uptime(),
lastCommandTimestamp: AuroraClient.lastCommandTimestamp,
};

View File

@@ -25,6 +25,8 @@ export const DashboardStatsSchema = z.object({
}),
commands: z.object({
total: z.number(),
active: z.number(),
disabled: z.number(),
changePercentFromLastMonth: z.number().optional(),
}),
ping: z.object({
@@ -53,6 +55,7 @@ export const ClientStatsSchema = z.object({
ping: z.number(),
cachedUsers: z.number(),
commandsRegistered: z.number(),
commandsKnown: z.number(),
uptime: z.number(),
lastCommandTimestamp: z.number().nullable(),
});

View File

@@ -2,6 +2,10 @@ import React from "react";
import { Link } from "react-router-dom";
import { useSocket } from "../hooks/use-socket";
import { Badge } from "../components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
import { Skeleton } from "../components/ui/skeleton";
import { Server, Users, Terminal, Activity } from "lucide-react";
import { cn } from "../lib/utils";
export function Dashboard() {
const { isConnected, stats } = useSocket();
@@ -51,15 +55,107 @@ export function Dashboard() {
</div>
</nav>
{/* Content Placeholder */}
<main className="pt-32 px-8 max-w-7xl mx-auto">
<div className="glass-card p-6 rounded-lg border border-border/50">
<h1 className="text-2xl font-bold text-primary mb-2">Dashboard Overview</h1>
<p className="text-muted-foreground">
Real-time connection status: <span className={isConnected ? "text-emerald-500 font-medium" : "text-red-500 font-medium"}>
{isConnected ? "Connected" : "Disconnected"}
</span>
{/* Dashboard Content */}
<main className="pt-32 px-8 max-w-7xl mx-auto space-y-8">
{/* Stats Grid */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4 animate-in fade-in slide-up">
<Card className="glass-card border-none bg-card/40 hover-glow">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Servers</CardTitle>
<Server className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{stats ? (
<>
<div className="text-2xl font-bold">{stats.guilds.count.toLocaleString()}</div>
<p className="text-xs text-muted-foreground mt-1">
{stats.guilds.changeFromLastMonth
? `${stats.guilds.changeFromLastMonth > 0 ? '+' : ''}${stats.guilds.changeFromLastMonth} from last month`
: "Active Guilds"
}
</p>
</>
) : (
<div className="space-y-2">
<Skeleton className="h-8 w-[60px]" />
<Skeleton className="h-3 w-[100px]" />
</div>
)}
</CardContent>
</Card>
<Card className="glass-card border-none bg-card/40 hover-glow delay-100">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Users</CardTitle>
<Users className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{stats ? (
<>
<div className="text-2xl font-bold">{stats.users.total.toLocaleString()}</div>
<p className="text-xs text-muted-foreground mt-1">
{stats.users.active.toLocaleString()} active now
</p>
</>
) : (
<div className="space-y-2">
<Skeleton className="h-8 w-[60px]" />
<Skeleton className="h-3 w-[100px]" />
</div>
)}
</CardContent>
</Card>
<Card className="glass-card border-none bg-card/40 hover-glow delay-200">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Commands</CardTitle>
<Terminal className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{stats ? (
<>
<div className="text-2xl font-bold">{stats.commands.total.toLocaleString()}</div>
<p className="text-xs text-muted-foreground mt-1">
{stats.commands.active} active · {stats.commands.disabled} disabled
</p>
</>
) : (
<div className="space-y-2">
<Skeleton className="h-8 w-[60px]" />
<Skeleton className="h-3 w-[100px]" />
</div>
)}
</CardContent>
</Card>
<Card className="glass-card border-none bg-card/40 hover-glow delay-300">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">System Ping</CardTitle>
<Activity className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{stats ? (
<>
<div className={cn(
"text-2xl font-bold transition-colors duration-300",
stats.ping.avg < 100 ? "text-emerald-500" :
stats.ping.avg < 200 ? "text-yellow-500" : "text-red-500"
)}>
{Math.round(stats.ping.avg)}ms
</div>
<p className="text-xs text-muted-foreground mt-1">
Average latency
</p>
</>
) : (
<div className="space-y-2">
<Skeleton className="h-8 w-[60px]" />
<Skeleton className="h-3 w-[100px]" />
</div>
)}
</CardContent>
</Card>
</div>
</main>
</div>

View File

@@ -388,6 +388,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
bot: { name: 'Aurora', avatarUrl: null },
guilds: 0,
commandsRegistered: 0,
commandsKnown: 0,
cachedUsers: 0,
ping: 0,
uptime: 0,
@@ -406,7 +407,11 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
bot: clientStats.bot,
guilds: { count: clientStats.guilds },
users: { active: activeUsers, total: totalUsers },
commands: { total: clientStats.commandsRegistered },
commands: {
total: clientStats.commandsKnown,
active: clientStats.commandsRegistered,
disabled: clientStats.commandsKnown - clientStats.commandsRegistered
},
ping: { avg: clientStats.ping },
economy: {
totalWealth: economyStats.totalWealth.toString(),