import React, { useState, useEffect, useRef } from 'react'; import type { GraphMeta, FilterType, ViewType, LayoutType, SearchResult } from '../types'; // Search configuration constants const SEARCH_DEBOUNCE_MS = 150; // Delay before triggering search API call const SEARCH_BLUR_DELAY_MS = 200; // Delay before hiding search results (must be > SEARCH_DEBOUNCE_MS) const MIN_SEARCH_QUERY_LENGTH = 1; // Minimum characters to trigger search interface HeaderProps { meta: GraphMeta; activeFilter: FilterType; currentView: ViewType; currentLayout: LayoutType; onFilterChange: (filter: FilterType) => void; onViewChange: (view: ViewType) => void; onLayoutChange: (layout: LayoutType) => void; onSearchSelect: (nodeId: string) => void; } export const Header: React.FC = ({ meta, activeFilter, currentView, currentLayout, onFilterChange, onViewChange, onLayoutChange, onSearchSelect, }) => { const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState([]); const [showResults, setShowResults] = useState(false); const searchTimeoutRef = useRef(); const searchInputRef = useRef(null); useEffect(() => { if (searchQuery.length < 1) { setShowResults(false); return; } if (searchTimeoutRef.current) { clearTimeout(searchTimeoutRef.current); } searchTimeoutRef.current = window.setTimeout(async () => { try { const response = await fetch(`/api/search?q=${encodeURIComponent(searchQuery)}`); const data = await response.json(); setSearchResults(data.results || []); setShowResults(true); } catch (error) { console.error('Search error:', error); setSearchResults([]); setShowResults(false); } }, SEARCH_DEBOUNCE_MS); return () => { if (searchTimeoutRef.current) { clearTimeout(searchTimeoutRef.current); } }; }, [searchQuery]); const handleSearchSelect = (nodeId: string) => { onSearchSelect(nodeId); setSearchQuery(''); setShowResults(false); searchInputRef.current?.blur(); }; const handleSearchBlur = () => { setTimeout(() => setShowResults(false), SEARCH_BLUR_DELAY_MS); }; return (
{meta.ontologyName}
setSearchQuery(e.target.value)} onBlur={handleSearchBlur} />
{searchResults.length > 0 ? ( searchResults.map((result) => (
handleSearchSelect(result.id)} > {result.label} {result.matchType}
)) ) : (
No results found
)}
{meta.totalUserContextFunctions > 0 && ( )} {meta.totalOrganizationContextFunctions > 0 && ( )}
); };