import { useQuery } from '@tanstack/react-query' import { Shield, Lock, Globe } from 'lucide-react' import { networkApi, type VpnTunnel } from '@/lib/networkApi' import { Skeleton } from '@/components/ui/skeleton' import { Badge } from '@/components/ui/badge' interface VpnTabProps { tenantId: string deviceId: string active: boolean } /** Format byte count to human-readable string. */ function formatBytes(bytes: string | null): string { if (!bytes) return '--' const n = parseInt(bytes, 10) if (isNaN(n)) return bytes if (n >= 1_073_741_824) return `${(n / 1_073_741_824).toFixed(1)} GB` if (n >= 1_048_576) return `${(n / 1_048_576).toFixed(1)} MB` if (n >= 1_024) return `${(n / 1_024).toFixed(1)} KB` return `${n} B` } /** VPN type configuration for icons and colors. */ const VPN_TYPE_CONFIG = { wireguard: { icon: Shield, label: 'WireGuard', color: '#a855f7', // purple }, ipsec: { icon: Lock, label: 'IPsec', color: '#3b82f6', // blue }, l2tp: { icon: Globe, label: 'L2TP', color: '#22c55e', // green }, } as const function TunnelRow({ tunnel }: { tunnel: VpnTunnel }) { const config = VPN_TYPE_CONFIG[tunnel.type] const Icon = config.icon const isUp = tunnel.status === 'connected' || tunnel.status === 'established' return ( {/* Type */}
{config.label}
{/* Remote Endpoint */} {tunnel.remote_endpoint} {/* Status */} {tunnel.status} {/* Uptime */} {tunnel.uptime ?? '--'} {/* RX */} {formatBytes(tunnel.rx_bytes)} {/* TX */} {formatBytes(tunnel.tx_bytes)} ) } export function VpnTab({ tenantId, deviceId, active }: VpnTabProps) { const { data, isLoading, error } = useQuery({ queryKey: ['vpn-tunnels', tenantId, deviceId], queryFn: () => networkApi.getVpnTunnels(tenantId, deviceId), refetchInterval: active ? 30_000 : false, enabled: active, }) if (isLoading) { return (
) } if (error) { return (
Failed to load VPN tunnels. The device may not support this feature.
) } if (!data || data.tunnels.length === 0) { return (

No active VPN tunnels

VPN tunnels will appear here when WireGuard peers, IPsec SAs, or L2TP connections are active on this device.

) } return (
{data.tunnels.map((tunnel, i) => ( ))}
Type Remote Endpoint Status Uptime RX TX
) }