import { createAxiosToken } from '@/hooks/use-chunk-request'; import { ReloadOutlined } from '@ant-design/icons'; import { AlertBlockInfo, AutoTooltip, ScrollerModal, StatusTag } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Table } from 'antd'; import type { ColumnsType } from 'antd/lib/table'; import dayjs from 'dayjs'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { queryGPUServiceInstanceEvents } from '../apis'; import { InstanceEventItem } from '../config/types'; type ViewEventsModalProps = { open: boolean; name: string; namespace: string; clusterID?: number; onCancel: () => void; }; const formatRelative = (text?: string) => (text ? dayjs(text).fromNow() : '-'); const eventTypeStatus: Record = { Normal: 'success', Warning: 'warning' }; const ViewEventsModal: React.FC = (props) => { const intl = useIntl(); const { open, onCancel, name, namespace, clusterID } = props || {}; const [events, setEvents] = useState([]); const [loading, setLoading] = useState(false); const tokenRef = useRef | null>(null); const fetchEvents = useCallback(async () => { if (!name || !clusterID || !namespace) return; tokenRef.current?.cancel?.(); const source = createAxiosToken(); tokenRef.current = source; setLoading(true); try { const res = await queryGPUServiceInstanceEvents( { name, namespace, clusterID }, { token: source.token } ); setEvents(res?.items ?? []); } catch (e) { // request cancellation or network failure — keep prior items } finally { setLoading(false); } }, [name, namespace, clusterID]); useEffect(() => { if (open) { fetchEvents(); } else { tokenRef.current?.cancel?.(); setEvents([]); } return () => { tokenRef.current?.cancel?.(); }; }, [open, fetchEvents]); const handleCancel = useCallback(() => { tokenRef.current?.cancel?.(); onCancel(); }, [onCancel]); const columns: ColumnsType = [ { title: intl.formatMessage({ id: 'common.table.type' }), dataIndex: 'type', key: 'type', width: 110, render: (value: string) => ( ) }, { title: intl.formatMessage({ id: 'gpuservice.instance.event.reason' }), dataIndex: 'reason', key: 'reason', width: 180, ellipsis: { showTitle: false }, render: (text: string) => ( {text || '-'} ) }, { title: intl.formatMessage({ id: 'gpuservice.instance.event.message' }), dataIndex: 'message', key: 'message', ellipsis: { showTitle: false }, render: (text: string) => {text || '-'} }, { title: intl.formatMessage({ id: 'gpuservice.instance.event.source' }), key: 'source', width: 200, ellipsis: { showTitle: false }, render: (_text, record) => { const src = record.source?.component || record.reportingComponent || record.reportingInstance || '-'; return ( {src} ); } }, { title: intl.formatMessage({ id: 'gpuservice.instance.event.count' }), dataIndex: 'count', key: 'count', width: 80, render: (value?: number) => value ?? '-' }, { title: intl.formatMessage({ id: 'gpuservice.instance.event.lastSeen' }), key: 'lastTimestamp', width: 180, render: (_text, record) => formatRelative( record.lastTimestamp || record.series?.lastObservedTime || record.eventTime ) } ]; return ( {intl.formatMessage({ id: 'common.button.viewevent' })}