""" Write replacement WatchdogAlerts.tsx that matches the new WatchdogAlert interface. Run on the server: python3 /tmp/watchdog_alerts_page.py """ content = '''import { useState } from "react"; import { Link } from "react-router-dom"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { ShieldAlert, RefreshCw, CheckCircle2, Clock, ChevronDown, ChevronRight, } from "lucide-react"; import { watchdogAlertsApi, WatchdogAlert } from "../api/client"; import { Card, CardHeader, CardTitle, CardContent } from "../components/Card"; import { Button } from "../components/Button"; import { NativeSelect } from "../components/Select"; import { useToast } from "../hooks/useToast"; import { cn } from "../lib/utils"; // --------------------------------------------------------------------------- // Status derivation // --------------------------------------------------------------------------- type WatchdogStatus = "active" | "acknowledged" | "resolved"; function watchdogStatus(alert: WatchdogAlert): WatchdogStatus { if (alert.resolved_at) return "resolved"; if (alert.acknowledged_at) return "acknowledged"; return "active"; } // --------------------------------------------------------------------------- // Status badge // --------------------------------------------------------------------------- function WatchdogStatusBadge({ status }: { status: WatchdogStatus }) { const classes: Record = { active: "bg-red-500/15 text-red-600 dark:text-red-400", acknowledged: "bg-amber-500/15 text-amber-600 dark:text-amber-400", resolved: "bg-green-500/15 text-green-600 dark:text-green-400", }; const label: Record = { active: "Active", acknowledged: "Acknowledged", resolved: "Resolved", }; return ( {label[status]} ); } // --------------------------------------------------------------------------- // Filter type // --------------------------------------------------------------------------- type StatusFilter = "" | "active" | "acknowledged" | "resolved"; // --------------------------------------------------------------------------- // WatchdogAlerts page // --------------------------------------------------------------------------- export function WatchdogAlerts() { const { toast } = useToast(); const queryClient = useQueryClient(); const [statusFilter, setStatusFilter] = useState("active"); const [expandedLogId, setExpandedLogId] = useState(null); const { data: allAlerts = [], isLoading, isError, refetch, } = useQuery({ queryKey: ["watchdog-alerts-page"], queryFn: () => watchdogAlertsApi.list().then((r) => r.data), refetchInterval: 30000, }); // Client-side filter by derived status const alerts = allAlerts.filter( (a) => !statusFilter || watchdogStatus(a) === statusFilter ); const acknowledgeMutation = useMutation({ mutationFn: (id: string) => watchdogAlertsApi.acknowledge(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["watchdog-alerts-page"] }); toast({ type: "success", title: "Alert acknowledged" }); }, onError: (err: Error) => { toast({ type: "error", title: "Could not acknowledge alert", message: err.message, }); }, }); const resolveMutation = useMutation({ mutationFn: (id: string) => watchdogAlertsApi.resolve(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["watchdog-alerts-page"] }); toast({ type: "success", title: "Alert resolved" }); }, onError: (err: Error) => { toast({ type: "error", title: "Could not resolve alert", message: err.message, }); }, }); const deleteMutation = useMutation({ mutationFn: (id: string) => watchdogAlertsApi.delete(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["watchdog-alerts-page"] }); toast({ type: "success", title: "Alert deleted" }); }, onError: (err: Error) => { toast({ type: "error", title: "Could not delete alert", message: err.message }); }, }); const isMutating = acknowledgeMutation.isPending || resolveMutation.isPending || deleteMutation.isPending; const activeCount = allAlerts.filter((a) => watchdogStatus(a) === "active").length; const acknowledgedCount = allAlerts.filter( (a) => watchdogStatus(a) === "acknowledged" ).length; return (

Watchdog Alerts

Agent crash and restart exhaustion events

{/* Summary chips */}
{activeCount}
Active
{acknowledgedCount}
Acknowledged
{isError && (
Failed to load watchdog alerts. Check your connection and try refreshing.
)}
Alert Stream setStatusFilter(e.target.value as StatusFilter) } className="w-auto min-w-[11rem]" aria-label="Filter by status" >
{isLoading ? (

Loading watchdog alerts...

) : alerts.length === 0 ? (

No watchdog alerts

No events match the current filter.

) : (
{alerts.map((alert: WatchdogAlert) => { const status = watchdogStatus(alert); const logExpanded = expandedLogId === alert.id; return (
{alert.restart_attempts} restart attempt {alert.restart_attempts !== 1 ? "s" : ""}
{alert.agent_id.slice(0, 8)}… {" \xb7 "} Triggered:{" "} {new Date(alert.triggered_at).toLocaleString()} {alert.acknowledged_at && ( <> {" \xb7 "}Ack:{" "} {new Date(alert.acknowledged_at).toLocaleString()} {alert.acknowledged_by && ` by ${alert.acknowledged_by}`} )} {alert.resolved_at && ( <> {" \xb7 "}Resolved:{" "} {new Date(alert.resolved_at).toLocaleString()} )}
{alert.last_error && (

Error:{" "} {alert.last_error}

)}
{status === "active" && ( )} {status !== "resolved" && ( )}
{alert.log_tail && (
{logExpanded && (
                            {alert.log_tail}
                          
)}
)}
); })}
)}
); } ''' path = "/home/guru/gururmm/dashboard/src/pages/WatchdogAlerts.tsx" with open(path, "w", encoding="utf-8") as f: f.write(content) print(f"Written WatchdogAlerts.tsx: {len(content.splitlines())} lines")