import { SegmentedControl } from "@mantine/core"; import { IconApi, IconBook, IconKeyOff, IconSettings, IconUser } from "@tabler/icons-react"; import { TbDatabase, TbFingerprint, TbHierarchy2, TbMenu2, TbPhoto, TbSelector, TbUser, TbX, } from "react-icons/tb"; import { useAuth, useBkndWindowContext } from "bknd/client"; import { useBknd } from "ui/client/bknd"; import { useTheme } from "ui/client/use-theme"; import { Button } from "ui/components/buttons/Button"; import { IconButton } from "ui/components/buttons/IconButton"; import { Logo } from "ui/components/display/Logo"; import { Dropdown, type DropdownProps } from "ui/components/overlay/Dropdown"; import { Link } from "ui/components/wouter/Link"; import { useEvent } from "ui/hooks/use-event"; import { useNavigate } from "ui/lib/routes"; import { useLocation } from "wouter"; import { NavLink } from "./AppShell"; import { autoFormatString } from "core/utils"; import { appShellStore } from "ui/store"; import { getVersion, isDebug } from "core/env"; import { McpIcon } from "ui/routes/tools/mcp/components/mcp-icon"; import { useAppShellAdminOptions } from "ui/options"; export function HeaderNavigation() { const [location, navigate] = useLocation(); const { config } = useBknd(); const items: { label: string; href: string; Icon?: any; exact?: boolean; tooltip?: string; disabled?: boolean; }[] = [ { label: "Data", href: "/data", Icon: TbDatabase }, { label: "Auth", href: "/auth", Icon: TbFingerprint }, { label: "Media", href: "/media", Icon: TbPhoto }, ]; if (isDebug() || Object.keys(config.flows?.flows ?? {}).length > 0) { items.push({ label: "Flows", href: "/flows", Icon: TbHierarchy2 }); } if (config.server.mcp.enabled) { items.push({ label: "MCP", href: "/tools/mcp", Icon: McpIcon }); } const activeItem = items.find((item) => item.exact ? location === item.href : location.startsWith(item.href), ); const handleItemClick = useEvent((item) => { navigate(item.href); }); const renderDropdownItem = (item, { key, onClick }) => (
{item.label}
); return ( <> ); } function SidebarToggler({ name = "default" }: { name?: string }) { const toggle = appShellStore((store) => store.toggleSidebar(name)); const open = appShellStore((store) => store.sidebars[name]?.open); return ; } export function Header({ hasSidebar = true }) { const { app } = useBknd(); const { theme } = useTheme(); const { logo_return_path = "/" } = app.options; return ( ); } function UserMenu() { const { config } = useBknd(); const uiOptions = useAppShellAdminOptions(); const auth = useAuth(); const [navigate] = useNavigate(); const { logout_route } = useBkndWindowContext(); async function handleLogout() { await auth.logout(); if (!auth.local) { navigate(logout_route, { reload: true }); } } async function handleLogin() { navigate("/auth/login"); } const items: DropdownProps["items"] = [ ...(uiOptions.userMenu ?? []), { label: "Settings", onClick: () => navigate("/settings"), icon: IconSettings }, { label: "OpenAPI", onClick: () => window.open("/api/system/swagger", "_blank"), icon: IconApi, }, { label: "Docs", onClick: () => window.open("https://docs.bknd.io", "_blank"), icon: IconBook, }, ]; if (config.server.mcp.enabled) { items.push({ label: "MCP", onClick: () => navigate("/tools/mcp"), icon: McpIcon, }); } if (config.auth.enabled) { if (!auth.user) { items.push({ label: "Login", onClick: handleLogin, icon: IconUser }); } else { items.push({ label: "Logout", title: `Logout ${auth.user.email}`, onClick: handleLogout, icon: IconKeyOff, }); } } items.push(() => ); items.push(() => (
{getVersion()}
)); return ( <> {auth.user ? ( ) : (