feat(admin): dashboard home, telemetry section, enrollment ops screen

- mission-control dashboard: now strip, tournament quick actions, usage
  sparklines, error feed, live activity, tools list
- /admin/telemetry with functions/events/errors/players/usage child routes,
  hand-rolled svg chart primitives, decomposed activities table
- error browser with grouping and mark-resolved
- consolidated per-tournament enrollment screen; hub simplified with
  run tournament promoted
- /admin/activities redirects to /admin/telemetry/functions
This commit is contained in:
2026-08-25 21:54:21 -07:00
parent 06fe1f4ed7
commit a52872bea8
46 changed files with 2824 additions and 645 deletions
@@ -0,0 +1,53 @@
import { ReactNode } from "react";
import { Box, Card, Group, Stack, Text, UnstyledButton } from "@mantine/core";
import Sparkline from "./sparkline";
interface StatTileProps {
label: ReactNode;
value: ReactNode;
delta?: number;
spark?: number[];
caption?: ReactNode;
onClick?: () => void;
}
export const StatTile = ({ label, value, delta, spark, caption, onClick }: StatTileProps) => {
const content = (
<Stack gap={4}>
<Text size="xs" c="dimmed">
{label}
</Text>
<Group gap="xs" align="baseline" wrap="nowrap">
<Text fz={24} fw={600} lh={1.2}>
{value}
</Text>
{delta !== undefined && delta !== 0 && (
<Text size="xs" c={delta > 0 ? "green" : "red"}>
{delta > 0 ? "+" : ""}
{delta.toLocaleString()}
</Text>
)}
</Group>
{caption && <Box>{caption}</Box>}
{spark && spark.length > 0 && <Sparkline data={spark} height={28} />}
</Stack>
);
if (onClick) {
return (
<UnstyledButton onClick={onClick} w="100%">
<Card withBorder radius="md" p="md">
{content}
</Card>
</UnstyledButton>
);
}
return (
<Card withBorder radius="md" p="md">
{content}
</Card>
);
};
export default StatTile;