Files
thrilltrack-explorer/src/components/admin/database-stats/HealthIssueCard.tsx
gpt-engineer-app[bot] 947964482f 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.
2025-11-11 17:11:11 +00:00

111 lines
3.7 KiB
TypeScript

import { AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import type { HealthIssue } from '@/types/database-analytics';
import { AlertCircle, AlertTriangle, Info, Lightbulb } from 'lucide-react';
interface HealthIssueCardProps {
issue: HealthIssue;
}
export function HealthIssueCard({ issue }: HealthIssueCardProps) {
const getSeverityIcon = () => {
switch (issue.severity) {
case 'critical':
return <AlertCircle className="h-4 w-4 text-red-600" />;
case 'warning':
return <AlertTriangle className="h-4 w-4 text-yellow-600" />;
case 'info':
return <Info className="h-4 w-4 text-blue-600" />;
}
};
const getSeverityColor = () => {
switch (issue.severity) {
case 'critical':
return 'border-red-600 bg-red-50 dark:bg-red-950/20';
case 'warning':
return 'border-yellow-600 bg-yellow-50 dark:bg-yellow-950/20';
case 'info':
return 'border-blue-600 bg-blue-50 dark:bg-blue-950/20';
}
};
const getSeverityBadgeVariant = () => {
switch (issue.severity) {
case 'critical':
return 'destructive';
case 'warning':
return 'default';
case 'info':
return 'secondary';
}
};
return (
<AccordionItem
value={`issue-${issue.category}-${issue.count}`}
className={`border rounded-lg ${getSeverityColor()}`}
>
<AccordionTrigger className="px-4 hover:no-underline">
<div className="flex items-center justify-between w-full pr-4">
<div className="flex items-center gap-3">
{getSeverityIcon()}
<div className="text-left">
<div className="font-semibold">{issue.description}</div>
<div className="text-sm text-muted-foreground capitalize">
{issue.category.replace(/_/g, ' ')}
</div>
</div>
</div>
<Badge variant={getSeverityBadgeVariant()}>
{issue.count} {issue.count === 1 ? 'entity' : 'entities'}
</Badge>
</div>
</AccordionTrigger>
<AccordionContent className="px-4 pb-4 space-y-4">
{/* Suggested Action */}
<div className="flex items-start gap-2 p-3 bg-background rounded border">
<Lightbulb className="h-4 w-4 text-yellow-600 mt-0.5 flex-shrink-0" />
<div className="space-y-1">
<div className="text-sm font-medium">Suggested Action</div>
<div className="text-sm text-muted-foreground">{issue.suggested_action}</div>
</div>
</div>
{/* Entity IDs (first 10) */}
{issue.entity_ids && issue.entity_ids.length > 0 && (
<div className="space-y-2">
<div className="text-sm font-medium">
Affected Entities ({issue.entity_ids.length})
</div>
<div className="flex flex-wrap gap-2">
{issue.entity_ids.slice(0, 10).map((id) => (
<Badge key={id} variant="outline" className="font-mono text-xs">
{id.substring(0, 8)}...
</Badge>
))}
{issue.entity_ids.length > 10 && (
<Badge variant="secondary" className="text-xs">
+{issue.entity_ids.length - 10} more
</Badge>
)}
</div>
</div>
)}
{/* Action Buttons */}
<div className="flex gap-2">
<Button size="sm" variant="default">
View Entities
</Button>
<Button size="sm" variant="outline">
Export List
</Button>
</div>
</AccordionContent>
</AccordionItem>
);
}