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,57 @@
import { Suspense } from "react";
import { Box, SimpleGrid, Stack } from "@mantine/core";
import { CardSkeleton, StatTileSkeleton } from "@/components/skeletons";
import QuietBoundary from "./quiet-boundary";
import NowStrip from "./now-strip";
import TournamentCard from "./tournament-card";
import UsageCard from "./usage-card";
import ErrorsCard from "./errors-card";
import ActivityFeed from "./activity-feed";
import ToolsList from "./tools-list";
const NowStripSkeleton = () => (
<SimpleGrid cols={3} spacing="xs">
<StatTileSkeleton />
<StatTileSkeleton />
<StatTileSkeleton />
</SimpleGrid>
);
export const AdminDashboard = () => (
<Stack gap="md" pb="md">
<Stack gap="md" px="md" pt="md">
<QuietBoundary>
<Suspense fallback={<NowStripSkeleton />}>
<NowStrip />
</Suspense>
</QuietBoundary>
<SimpleGrid cols={{ base: 1, md: 2 }} spacing="md">
<QuietBoundary>
<Suspense fallback={<CardSkeleton />}>
<TournamentCard />
</Suspense>
</QuietBoundary>
<QuietBoundary>
<Suspense fallback={<CardSkeleton />}>
<ErrorsCard />
</Suspense>
</QuietBoundary>
</SimpleGrid>
<SimpleGrid cols={{ base: 1, md: 2 }} spacing="md">
<QuietBoundary>
<Suspense fallback={<CardSkeleton />}>
<UsageCard />
</Suspense>
</QuietBoundary>
<QuietBoundary>
<ActivityFeed />
</QuietBoundary>
</SimpleGrid>
</Stack>
<Box>
<ToolsList />
</Box>
</Stack>
);
export default AdminDashboard;