// 主机详情弹窗:展示历史指标趋势图 + 端口发现列表(从 AgentMonitor.tsx 提取) // Logan.Li import { useState, useEffect } from 'react'; import { agentApi } from '@/api'; import { isOnline, timeAgo, asList } from './agentUtils'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Server, Activity, Network, Terminal, Loader2 } from 'lucide-react'; import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, } from 'recharts'; import type { JsonData } from '@/types/common'; import i18n from '@/i18n'; export function HostDetailDialog({ host, onClose, onCommand, }: { host?: JsonData; onClose: () => void; onCommand: (hostname: string) => void; }) { const [history, setHistory] = useState([]); const [loading, setLoading] = useState(false); const [hours, setHours] = useState(1); useEffect(() => { if (!host) return; let active = true; setLoading(true); agentApi .getHistory(host.hostname, { hours }) .then((data) => { if (active) setHistory(asList(data)); }) .catch(() => { if (active) setHistory([]); }) .finally(() => { if (active) setLoading(false); }); return () => { active = false; }; }, [host, hours]); if (!host) return null; const online = isOnline(host.last_report || host.last_reported_at || host.updated_at); const ports: JsonData[] = Array.isArray(host.ports) ? host.ports : []; const chartData = history.map((h) => ({ // eslint-disable-next-line react-hooks/purity time: new Date(h.timestamp || h.time || h.created_at || Date.now()).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }), cpu: Number(h.cpu_percent ?? h.cpu ?? 0), mem: Number(h.mem_percent ?? h.mem ?? 0), disk: Number(h.disk_percent ?? h.disk ?? 0), })); return ( { if (!v) onClose(); }}> {host.hostname} {online ? ( {i18n.t('agent.agentOnline')} ) : ( {i18n.t('agent.agentOffline')} )} {i18n.t('agent.hostDetailDialog.desc')}
{/* 基本信息 */}
{/* 趋势图 */}
{i18n.t('common.metricTrend')}
{loading ? (
) : chartData.length === 0 ? (
{i18n.t('agent.hostDetailDialog.noHistoryData')}
) : ( )}
{/* 端口列表 */}
{i18n.t('common.portDiscovery', { count: ports.length })} {ports.length === 0 ? (

{i18n.t('agent.hostDetailDialog.noPortData')}

) : (
{ports.map((p, idx) => ( {p.port ?? p} ))}
)}
); } function InfoCell({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); } export default HostDetailDialog;