mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 12:51:16 -05:00
Add comprehensive monitoring dashboard scaffolding: - Extend queryKeys with monitoring keys - Create hooks: useCombinedAlerts, useRecentActivity, useDatabaseHealth, useModerationHealth - Build UI components: SystemHealthStatus, CriticalAlertsPanel, MonitoringQuickStats, RecentActivityTimeline, MonitoringNavCards - Create MonitoringOverview page and integrate routing (MonitoringOverview route) - Wire AdminSidebar to include Monitoring navigation - Introduce supporting routing and admin layout hooks/utilities - Align with TanStack Query patterns and plan for auto-refresh and optimistic updates
78 lines
2.9 KiB
TypeScript
78 lines
2.9 KiB
TypeScript
import { useQuery } from '@tanstack/react-query';
|
|
import { supabase } from '@/integrations/supabase/client';
|
|
import { queryKeys } from '@/lib/queryKeys';
|
|
|
|
export type ActivityEvent =
|
|
| { id: string; created_at: string; type: 'error'; error_type: string | null; error_message: string | null; endpoint: string }
|
|
| { id: string; created_at: string; type: 'approval'; success: false; error_message: string | null; moderator_id: string }
|
|
| { id: string; created_at: string; type: 'alert'; alert_type: string; severity: string; message: string };
|
|
|
|
export function useRecentActivity(timeWindow = 3600000) { // 1 hour default
|
|
return useQuery({
|
|
queryKey: queryKeys.monitoring.recentActivity(timeWindow),
|
|
queryFn: async () => {
|
|
const threshold = new Date(Date.now() - timeWindow);
|
|
|
|
const [errors, approvals, alerts] = await Promise.all([
|
|
supabase
|
|
.from('request_metadata')
|
|
.select('id, created_at, error_type, error_message, endpoint')
|
|
.not('error_type', 'is', null)
|
|
.gte('created_at', threshold.toISOString())
|
|
.order('created_at', { ascending: false })
|
|
.limit(10),
|
|
supabase
|
|
.from('approval_transaction_metrics')
|
|
.select('id, created_at, success, error_message, moderator_id')
|
|
.eq('success', false)
|
|
.gte('created_at', threshold.toISOString())
|
|
.order('created_at', { ascending: false })
|
|
.limit(10),
|
|
supabase
|
|
.from('system_alerts')
|
|
.select('id, created_at, alert_type, severity, message')
|
|
.gte('created_at', threshold.toISOString())
|
|
.order('created_at', { ascending: false })
|
|
.limit(10),
|
|
]);
|
|
|
|
const combined: ActivityEvent[] = [
|
|
...(errors.data || [])
|
|
.filter(e => e.error_type && e.error_message)
|
|
.map(e => ({
|
|
id: e.id,
|
|
created_at: e.created_at,
|
|
type: 'error' as const,
|
|
error_type: e.error_type,
|
|
error_message: e.error_message,
|
|
endpoint: e.endpoint,
|
|
})),
|
|
...(approvals.data || [])
|
|
.filter(a => a.created_at && a.error_message)
|
|
.map(a => ({
|
|
id: a.id,
|
|
created_at: a.created_at || new Date().toISOString(),
|
|
type: 'approval' as const,
|
|
success: false as const,
|
|
error_message: a.error_message,
|
|
moderator_id: a.moderator_id,
|
|
})),
|
|
...(alerts.data || []).map(a => ({
|
|
id: a.id,
|
|
created_at: a.created_at,
|
|
type: 'alert' as const,
|
|
alert_type: a.alert_type,
|
|
severity: a.severity,
|
|
message: a.message,
|
|
})),
|
|
];
|
|
|
|
return combined
|
|
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
|
|
.slice(0, 30);
|
|
},
|
|
staleTime: 30000,
|
|
refetchInterval: 60000,
|
|
});
|
|
}
|