import { ReloadOutlined } from '@ant-design/icons'; import { AlertBlockInfo, AutoTooltip, ScrollerModal, StatusTag } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Button, Table, Tabs, TabsProps } from 'antd'; import type { ColumnsType } from 'antd/lib/table'; import dayjs from 'dayjs'; import React, { useEffect, useMemo, useState } from 'react'; import { InstanceEventItem } from '../config/types'; import useQueryInstanceEvents from '../services/use-query-instance-events'; import useQueryVolumeEvents from '../services/use-query-volume-events'; type ViewEventsModalProps = { open: boolean; name: string; namespace: string; volumeName?: string; clusterID?: number; hasPersistentVolume?: boolean; 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, volumeName, hasPersistentVolume } = props || {}; const [activeKey, setActiveKey] = useState('instance'); const { detailData: instanceEventsData, loading: instanceLoading, cancelRequest: cancelInstanceRequest, fetchData: fetchInstanceEvents } = useQueryInstanceEvents(); const { detailData: volumeEventsData, loading: volumeLoading, cancelRequest: cancelVolumeRequest, fetchData: fetchVolumeEvents } = useQueryVolumeEvents(); const instanceEvents = instanceEventsData?.items ?? []; const volumeEvents = volumeEventsData?.items ?? []; const refreshAll = () => { if (!name || !namespace || !clusterID) return; fetchInstanceEvents({ name, namespace, clusterID }); if (hasPersistentVolume) { fetchVolumeEvents({ name: volumeName || '', namespace, clusterID }); } }; useEffect(() => { if (open) { refreshAll(); } else { cancelInstanceRequest(); cancelVolumeRequest(); } return () => { cancelInstanceRequest(); cancelVolumeRequest(); }; }, [open]); const handleCancel = () => { cancelInstanceRequest(); cancelVolumeRequest(); onCancel(); }; const columns: ColumnsType = useMemo( () => [ { 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 ) } ], [intl] ); const renderTable = ( dataSource: InstanceEventItem[], tableLoading: boolean ) => ( `${record.metadata?.name}-${record.metadata?.namespace}` } loading={{ spinning: tableLoading, size: 'middle' }} virtual scroll={{ y: 'calc(100vh - 80px)' }} pagination={false} /> ); const tabItems: TabsProps['items'] = [ { key: 'instance', label: intl.formatMessage({ id: 'gpuservice.instance.event.tab.instance' }), children: renderTable(instanceEvents, instanceLoading) }, ...(hasPersistentVolume ? [ { key: 'volume', label: intl.formatMessage({ id: 'gpuservice.instance.event.tab.volume' }), children: renderTable(volumeEvents, volumeLoading) } ] : []) ]; const isLoading = instanceLoading || (hasPersistentVolume && volumeLoading); return ( {intl.formatMessage({ id: 'common.button.viewevent' })}