mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 21:31:14 -05:00
Implement monitoring overview features
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
This commit is contained in:
77
src/hooks/admin/useRecentActivity.ts
Normal file
77
src/hooks/admin/useRecentActivity.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
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,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user