import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { supabase } from '@/lib/supabaseClient'; import { AdminLayout } from '@/components/layout/AdminLayout'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Badge } from '@/components/ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { AlertCircle, XCircle } from 'lucide-react'; import { RefreshButton } from '@/components/ui/refresh-button'; import { ErrorDetailsModal } from '@/components/admin/ErrorDetailsModal'; import { ApprovalFailureModal } from '@/components/admin/ApprovalFailureModal'; import { ErrorAnalytics } from '@/components/admin/ErrorAnalytics'; import { PipelineHealthAlerts } from '@/components/admin/PipelineHealthAlerts'; import { format } from 'date-fns'; // Helper to calculate date threshold for filtering const getDateThreshold = (range: '1h' | '24h' | '7d' | '30d'): string => { const now = new Date(); const msMap = { '1h': 60 * 60 * 1000, // 1 hour in milliseconds '24h': 24 * 60 * 60 * 1000, // 1 day '7d': 7 * 24 * 60 * 60 * 1000, // 7 days '30d': 30 * 24 * 60 * 60 * 1000, // 30 days }; const threshold = new Date(now.getTime() - msMap[range]); return threshold.toISOString(); }; interface EnrichedApprovalFailure { 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 | null; success: boolean; moderator?: { user_id: string; username: string | null; avatar_url: string | null; }; submission?: { id: string; submission_type: string; user_id: string; }; } export default function ErrorMonitoring() { const [selectedError, setSelectedError] = useState(null); const [selectedFailure, setSelectedFailure] = useState(null); const [searchTerm, setSearchTerm] = useState(''); const [errorTypeFilter, setErrorTypeFilter] = useState('all'); const [dateRange, setDateRange] = useState<'1h' | '24h' | '7d' | '30d'>('24h'); // Fetch recent errors const { data: errors, isLoading, refetch, isFetching } = useQuery({ queryKey: ['admin-errors', dateRange, errorTypeFilter, searchTerm], queryFn: async () => { let query = supabase .from('request_metadata') .select(` *, request_breadcrumbs( timestamp, category, message, level, sequence_order ) `) .not('error_type', 'is', null) .gte('created_at', getDateThreshold(dateRange)) .order('created_at', { ascending: false }) .limit(100); if (errorTypeFilter !== 'all') { query = query.eq('error_type', errorTypeFilter); } if (searchTerm) { query = query.or(`request_id.ilike.%${searchTerm}%,error_message.ilike.%${searchTerm}%,endpoint.ilike.%${searchTerm}%`); } const { data, error } = await query; if (error) throw error; return data; }, refetchInterval: 30000, // Auto-refresh every 30 seconds }); // Fetch error summary const { data: errorSummary } = useQuery({ queryKey: ['error-summary'], queryFn: async () => { const { data, error } = await supabase .from('error_summary') .select('*'); if (error) throw error; return data; }, }); // Fetch approval metrics (last 24h) const { data: approvalMetrics } = useQuery({ queryKey: ['approval-metrics'], queryFn: async () => { const { data, error } = await supabase .from('approval_transaction_metrics') .select('id, success, duration_ms, created_at') .gte('created_at', getDateThreshold('24h')) .order('created_at', { ascending: false }) .limit(1000); if (error) throw error; return data; }, }); // Fetch approval failures const { data: approvalFailures, refetch: refetchFailures, isFetching: isFetchingFailures } = useQuery({ queryKey: ['approval-failures', dateRange, searchTerm], queryFn: async () => { let query = supabase .from('approval_transaction_metrics') .select('*') .eq('success', false) .gte('created_at', getDateThreshold(dateRange)) .order('created_at', { ascending: false }) .limit(50); if (searchTerm) { query = query.or(`submission_id.ilike.%${searchTerm}%,error_message.ilike.%${searchTerm}%`); } const { data, error } = await query; if (error) throw error; // Fetch moderator and submission data separately if (data && data.length > 0) { const moderatorIds = [...new Set(data.map(f => f.moderator_id))]; const submissionIds = [...new Set(data.map(f => f.submission_id))]; const [moderatorsData, submissionsData] = await Promise.all([ supabase.from('profiles').select('user_id, username, avatar_url').in('user_id', moderatorIds), supabase.from('content_submissions').select('id, submission_type, user_id').in('id', submissionIds) ]); // Enrich data with moderator and submission info return data.map(failure => ({ ...failure, moderator: moderatorsData.data?.find(m => m.user_id === failure.moderator_id), submission: submissionsData.data?.find(s => s.id === failure.submission_id) })) as EnrichedApprovalFailure[]; } return (data || []) as EnrichedApprovalFailure[]; }, refetchInterval: 30000, }); return (

Error Monitoring

Track and analyze application errors

{ await refetch(); }} isLoading={isFetching} variant="outline" size="sm" />
{/* Pipeline Health Alerts */} {/* Analytics Section */} {/* Tabs for Errors and Approval Failures */} Application Errors Approval Failures Error Log Recent errors across the application
setSearchTerm(e.target.value)} className="w-full" />
{isLoading ? (
Loading errors...
) : errors && errors.length > 0 ? (
{errors.map((error) => (
setSelectedError(error)} className="p-4 border rounded-lg hover:bg-accent cursor-pointer transition-colors" >
{error.error_type} {error.endpoint}

{error.error_message}

ID: {error.request_id.slice(0, 8)} {format(new Date(error.created_at), 'PPp')} {error.duration_ms != null && {error.duration_ms}ms}
))}
) : (
No errors found for the selected filters
)}
Approval Failures Failed approval transactions requiring investigation
setSearchTerm(e.target.value)} className="w-full" />
{isFetchingFailures ? (
Loading approval failures...
) : approvalFailures && approvalFailures.length > 0 ? (
{approvalFailures.map((failure) => (
setSelectedFailure(failure)} className="p-4 border rounded-lg hover:bg-accent cursor-pointer transition-colors" >
Approval Failed {failure.submission?.submission_type || 'Unknown'} {failure.rollback_triggered && ( Rollback )}

{failure.error_message || 'No error message available'}

Moderator: {failure.moderator?.username || 'Unknown'} {failure.created_at && format(new Date(failure.created_at), 'PPp')} {failure.duration_ms != null && {failure.duration_ms}ms} {failure.items_count} items
))}
) : (
No approval failures found for the selected filters
)}
{/* Error Details Modal */} {selectedError && ( setSelectedError(null)} /> )} {/* Approval Failure Modal */} {selectedFailure && ( setSelectedFailure(null)} /> )}
); }