import { useState, useEffect, useCallback, useMemo } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { RefreshCw, Bell, AlertTriangle, X } from 'lucide-react'; import { kubernetesApi } from '@/api'; import { EventTable } from './EventTable'; import { normalizeK8sEvent, formatEventRelative } from './k8s-event-utils'; import { PageShell } from '@/components/layout/PageShell'; import { ContentPanel } from '@/components/layout/ContentPanel'; import { StatStrip } from '@/components/ui/stat-strip'; import type { JsonData } from '@/types/common'; import i18n from '@/i18n'; interface RankItem { name: string; count: number } // 简洁排名列表,替代花哨柱状图 // Logan.Li function RankPanel({ title, items, selected, onSelect, emptyText, }: { title: string; items: RankItem[]; selected?: string; onSelect?: (name: string) => void; emptyText?: string; }) { const max = Math.max(...items.map((i) => i.count), 1); return (

{title}

{items.length === 0 ? (

{emptyText || i18n.t('aiops.assistantNoData')}

) : (
{items.map((item) => { const active = selected === item.name; return ( ); })}
)}
); } export default function EventsPage() { const { clusterCode } = useParams<{ clusterCode: string }>(); const navigate = useNavigate(); const [loading, setLoading] = useState(false); const [events, setEvents] = useState([]); const [clusters, setClusters] = useState([]); const [namespaces, setNamespaces] = useState([]); const [selectedNs, setSelectedNs] = useState('all'); const [filterType, setFilterType] = useState('all'); const [timeWindow, setTimeWindow] = useState('0'); const [activeCluster, setActiveCluster] = useState(clusterCode || ''); const [summary, setSummary] = useState(null); const [selectedReason, setSelectedReason] = useState(''); const [selectedKind, setSelectedKind] = useState(''); useEffect(() => { kubernetesApi.getClusters().then((res: JsonData) => { const list = res?.list || []; setClusters(list); if (!activeCluster && list.length > 0) { const code = list[0].code || String(list[0].id); setActiveCluster(code); navigate(`/kubernetes/${code}/events`, { replace: true }); } }).catch(() => {}); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { if (!activeCluster) return; kubernetesApi.getNamespaces(activeCluster).then((res: JsonData) => { setNamespaces(Array.isArray(res) ? res : (res?.list || res?.data || [])); }).catch(() => {}); }, [activeCluster]); const loadEvents = useCallback(async () => { if (!activeCluster) return; setLoading(true); try { const ns = selectedNs === 'all' ? undefined : selectedNs; const ft = filterType === 'all' ? undefined : filterType; const res: JsonData = await kubernetesApi.getEvents(activeCluster, ns, ft); setEvents(Array.isArray(res) ? res : (res?.list || [])); } catch { setEvents([]); } finally { setLoading(false); } }, [activeCluster, selectedNs, filterType]); const loadSummary = useCallback(async () => { if (!activeCluster) return; try { const ns = selectedNs === 'all' ? undefined : selectedNs; const hours = parseInt(timeWindow) || undefined; const res: JsonData = await kubernetesApi.getEventsSummary(activeCluster, ns, hours); setSummary(res || null); } catch { setSummary(null); } }, [activeCluster, selectedNs, timeWindow]); useEffect(() => { loadEvents(); }, [loadEvents]); useEffect(() => { loadSummary(); }, [loadSummary]); const displayEvents = useMemo(() => { let filtered = events.map((e) => normalizeK8sEvent(e)); const hours = parseInt(timeWindow, 10); if (hours > 0) { const since = Date.now() - hours * 3600 * 1000; filtered = filtered.filter((e) => !e.lastTime || new Date(e.lastTime).getTime() >= since); } if (selectedReason) filtered = filtered.filter((e) => e.reason === selectedReason); if (selectedKind) { filtered = filtered.filter((e) => e.objectKind === selectedKind || e.object.startsWith(`${selectedKind}/`), ); } return filtered; }, [events, selectedReason, selectedKind, timeWindow]); const warningCount = useMemo(() => events.filter((e) => e.type === 'Warning').length, [events]); const normalCount = useMemo(() => events.filter((e) => e.type === 'Normal').length, [events]); const reasonData = useMemo(() => (summary?.by_reason || []).map((r: JsonData) => ({ name: r.reason || 'Unknown', count: r.count })), [summary]); const nsData = useMemo(() => (summary?.by_namespace || []).map((n: JsonData) => ({ name: n.namespace || '', count: n.count })), [summary]); const kindData = useMemo(() => (summary?.by_kind || []).map((k: JsonData) => ({ name: k.kind || 'Unknown', count: k.count })), [summary]); const clusterName = clusters.find((c: JsonData) => (c.code || String(c.id)) === activeCluster)?.name; const filterToolbar = (selectedReason || selectedKind) ? (
{i18n.t('kubernetes.eventspagetsx.s841389c5')} {selectedReason && ( )} {selectedKind && ( )}
) : undefined; return ( } metrics={!loading ? ( ) : undefined} toolbar={filterToolbar} actions={( <> )} > {reasonData.length > 0 && (
{nsData.length > 0 && } {kindData.length > 0 && ( )}
)} {summary?.recent_warnings?.length > 0 && (

最新告警 ({summary.recent_warnings.length})

{summary.recent_warnings.map((w: JsonData, i: number) => (
{w.reason} {w.object} {w.namespace} {w.source && {w.source}} ×{w.count} {formatEventRelative(w.last_time)}

{w.message}

))}
)} 事件列表 ({displayEvents.length}) )} >
); }