import { Card, Drawer, Space, Tag, Typography } from 'antd'; import type { HostIntelligenceEvidence } from '../../types/analysis'; import { endpointText, formatBytes, formatTimestamp, protocolColor, renderLabelTags, } from './shared.tsx'; const { Text } = Typography; export function HostDetailDrawer({ host, open, onClose, }: { host: HostIntelligenceEvidence | null; open: boolean; onClose: () => void; }) { return ( {host == null ? null : ( IP: {host.ip_address ?? '—'} MAC: {host.mac_address ?? '—'} Interfaces: {host.interfaces.join(', ') || '—'} First seen: {formatTimestamp(host.first_seen)} | Last seen: {formatTimestamp(host.last_seen)}
{renderLabelTags(host.hostnames, 'geekblue')}
{host.top_protocols.length === 0 ? ( No protocol profile available yet. ) : ( host.top_protocols.map((protocol) => { const maxCount = Math.max(...host.top_protocols.map((item) => item.packet_count), 1); const widthPct = (protocol.packet_count / maxCount) * 100; return (
{protocol.label} {protocol.packet_count}
); }) )} {host.peers.length === 0 ? ( No peer details available yet. ) : ( host.peers.map((peer) => { const maxCount = Math.max(...host.peers.map((item) => item.packet_count), 1); const widthPct = (peer.packet_count / maxCount) * 100; return (
{endpointText(peer.ip_address, peer.mac_address)} {peer.packet_count} packets · {formatBytes(peer.byte_count)} · {formatTimestamp(peer.last_seen)}
{renderLabelTags(peer.protocols, 'purple')}
); }) )}
{host.services.length === 0 ? ( No service evidence inferred yet. ) : ( host.services.map((service) => (
Port {service.port ?? '—'} · {service.protocol} · {service.packet_count} packets · {formatBytes(service.byte_count)}
{renderLabelTags(service.hostnames, 'geekblue')}
)) )}
)} ); }