mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 11:51:14 -05:00
Implement Phase 3 fixes
The AI has implemented the Phase 3 plan, which includes adding approval failure monitoring to the existing error monitoring page, extending the ErrorAnalytics component with approval metrics, adding performance indexes, and creating the ApprovalFailureModal component.
This commit is contained in:
202
src/components/admin/ApprovalFailureModal.tsx
Normal file
202
src/components/admin/ApprovalFailureModal.tsx
Normal file
@@ -0,0 +1,202 @@
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { format } from 'date-fns';
|
||||
import { XCircle, Clock, User, FileText, AlertTriangle } from 'lucide-react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
interface ApprovalFailure {
|
||||
id: string;
|
||||
submission_id: string;
|
||||
moderator_id: string;
|
||||
submitter_id: string;
|
||||
items_count: number;
|
||||
duration_ms: number | null;
|
||||
error_message: string | null;
|
||||
request_id: string | null;
|
||||
rollback_triggered: boolean | null;
|
||||
created_at: string;
|
||||
success: boolean;
|
||||
moderator?: {
|
||||
username: string;
|
||||
avatar_url: string | null;
|
||||
};
|
||||
submission?: {
|
||||
submission_type: string;
|
||||
user_id: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface ApprovalFailureModalProps {
|
||||
failure: ApprovalFailure | null;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function ApprovalFailureModal({ failure, onClose }: ApprovalFailureModalProps) {
|
||||
if (!failure) return null;
|
||||
|
||||
return (
|
||||
<Dialog open={!!failure} onOpenChange={onClose}>
|
||||
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<XCircle className="w-5 h-5 text-destructive" />
|
||||
Approval Failure Details
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<Tabs defaultValue="overview" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="error">Error Details</TabsTrigger>
|
||||
<TabsTrigger value="metadata">Metadata</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="overview" className="space-y-4">
|
||||
<Card>
|
||||
<CardContent className="pt-6 space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Timestamp</div>
|
||||
<div className="font-medium">
|
||||
{format(new Date(failure.created_at), 'PPpp')}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Duration</div>
|
||||
<div className="font-medium flex items-center gap-2">
|
||||
<Clock className="w-4 h-4" />
|
||||
{failure.duration_ms != null ? `${failure.duration_ms}ms` : 'N/A'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Submission Type</div>
|
||||
<Badge variant="outline">
|
||||
{failure.submission?.submission_type || 'Unknown'}
|
||||
</Badge>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Items Count</div>
|
||||
<div className="font-medium">{failure.items_count}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Moderator</div>
|
||||
<div className="font-medium flex items-center gap-2">
|
||||
<User className="w-4 h-4" />
|
||||
{failure.moderator?.username || 'Unknown'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Submission ID</div>
|
||||
<Link
|
||||
to={`/admin/moderation?submission=${failure.submission_id}`}
|
||||
className="font-mono text-sm text-primary hover:underline flex items-center gap-2"
|
||||
>
|
||||
<FileText className="w-4 h-4" />
|
||||
{failure.submission_id}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{failure.rollback_triggered && (
|
||||
<div className="flex items-center gap-2 p-3 bg-warning/10 text-warning rounded-md">
|
||||
<AlertTriangle className="w-4 h-4" />
|
||||
<span className="text-sm font-medium">
|
||||
Rollback was triggered for this approval
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="error" className="space-y-4">
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-2">Error Message</div>
|
||||
<div className="p-4 bg-destructive/10 text-destructive rounded-md font-mono text-sm">
|
||||
{failure.error_message || 'No error message available'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{failure.request_id && (
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-2">Request ID</div>
|
||||
<div className="p-3 bg-muted rounded-md font-mono text-sm">
|
||||
{failure.request_id}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 p-4 bg-muted rounded-md">
|
||||
<div className="text-sm font-medium mb-2">Troubleshooting Tips</div>
|
||||
<ul className="text-sm text-muted-foreground space-y-1 list-disc list-inside">
|
||||
<li>Check if the submission still exists in the database</li>
|
||||
<li>Verify that all foreign key references are valid</li>
|
||||
<li>Review the edge function logs for detailed stack traces</li>
|
||||
<li>Check for concurrent modification conflicts</li>
|
||||
<li>Verify network connectivity and database availability</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="metadata" className="space-y-4">
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Failure ID</div>
|
||||
<div className="font-mono text-sm">{failure.id}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Success Status</div>
|
||||
<Badge variant="destructive">
|
||||
{failure.success ? 'Success' : 'Failed'}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Moderator ID</div>
|
||||
<div className="font-mono text-sm">{failure.moderator_id}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Submitter ID</div>
|
||||
<div className="font-mono text-sm">{failure.submitter_id}</div>
|
||||
</div>
|
||||
|
||||
{failure.request_id && (
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Request ID</div>
|
||||
<div className="font-mono text-sm break-all">{failure.request_id}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">Rollback Triggered</div>
|
||||
<Badge variant={failure.rollback_triggered ? 'destructive' : 'secondary'}>
|
||||
{failure.rollback_triggered ? 'Yes' : 'No'}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user