From 21cd547c2764df97cc56e3fe26e6e170500d1821 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 14:11:46 +0000 Subject: [PATCH] Add loading state to Resolve button - Introduce per-button loading state in PipelineHealthAlerts - Disable button and show spinner with "Resolving..." while resolving - Re-enable after operation completes - Keeps user feedback inline with alert resolution flow --- src/components/admin/PipelineHealthAlerts.tsx | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/components/admin/PipelineHealthAlerts.tsx b/src/components/admin/PipelineHealthAlerts.tsx index d01e24ef..cbd3ad98 100644 --- a/src/components/admin/PipelineHealthAlerts.tsx +++ b/src/components/admin/PipelineHealthAlerts.tsx @@ -5,11 +5,12 @@ * Shows top 10 active alerts with severity-based styling and resolution actions. */ +import { useState } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { useSystemAlerts } from '@/hooks/useSystemHealth'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; -import { AlertTriangle, CheckCircle, XCircle, AlertCircle } from 'lucide-react'; +import { AlertTriangle, CheckCircle, XCircle, AlertCircle, Loader2 } from 'lucide-react'; import { format } from 'date-fns'; import { supabase } from '@/lib/supabaseClient'; import { toast } from 'sonner'; @@ -41,6 +42,7 @@ const ALERT_TYPE_LABELS: Record = { export function PipelineHealthAlerts() { const queryClient = useQueryClient(); + const [resolvingAlertId, setResolvingAlertId] = useState(null); const { data: criticalAlerts } = useSystemAlerts('critical'); const { data: highAlerts } = useSystemAlerts('high'); const { data: mediumAlerts } = useSystemAlerts('medium'); @@ -53,22 +55,27 @@ export function PipelineHealthAlerts() { const resolveAlert = async (alertId: string) => { console.log('🔴 Resolve button clicked in PipelineHealthAlerts', { alertId }); + setResolvingAlertId(alertId); - const { error } = await supabase - .from('system_alerts') - .update({ resolved_at: new Date().toISOString() }) - .eq('id', alertId); + try { + const { error } = await supabase + .from('system_alerts') + .update({ resolved_at: new Date().toISOString() }) + .eq('id', alertId); - if (error) { - console.error('❌ Error resolving alert:', error); - toast.error('Failed to resolve alert'); - } else { - console.log('✅ Alert resolved successfully'); - toast.success('Alert resolved'); - - // Invalidate queries to refresh the UI - queryClient.invalidateQueries({ queryKey: queryKeys.monitoring.systemAlerts() }); - queryClient.invalidateQueries({ queryKey: queryKeys.monitoring.systemHealth() }); + if (error) { + console.error('❌ Error resolving alert:', error); + toast.error('Failed to resolve alert'); + } else { + console.log('✅ Alert resolved successfully'); + toast.success('Alert resolved'); + + // Invalidate queries to refresh the UI + queryClient.invalidateQueries({ queryKey: queryKeys.monitoring.systemAlerts() }); + queryClient.invalidateQueries({ queryKey: queryKeys.monitoring.systemHealth() }); + } + } finally { + setResolvingAlertId(null); } }; @@ -124,8 +131,16 @@ export function PipelineHealthAlerts() { variant="outline" size="sm" onClick={() => resolveAlert(alert.id)} + disabled={resolvingAlertId === alert.id} > - Resolve + {resolvingAlertId === alert.id ? ( + <> + + Resolving... + + ) : ( + 'Resolve' + )} );