import React, { useState, useMemo, useCallback } from "react"; import { useAgentGraph } from "@/context/AgentGraphContext"; import { useNavigation } from "@/context/NavigationContext"; import { Search, Bell, Settings, HelpCircle, User, ChevronDown, FileText, GitBranch, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { WelcomeGuideModal } from "@/components/shared/WelcomeGuideModal"; import { SettingsModal } from "@/components/shared/SettingsModal"; export function TopNavBar() { const { state, actions } = useAgentGraph(); const navigation = useNavigation(); const [searchQuery, setSearchQuery] = useState(""); const [isSearchOpen, setIsSearchOpen] = useState(false); const [isHelpModalOpen, setIsHelpModalOpen] = useState(false); const [isNotificationsOpen, setIsNotificationsOpen] = useState(false); const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false); const handleDashboardClick = useCallback(() => { actions.setActiveView("welcome"); }, [actions]); const searchResults = useMemo(() => { if (!searchQuery.trim()) return { traces: [], graphs: [] }; const query = searchQuery.toLowerCase(); const traces = state.traces.filter( (trace) => trace.filename.toLowerCase().includes(query) || trace.title?.toLowerCase().includes(query) || trace.description?.toLowerCase().includes(query) ); const graphs = state.knowledgeGraphs.filter( (kg) => kg.filename.toLowerCase().includes(query) || kg.kg_id.toLowerCase().includes(query) ); return { traces: traces.slice(0, 5), graphs: graphs.slice(0, 5) }; }, [searchQuery, state.traces, state.knowledgeGraphs]); const handleSearchSelect = useCallback( (type: "trace" | "graph", id: string) => { if (type === "trace") { const trace = state.traces.find((t) => t.id.toString() === id); if (trace) { actions.setSelectedTrace(trace); actions.setActiveView("trace-kg"); } } else { const graph = state.knowledgeGraphs.find((kg) => kg.kg_id === id); if (graph) { actions.setSelectedKnowledgeGraph(graph); actions.setActiveView("kg-visualizer"); } } setIsSearchOpen(false); setSearchQuery(""); }, [state.traces, state.knowledgeGraphs, actions] ); // Close search when clicking outside React.useEffect(() => { const handleClickOutside = (event: MouseEvent) => { const target = event.target as Element; if (!target.closest(".search-container")) { setIsSearchOpen(false); } }; if (isSearchOpen) { document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); } return undefined; }, [isSearchOpen]); const results = searchResults; const hasResults = results.traces.length > 0 || results.graphs.length > 0; // Memoize notification calculations to prevent infinite loops const unreadNotificationsCount = useMemo(() => { return navigation.state.notifications.filter((n) => !n.read).length; }, [navigation.state.notifications]); const hasUnreadNotifications = unreadNotificationsCount > 0; return (
{/* Left Section - Logo and Brand */}
{/* Logo */}
{/* Simple, Modern AgentGraph Icon */} {/* Main diamond shape representing AI core */} {/* Connection nodes */} {/* Graph connections */}
AgentGraph
{/* Navigation Divider */}
{/* Enhanced Search Bar */}
setSearchQuery(e.target.value)} onFocus={() => setIsSearchOpen(true)} className="w-full pl-10 h-9 bg-slate-700/50 border-slate-600 text-white placeholder-slate-400 hover:bg-slate-700/70 focus:bg-slate-700 transition-colors" /> {/* Search Results Dropdown */} {isSearchOpen && (
{searchQuery.trim() && hasResults ? (
{results.traces.length > 0 && (
Traces
{results.traces.map((trace) => ( ))}
)} {results.graphs.length > 0 && (
Agent Graphs
{results.graphs.map((graph) => ( ))}
)}
) : searchQuery.trim() && !hasResults ? (

No results found

) : (

Start typing to search...

)}
)}
{/* Right Section - User Actions with enhanced styling */}
{/* Notifications */}

Notifications

{unreadNotificationsCount} unread

{navigation.state.notifications.length > 0 ? ( navigation.state.notifications .slice(0, 10) .map((notification) => { // Get notification type colors const getNotificationColor = (type: string) => { switch (type) { case "success": return "border-l-green-500 bg-green-50 dark:bg-green-950/20"; case "error": return "border-l-red-500 bg-red-50 dark:bg-red-950/20"; case "warning": return "border-l-yellow-500 bg-yellow-50 dark:bg-yellow-950/20"; case "info": return "border-l-blue-500 bg-blue-50 dark:bg-blue-950/20"; default: return "border-l-gray-500 bg-gray-50 dark:bg-gray-950/20"; } }; return ( navigation.actions.markNotificationRead( notification.id ) } >
{notification.title} {notification.timestamp.toLocaleDateString()}

{notification.message}

); }) ) : (

No notifications

)}
{navigation.state.notifications.length > 0 && (
)}
{/* Help */} {/* Settings */} {/* Divider */}
{/* User Menu with enhanced styling */} Profile Settings Help & Support Log out
{/* Help Modal */} {/* Settings Modal */}
); }