import type { ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; import { Popover } from 'antd'; import { CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons'; import type { OutboundTestResult } from '@/hooks/useXraySetting'; interface TestResultPopoverProps { result: OutboundTestResult; // Custom trigger element; defaults to the ok/fail latency pill. children?: ReactNode; } // Latency pill + detail popover for an outbound test result: per-endpoint // dial outcomes for TCP probes, HTTP status and the timing breakdown for // HTTP probes. export default function TestResultPopover({ result: r, children }: TestResultPopoverProps) { const { t } = useTranslation(); const breakdown: Array<{ key: string; label: string; value: string }> = []; if (typeof r.httpStatus === 'number') { breakdown.push({ key: 'status', label: t('pages.xray.outbound.httpStatus'), value: String(r.httpStatus) }); } if (typeof r.connectMs === 'number') { breakdown.push({ key: 'connect', label: t('pages.xray.outbound.breakdownConnect'), value: `${r.connectMs} ms` }); } if (typeof r.tlsMs === 'number') { breakdown.push({ key: 'tls', label: t('pages.xray.outbound.breakdownTls'), value: `${r.tlsMs} ms` }); } if (typeof r.ttfbMs === 'number') { breakdown.push({ key: 'ttfb', label: t('pages.xray.outbound.breakdownTtfb'), value: `${r.ttfbMs} ms` }); } return (
{r.success ? {r.delay} ms : {r.error || 'failed'}} {r.mode && {String(r.mode).toUpperCase()}}
{(r.endpoints || []).map((ep) => (
{ep.address} {ep.success ? `${ep.delay} ms` : ep.error || 'failed'}
))} {breakdown.map((row) => (
{row.label} {row.value}
))} } > {children ?? ( {r.success ? : } {r.success ? {r.delay} ms : failed} )}
); }