- ESLint warnings 43→42 (-1) - 剩余 42 warnings 全部为 react-refresh/only-export-components 架构性约束 - tsc -b=0, npm build✓ (23.04s), 17/17 集成测试通过
114 lines
4.0 KiB
TypeScript
114 lines
4.0 KiB
TypeScript
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>
|
||
);
|
||
}
|