Enhance admin stats dashboard

Add data quality metrics, growth trends visualization, entity comparison views, and automated health checks to the AdminDatabaseStats dashboard, including new TS types, hooks, UI components, and integrated tabbed layout.
This commit is contained in:
gpt-engineer-app[bot]
2025-11-11 17:11:11 +00:00
parent f036776dce
commit 947964482f
14 changed files with 1579 additions and 88 deletions

View File

@@ -0,0 +1,107 @@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Progress } from '@/components/ui/progress';
import { Link } from 'react-router-dom';
import { ExternalLink } from 'lucide-react';
interface Column {
key: string;
label: string;
numeric?: boolean;
linkBase?: string;
}
interface ComparisonTableProps {
title: string;
data: any[];
columns: Column[];
slugKey: string;
parkSlugKey?: string;
}
export function ComparisonTable({ title, data, columns, slugKey, parkSlugKey }: ComparisonTableProps) {
if (!data || data.length === 0) {
return (
<div className="text-center py-8 text-muted-foreground">
No data available
</div>
);
}
// Find the max value for each numeric column (for progress bars)
const maxValues: Record<string, number> = {};
columns.forEach(col => {
if (col.numeric) {
maxValues[col.key] = Math.max(...data.map(row => row[col.key] || 0));
}
});
return (
<div className="space-y-2">
<h3 className="text-lg font-semibold">{title}</h3>
<div className="border rounded-lg">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-12">Rank</TableHead>
{columns.map(col => (
<TableHead key={col.key} className={col.numeric ? 'text-right' : ''}>
{col.label}
</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{data.map((row, index) => {
const slug = row[slugKey];
const parkSlug = parkSlugKey ? row[parkSlugKey] : null;
return (
<TableRow key={index}>
<TableCell className="font-medium text-muted-foreground">
#{index + 1}
</TableCell>
{columns.map(col => {
const value = row[col.key];
const isFirst = col === columns[0];
if (isFirst && col.linkBase && slug) {
const linkPath = parkSlug
? `${col.linkBase}/${parkSlug}/rides/${slug}`
: `${col.linkBase}/${slug}`;
return (
<TableCell key={col.key}>
<Link
to={linkPath}
className="flex items-center gap-2 hover:text-primary transition-colors"
>
{value}
<ExternalLink className="h-3 w-3" />
</Link>
</TableCell>
);
}
if (col.numeric) {
const percentage = (value / maxValues[col.key]) * 100;
return (
<TableCell key={col.key} className="text-right">
<div className="flex items-center justify-end gap-2">
<span className="font-semibold min-w-12">{value}</span>
<Progress value={percentage} className="h-2 w-24" />
</div>
</TableCell>
);
}
return <TableCell key={col.key}>{value}</TableCell>;
})}
</TableRow>
);
})}
</TableBody>
</Table>
</div>
</div>
);
}