// Agent 告警主组件:告警事件 Tab + 告警规则 Tab + 规则编辑弹窗 // Logan.Li import { useState, useEffect, useCallback } from 'react'; import { toast } from 'sonner'; import { useConfirm } from '@/components/ui/confirm-dialog'; import { agentApi } from '@/api'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Switch } from '@/components/ui/switch'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { AlertTriangle, CheckCircle, Plus, Pencil, Trash2, Loader2, RefreshCw, Bell, Cpu, Clock, } from 'lucide-react'; import { METRIC_OPTIONS, getMetricLabel, asList, severityBadge, } from './agentAlertHelper'; import { AgentRuleDialog } from './AgentRuleDialog'; import type { JsonData } from '@/types/common'; import i18n from '@/i18n'; export function AgentAlerts() { const confirm = useConfirm(); const [activeTab, setActiveTab] = useState('events'); const [alerts, setAlerts] = useState([]); const [rules, setRules] = useState([]); const [loading, setLoading] = useState(true); const [resolvedView, setResolvedView] = useState(false); // 规则编辑弹窗 const [ruleOpen, setRuleOpen] = useState(false); const [editingRule, setEditingRule] = useState(null); const loadData = useCallback(async () => { setLoading(true); try { const [alertsRes, rulesRes] = await Promise.all([ agentApi.listAlerts({ resolved: String(resolvedView) }), agentApi.listRules(), ]); setAlerts(asList(alertsRes)); setRules(asList(rulesRes)); } catch (err) { console.error(err); toast.error(i18n.t('agent.alerts.loadFailed')); } finally { setLoading(false); } }, [resolvedView]); useEffect(() => { loadData(); }, [loadData]); // ============ 告警事件 ============ const handleResolve = async (id: number) => { const ok = await confirm({ title: i18n.t('agent.alerts.resolveAlert'), description: i18n.t('agent.alerts.resolveConfirm'), confirmText: i18n.t('kubernetes.deployment.resume') }); if (!ok) return; try { await agentApi.resolveAlert(id); toast.success(i18n.t('agent.alerts.resolved')); loadData(); } catch (err) { toast.error(err?.message || i18n.t('cloud.operationFailed')); } }; // ============ 规则 CRUD ============ const openCreateRule = () => { setEditingRule(null); setRuleOpen(true); }; const openEditRule = (rule: JsonData) => { setEditingRule(rule); setRuleOpen(true); }; const handleDeleteRule = async (id: number) => { const ok = await confirm({ title: i18n.t('monitor.deleteRule'), description: i18n.t('agent.alerts.deleteRule'), confirmText: i18n.t('kubernetes.storage.delete2'), variant: 'destructive' }); if (!ok) return; try { await agentApi.deleteRule(id); toast.success(i18n.t('agent.alerts.resolved')); loadData(); } catch (err) { toast.error(err?.message || i18n.t('kubernetes.msg.deleteFailed2')); } }; const handleToggleRule = async (rule: JsonData) => { try { await agentApi.updateRule(rule.id, { ...rule, enabled: !rule.enabled }); loadData(); } catch (err) { toast.error(err?.message || i18n.t('cloud.operationFailed')); } }; return (
{/* 页头 */}

{i18n.t('agent.alerts.title')}

{i18n.t('agent.alerts.thresholdTriggered')}

{i18n.t('kubernetes.eventsPage.alertEvents')} {i18n.t('monitor.alertRules')} {/* ========== 告警事件 ========== */}
{loading ? ( {i18n.t('monitor.logPanel.logResults.loading')} ) : alerts.length === 0 ? (

{resolvedView ? i18n.t('agent.alerts.noResolved') : i18n.t('agent.alerts.noActive')}

) : (
{alerts.map((alert) => (
{severityBadge(alert.severity)} {alert.rule_name || alert.name || alert.title || i18n.t('monitor.hostDashboard.alert')}

{alert.message || alert.description || i18n.t('agent.alerts.thresholdTriggered')}

{alert.hostname || '--'} {i18n.t('agent.agentAlerts.metric')} {getMetricLabel(alert.metric)} {alert.value != null && ( {i18n.t('agent.agentAlerts.currentValue')} {alert.value} )} {alert.created_at || alert.triggered_at ? new Date(alert.created_at || alert.triggered_at).toLocaleString() : '--'}
{!resolvedView && ( )}
))}
)}
{/* ========== 告警规则 ========== */}
{loading ? ( {i18n.t('monitor.logPanel.logResults.loading')} ) : rules.length === 0 ? (

{i18n.t('monitor.noRules')}

) : (
{rules.map((rule) => { const MetricIcon = METRIC_OPTIONS.find((m) => m.value === rule.metric)?.icon || Cpu; return (
{rule.name} {severityBadge(rule.severity)} {rule.enabled === false && ( {i18n.t('aiops.llmDisabled')} )}
{getMetricLabel(rule.metric)} {rule.metric !== 'offline' && ( {rule.operator} {rule.threshold}{rule.metric === 'port_down' ? '' : '%'} )} {rule.metric === 'port_down' && rule.port ? ( {i18n.t("common.port")} {rule.port} ) : null} {rule.duration ? {i18n.t("common.duration")} {rule.duration}s : null}
handleToggleRule(rule)} />
); })}
)}
{/* ========== 规则编辑弹窗 ========== */}
); } export default AgentAlerts;