import { ArrowUpRight, BookUser, Boxes, BoxIcon, BugIcon, Building, Building2, ChartColumnBig, ChevronsLeftRightEllipsis, Construction, DatabaseZap, FlaskConical, FolderGit, Globe, KeyRound, Landmark, LayoutGrid, LogOut, Logs, Network, PanelLeftClose, Plug, Puzzle, ScrollText, Search, SearchCheck, Settings, Settings2Icon, ShieldCheck, ShieldUser, Shuffle, SlidersHorizontal, Telescope, ToolCase, TrendingUp, User, UserRoundCheck, Users, Wallet, WalletCards, } from "lucide-react"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Separator } from "@/components/ui/separator"; import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, useSidebar, } from "@/components/ui/sidebar"; import { useWebSocket } from "@/hooks/useWebSocket"; import { IS_ENTERPRISE, TRIAL_EXPIRY } from "@/lib/constants/config"; import { useGetCoreConfigQuery, useGetLatestReleaseQuery, useGetVersionQuery, useLogoutMutation } from "@/lib/store"; import { cn } from "@/lib/utils"; import { RbacOperation, RbacResource, useRbac } from "@enterprise/lib"; import type { UserInfo } from "@enterprise/lib/store/utils/tokenManager"; import { getUserInfo } from "@enterprise/lib/store/utils/tokenManager"; import { BooksIcon, DiscordLogoIcon, GithubLogoIcon } from "@phosphor-icons/react"; import { Link, useLocation, useNavigate } from "@tanstack/react-router"; import { differenceInDays } from "date-fns"; import { ChevronRight } from "lucide-react"; import { useTheme } from "next-themes"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useCookies } from "react-cookie"; import { ThemeToggle } from "./themeToggle"; import { Badge } from "./ui/badge"; import { PromoCardStack } from "./ui/promoCardStack"; // Cookie name for dismissing production setup card const PRODUCTION_SETUP_DISMISSED_COOKIE = "bifrost_production_setup_dismissed"; // Custom MCP Icon Component const MCPIcon = ({ className }: { className?: string }) => ( MCP clients icon ); // Main navigation items // External links const externalLinks = [ { title: "Discord Server", url: "https://discord.gg/exN5KAydbU", icon: DiscordLogoIcon, }, { title: "GitHub Repository", url: "https://github.com/maximhq/bifrost", icon: GithubLogoIcon, }, { title: "Report a bug", url: "https://github.com/maximhq/bifrost/issues/new?title=[Bug Report]&labels=bug&type=bug&projects=maximhq/1", icon: BugIcon, strokeWidth: 1.5, }, { title: "Full Documentation", url: "https://docs.getbifrost.ai", icon: BooksIcon, strokeWidth: 1, }, ]; // Base promotional card (memoized outside component to prevent recreation) const productionSetupHelpCard = { id: "production-setup", title: "Need help with production setup?", description: ( <> We offer help with production setup including custom integrations and dedicated support.

Book a demo with our team{" "} here . ), dismissible: true, }; // Sidebar item interface interface SidebarItem { title: string; url: string; icon: React.ComponentType<{ className?: string }>; description: string; isAllowed?: boolean; hasAccess: boolean; subItems?: SidebarItem[]; tag?: string; isExternal?: boolean; queryParam?: string; // Optional: for tab-based subitems (e.g., "client-settings") } const getSidebarItemHref = (item: Pick) => { return item.queryParam ? `${item.url}?tab=${item.queryParam}` : item.url; }; const TIME_FILTER_PAGES = new Set(["/workspace/dashboard", "/workspace/logs", "/workspace/mcp-logs"]); const SidebarItemView = ({ item, isActive, isExternal, isWebSocketConnected, isExpanded, onToggle, pathname, search, isSidebarCollapsed, expandSidebar, highlightedUrl, }: { item: SidebarItem; isActive: boolean; isExternal?: boolean; isWebSocketConnected: boolean; isExpanded?: boolean; onToggle?: () => void; pathname: string; search: string; isSidebarCollapsed: boolean; expandSidebar: () => void; highlightedUrl?: string; }) => { const hasSubItems = "subItems" in item && item.subItems && item.subItems.length > 0; const isRouteMatch = (url: string) => { if (url === "/workspace/custom-pricing") return pathname === url; return pathname.startsWith(url); }; const isAnySubItemActive = hasSubItems && item.subItems?.some((subItem) => { return isRouteMatch(subItem.url); }); const handleClick = (e: React.MouseEvent) => { if (hasSubItems && item.hasAccess) { e.preventDefault(); // If sidebar is collapsed, expand it first then toggle the submenu if (isSidebarCollapsed) { expandSidebar(); // Small delay to allow sidebar to expand before toggling submenu setTimeout(() => { if (onToggle) onToggle(); }, 100); } else if (onToggle) { onToggle(); } } }; const isHighlighted = !hasSubItems && highlightedUrl === item.url; const buttonClassName = `relative h-7.5 cursor-pointer rounded-sm border px-3 transition-all duration-200 ${ isHighlighted ? "bg-sidebar-accent text-accent-foreground border-primary/20" : isActive || isAnySubItemActive ? "bg-sidebar-accent text-primary border-primary/20" : item.hasAccess ? "hover:bg-sidebar-accent hover:text-accent-foreground border-transparent text-slate-500 dark:text-zinc-400" : "hover:bg-destructive/5 hover:text-muted-foreground text-muted-foreground cursor-not-allowed border-transparent" } `; const innerContent = (
{item.title} {item.tag && ( {item.tag} )}
{hasSubItems && ( )} {!hasSubItems && item.url === "/logs" && isWebSocketConnected && (
)} {isExternal && }
); // Render strategy: // - Items with sub-items:
{/* Collapsed state: vertical layout */}
Bifrost
{ setSearchQuery(e.target.value); setFocusedIndex(-1); }} onKeyDown={handleSearchKeyDown} className="border-input text-foreground placeholder:text-shadow-muted-foreground focus:ring-ring h-8 w-full rounded-sm border bg-transparent pr-14 pl-8 text-sm outline-none focus:bg-transparent" /> K
{filteredItems.map((item) => { const isActive = isActiveRoute(item.url); const highlightedUrl = focusedIndex >= 0 ? navigableItems[focusedIndex]?.url : undefined; return ( toggleItem(item.title)} pathname={pathname} search={search} isSidebarCollapsed={sidebarState === "collapsed"} expandSidebar={() => toggleSidebar()} highlightedUrl={highlightedUrl} /> ); })}
{externalLinks.map((item, index) => (
))} {IS_ENTERPRISE && userInfo && (userInfo.name || userInfo.email) ? (

{userInfo.name || userInfo.email || "User"}

) : isAuthEnabled && !IS_ENTERPRISE ? (
) : null}
{version ?? ""}
{trialDaysRemaining !== null && (
{trialDaysRemaining} {trialDaysRemaining === 1 ? "day" : "days"} remaining
)}
); }