import { Globe, Router, Server, Layers, Box, Container, HardDrive, Cpu, Wifi, Circle, Network } from 'lucide-react' import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' interface Service { port: number protocol: string service_name: string icon?: string | null category?: string | null } export interface PendingDevice { id: string ip: string | null mac: string | null hostname: string | null os: string | null services: Service[] suggested_type: string | null status: string discovery_source: string | null ieee_address?: string | null friendly_name?: string | null device_subtype?: string | null model?: string | null vendor?: string | null lqi?: number | null discovered_at: string // How many canvases (designs) this device already appears on. Computed server-side. canvas_count?: number } interface PendingDeviceModalProps { device: PendingDevice | null onClose: () => void onApprove: (device: PendingDevice) => void onHide: (device: PendingDevice) => void onIgnore: (device: PendingDevice) => void } const TYPE_ICONS: Record = { isp: Globe, router: Router, server: Server, proxmox: Layers, vm: Box, lxc: Container, nas: HardDrive, iot: Cpu, ap: Wifi, switch: Network, generic: Circle, } const CATEGORY_COLORS: Record = { hypervisor: '#ff6e00', nas: '#39d353', automation: '#a855f7', containers: '#00d4ff', network: '#39d353', security: '#f85149', monitoring: '#e3b341', database: '#a855f7', web: '#00d4ff', media: '#ff6e00', iot: '#e3b341', } function categoryColor(category: string | null | undefined) { if (!category) return '#8b949e' return CATEGORY_COLORS[category.toLowerCase()] ?? '#8b949e' } function InfoRow({ label, value }: { label: string; value: string }) { return (
{label} {value}
) } export function PendingDeviceModal({ device, onClose, onApprove, onHide, onIgnore }: PendingDeviceModalProps) { if (!device) return null const TypeIcon = TYPE_ICONS[device.suggested_type ?? 'generic'] ?? Circle const isZigbee = device.discovery_source === 'zigbee' const titleLabel = device.friendly_name ?? device.hostname ?? device.ip ?? device.ieee_address ?? 'Pending device' const handleApprove = () => { onApprove(device) } const handleHide = () => { onHide(device); onClose() } const handleIgnore = () => { onIgnore(device); onClose() } return ( !o && onClose()}> {titleLabel} {isZigbee && ( Zigbee )}
{/* Device info */}
{device.ip && } {device.hostname && } {device.mac && } {device.os && } {device.ieee_address && } {device.friendly_name && device.friendly_name !== device.hostname && ( )} {device.vendor && } {device.model && } {device.device_subtype && } {device.lqi != null && } {device.suggested_type && ( )} {device.discovery_source && ( )}
{/* Services (skipped for Zigbee devices — they don't have IP services) */} {!isZigbee &&

Services found ({device.services.length})

{device.services.length === 0 ? (

No services detected

) : (
{device.services.map((svc, i) => (
{svc.port} {svc.protocol} {svc.service_name} {svc.category && ( {svc.category} )}
))}
)}
} {/* Actions */}
) }