import { useState, useCallback } from 'react' import { useReactFlow } from '@xyflow/react' import { Search } from 'lucide-react' import { useCanvasStore } from '@/stores/canvasStore' interface SearchModalProps { open: boolean onClose: () => void } export function SearchModal({ open, onClose }: SearchModalProps) { const [query, setQuery] = useState('') const nodes = useCanvasStore((s) => s.nodes) const setSelectedNode = useCanvasStore((s) => s.setSelectedNode) const { fitView } = useReactFlow() const searchable = nodes.filter((n) => n.data.type !== 'groupRect') const q = query.toLowerCase() const results = q.length === 0 ? [] : searchable.filter((n) => n.data.label?.toLowerCase().includes(q) || n.data.ip?.toLowerCase().includes(q) || n.data.hostname?.toLowerCase().includes(q) ).slice(0, 8) const handleSelect = useCallback((nodeId: string) => { setSelectedNode(nodeId) fitView({ nodes: [{ id: nodeId }], duration: 600, padding: 0.4, maxZoom: 1.5 }) onClose() setQuery('') }, [fitView, setSelectedNode, onClose]) if (!open) return null return (
e.stopPropagation()} >
setQuery(e.target.value)} placeholder="Search nodes by label, IP, hostname…" className="flex-1 bg-transparent text-sm text-foreground placeholder:text-muted-foreground outline-none" onKeyDown={(e) => { if (e.key === 'Escape') { onClose(); setQuery('') } if (e.key === 'Enter' && results.length > 0) handleSelect(results[0].id) }} /> ESC
{results.length > 0 && ( )} {q.length > 0 && results.length === 0 && (

No nodes match "{query}"

)} {q.length === 0 && (

Type to search nodes…

)}
) }