import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Search, Loader2, ExternalLink } from 'lucide-react'; import { format } from 'date-fns'; import { supabase } from '@/lib/supabaseClient'; interface SearchResult { type: 'error' | 'approval' | 'edge' | 'database'; id: string; timestamp: string; message: string; severity?: string; metadata?: Record; } interface UnifiedLogSearchProps { onNavigate: (tab: string, filters: Record) => void; } export function UnifiedLogSearch({ onNavigate }: UnifiedLogSearchProps) { const [searchQuery, setSearchQuery] = useState(''); const [searchTerm, setSearchTerm] = useState(''); const { data: results, isLoading } = useQuery({ queryKey: ['unified-log-search', searchTerm], queryFn: async () => { if (!searchTerm) return []; const results: SearchResult[] = []; // Search application errors const { data: errors } = await supabase .from('request_metadata') .select('request_id, created_at, error_type, error_message') .or(`request_id.ilike.%${searchTerm}%,error_message.ilike.%${searchTerm}%`) .order('created_at', { ascending: false }) .limit(10); if (errors) { results.push(...errors.map(e => ({ type: 'error' as const, id: e.request_id, timestamp: e.created_at, message: e.error_message || 'Unknown error', severity: e.error_type || undefined, }))); } // Search approval failures const { data: approvals } = await supabase .from('approval_transaction_metrics') .select('id, created_at, error_message, request_id') .eq('success', false) .or(`request_id.ilike.%${searchTerm}%,error_message.ilike.%${searchTerm}%`) .order('created_at', { ascending: false }) .limit(10); if (approvals) { results.push(...approvals .filter(a => a.created_at) .map(a => ({ type: 'approval' as const, id: a.id, timestamp: a.created_at!, message: a.error_message || 'Approval failed', metadata: { request_id: a.request_id }, }))); } // Sort by timestamp results.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); return results; }, enabled: !!searchTerm, }); const handleSearch = () => { setSearchTerm(searchQuery); }; const getTypeColor = (type: string): "default" | "destructive" | "outline" | "secondary" => { switch (type) { case 'error': return 'destructive'; case 'approval': return 'destructive'; case 'edge': return 'default'; case 'database': return 'secondary'; default: return 'outline'; } }; const getTypeLabel = (type: string) => { switch (type) { case 'error': return 'Application Error'; case 'approval': return 'Approval Failure'; case 'edge': return 'Edge Function'; case 'database': return 'Database Log'; default: return type; } }; const handleResultClick = (result: SearchResult) => { switch (result.type) { case 'error': onNavigate('errors', { requestId: result.id }); break; case 'approval': onNavigate('approvals', { failureId: result.id }); break; case 'edge': onNavigate('edge-functions', { search: result.message }); break; case 'database': onNavigate('database', { search: result.message }); break; } }; return ( Unified Log Search
setSearchQuery(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSearch()} className="pl-10" />
{searchTerm && (
{isLoading ? (
) : results && results.length > 0 ? ( <>
Found {results.length} results
{results.map((result) => ( handleResultClick(result)} >
{getTypeLabel(result.type)} {result.severity && ( {result.severity} )} {format(new Date(result.timestamp), 'PPp')}

{result.message}

{result.id.slice(0, 16)}...
))} ) : (

No results found for "{searchTerm}"

)}
)}
); }