/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ import { Link, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import * as LucideIcons from 'lucide-react'; const { Sun, Moon, User, LogOut, Check, Menu, Sparkles, Search } = LucideIcons; import { Button } from '@/components/ui/button'; import { GlobalSearch } from '@/components/common/GlobalSearch'; import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog'; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import Logo from '@/components/common/Logo'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import { EnterpriseUpsell } from '@/components/common/EnterpriseUpsell'; import { findFirstAccessibleLinkInLayout, findFirstVisibleLinkInLayout, visibleLayouts } from '@/lib/layout'; import { useUIStore } from '@/stores/uiStore'; import { useAuthStore } from '@/stores/authStore'; import { buildEndSessionUrl, getPostLogoutRedirectUri } from '@/services/auth/oauth'; import { useState } from 'react'; import { useAccountStore } from '@/stores/accountStore'; import { useSchemaStore } from '@/stores/schemaStore'; function getIcon(name: string): LucideIcons.LucideIcon { const formatted = name .split('-') .map((s) => s[0].toUpperCase() + s.slice(1)) .join(''); return ((LucideIcons as Record)[formatted] as LucideIcons.LucideIcon) || LucideIcons.Circle; } export function TopBar() { const { t } = useTranslation(); const navigate = useNavigate(); const theme = useUIStore((s) => s.theme); const toggleTheme = useUIStore((s) => s.toggleTheme); const toggleSidebar = useUIStore((s) => s.toggleSidebar); const setActiveSection = useUIStore((s) => s.setActiveSection); const accounts = useAuthStore((s) => s.accounts); const activeAccountId = useAuthStore((s) => s.activeAccountId); const switchAccount = useAuthStore((s) => s.switchAccount); const logout = useAuthStore((s) => s.logout); const edition = useAccountStore((s) => s.edition); const hasObjectPermission = useAccountStore((s) => s.hasObjectPermission); const hasPermission = useAccountStore((s) => s.hasPermission); const schema = useSchemaStore((s) => s.schema); const [upsellOpen, setUpsellOpen] = useState(false); const [mobileSearchOpen, setMobileSearchOpen] = useState(false); const navigableLayouts = schema ? visibleLayouts(schema, edition, (prefix) => hasObjectPermission(prefix, 'Get'), hasPermission) : []; return (
{t('version.label', 'Stalwart WebUI v{{version}}', { version: __APP_VERSION__ })}
{edition !== 'enterprise' && setUpsellOpen(false)} />} {t('search', 'Search')} setMobileSearchOpen(false)} /> {schema && navigableLayouts.length > 0 && ( <> {t('sections', 'Sections')} {navigableLayouts.map((layout) => { const Icon = getIcon(layout.icon); return ( { setActiveSection(layout.name); const canGet = (prefix: string) => hasObjectPermission(prefix, 'Get'); const firstLink = findFirstAccessibleLinkInLayout(schema, layout, edition, canGet, hasPermission) ?? findFirstVisibleLinkInLayout(schema, layout, edition, canGet, hasPermission); if (firstLink) { navigate(`/${layout.name}/${firstLink}`); } }} > {layout.name} ); })} )} {Object.keys(accounts).length > 0 && ( <> {t('accounts', 'Accounts')} {Object.entries(accounts).map(([id, info]) => ( switchAccount(id)}> {id === activeAccountId && } {info.name || id} ))} )} {edition !== 'enterprise' && ( <> setUpsellOpen(true)}> {t('tryEnterprise', 'Try Enterprise')} )} { const endSessionEndpoint = useAuthStore.getState().endSessionEndpoint; logout(); if (endSessionEndpoint) { window.location.href = buildEndSessionUrl(endSessionEndpoint, getPostLogoutRedirectUri()); } else { navigate('/login'); } }} > {t('logout', 'Logout')}
); }