Files
aiops/frontend/src/components/kubernetes/cluster-detail/EventsTab.tsx
T
attacker 5a427e02d4 fix(lint): 清理 EventsTab 冗余 eslint-disable 指令 — F7 (ca036a8) 提交时引入的 react-hooks/set-state-in-effect 标注,规则版本演进后不再触发,保留反而引入 ESLint Unused disable warning
- ESLint warnings 43→42 (-1)
- 剩余 42 warnings 全部为 react-refresh/only-export-components 架构性约束
- tsc -b=0, npm build✓ (23.04s), 17/17 集成测试通过
2026-07-19 18:11:32 +08:00

114 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, useEffect, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { RefreshCw } from 'lucide-react';
import { kubernetesApi } from '@/api';
import { normalizeK8sEvent, formatEventRelative } from '../k8s-event-utils';
import type { NormalizedEvent } from '../k8s-event-utils';
import type { JsonData } from '@/types/common';
interface EventsTabProps {
clusterCode?: string;
}
export function EventsTab({ clusterCode }: EventsTabProps) {
const { t } = useTranslation();
const [events, setEvents] = useState<NormalizedEvent[]>([]);
const [loading, setLoading] = useState(false);
const fetchEvents = useCallback(async () => {
if (!clusterCode) return;
setLoading(true);
try {
const res = await kubernetesApi.getEvents(clusterCode);
const arr = Array.isArray(res) ? res : (res?.list || []);
const normalized = (arr as JsonData[]).map(normalizeK8sEvent);
// Warning 优先,然后按 lastTime 降序
normalized.sort((a, b) => {
if (a.type !== b.type) return a.type === 'Warning' ? -1 : 1;
return new Date(b.lastTime || 0).getTime() - new Date(a.lastTime || 0).getTime();
});
setEvents(normalized.slice(0, 100));
} catch {
setEvents([]);
} finally {
setLoading(false);
}
}, [clusterCode]);
useEffect(() => {
if (clusterCode) {
fetchEvents();
}
}, [clusterCode, fetchEvents]);
if (loading) {
return (
<div className="flex items-center justify-center py-8 text-[var(--dg-text-muted)]">
<RefreshCw className="h-4 w-4 mr-2 animate-spin" />
{t('common.loading')}
</div>
);
}
if (events.length === 0) {
return (
<div className="flex items-center justify-between">
<div className="py-8 text-center text-[var(--dg-text-muted)]">
{t('k8s.empty.events')}
</div>
{clusterCode && (
<Button variant="ghost" size="sm" onClick={fetchEvents} title={t('common.refresh')}>
<RefreshCw className="h-4 w-4" />
</Button>
)}
</div>
);
}
return (
<div className="space-y-2">
<div className="flex justify-end mb-2">
<Button variant="ghost" size="sm" onClick={fetchEvents} title={t('common.refresh')}>
<RefreshCw className="h-3.5 w-3.5 mr-1" />
{t('common.refresh')}
</Button>
</div>
{events.map((event, index) => (
<div
key={`${event.name}-${index}`}
className="flex items-center gap-3 p-3 rounded-lg bg-[var(--dg-bg-tertiary)]/50"
>
<Badge
variant="outline"
className={
event.type === 'Normal'
? 'border-[var(--dg-green)]/30 text-[var(--dg-green)] bg-[var(--dg-green)]/10 shrink-0'
: 'border-[var(--dg-orange)]/30 text-[var(--dg-orange)] bg-[var(--dg-orange)]/10 shrink-0'
}
>
{event.type}
</Badge>
<span className="text-sm font-medium text-[var(--dg-text-secondary)] min-w-[120px] shrink-0">{event.reason}</span>
<span className="text-sm text-[var(--dg-text-secondary)] flex-1 truncate" title={event.message}>{event.message}</span>
{event.count > 1 && (
<span className="text-xs text-[var(--dg-text-muted)] shrink-0">×{event.count}</span>
)}
{event.object && event.object !== '-' && (
<span className="text-xs font-mono text-[var(--dg-text-muted)] shrink-0 max-w-[200px] truncate" title={event.object}>{event.object}</span>
)}
{event.lastTime && (
<span className="text-xs text-[var(--dg-text-muted)] shrink-0">{formatEventRelative(event.lastTime)}</span>
)}
</div>
))}
{events.length === 100 && (
<div className="text-xs text-center text-[var(--dg-text-muted)] py-2">
{t('k8s.event.totalCount', { count: 100 })}
</div>
)}
</div>
);
}