sprint9: app visibility — sidebar permission filter + TopBar + ProtectedRoute + route guards
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
This commit is contained in:
@@ -8,9 +8,10 @@ import { useLogout } from '@/api/hooks';
|
||||
import { Avatar } from '@/components/ui/Avatar';
|
||||
import { SearchDropdown } from '@/components/shared/SearchDropdown';
|
||||
import { SuggestionBadge } from '@/components/ai/SuggestionBadge';
|
||||
import { Building, ChevronDown, Menu, Zap, Bot, Layers, Code } from 'lucide-react';
|
||||
import { Building, ChevronDown, Menu, Zap, Bot, Layers, Code, Plus } from 'lucide-react';
|
||||
import { NotificationBell } from '@/components/layout/NotificationBell';
|
||||
import { useWindowStore } from '@/store/windowStore';
|
||||
import { usePermission } from '@/hooks/usePermission';
|
||||
|
||||
export function TopBar() {
|
||||
const { t } = useTranslation();
|
||||
@@ -20,6 +21,7 @@ export function TopBar() {
|
||||
const { toggleSidebar, toggleMessageSidebar } = useUIStore();
|
||||
const logoutMutation = useLogout();
|
||||
const minimizedWindows = useWindowStore((s) => s.windows.filter((w) => w.state === 'minimized'));
|
||||
const { hasPermission } = usePermission();
|
||||
const restoreWindow = useWindowStore((s) => s.restoreWindow);
|
||||
|
||||
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
||||
@@ -82,6 +84,18 @@ export function TopBar() {
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<NotificationBell />
|
||||
{/* Quick Create */}
|
||||
{hasPermission('contacts:write') && (
|
||||
<button
|
||||
onClick={() => navigate('/contacts/new')}
|
||||
className="flex items-center gap-1.5 bg-primary-600 text-white px-3 py-1.5 rounded-md text-sm font-medium hover:bg-primary-700 min-h-touch focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
|
||||
aria-label={t('topbar.quickCreate')}
|
||||
title={t('topbar.quickCreate', 'Neuer Kontakt')}
|
||||
>
|
||||
<Plus className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
|
||||
<span className="hidden md:inline">{t('topbar.quickCreate', 'Neu')}</span>
|
||||
</button>
|
||||
)}
|
||||
{/* Minimized windows */}
|
||||
{minimizedWindows.length > 0 && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
@@ -130,13 +144,15 @@ export function TopBar() {
|
||||
>
|
||||
{t('topbar.profile')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => { setUserMenuOpen(false); navigate('/settings'); }}
|
||||
className="w-full text-left px-3 py-2 text-sm hover:bg-secondary-50 min-h-touch focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
|
||||
role="menuitem"
|
||||
>
|
||||
{t('topbar.settings')}
|
||||
</button>
|
||||
{hasPermission('settings:read') && (
|
||||
<button
|
||||
onClick={() => { setUserMenuOpen(false); navigate('/settings'); }}
|
||||
className="w-full text-left px-3 py-2 text-sm hover:bg-secondary-50 min-h-touch focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
|
||||
role="menuitem"
|
||||
>
|
||||
{t('topbar.settings')}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => { setUserMenuOpen(false); navigate('/automation'); }}
|
||||
className="w-full text-left px-3 py-2 text-sm hover:bg-secondary-50 min-h-touch focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 flex items-center gap-2"
|
||||
@@ -153,13 +169,15 @@ export function TopBar() {
|
||||
<Bot className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
|
||||
{t('nav.agents', 'Agenten')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => { setUserMenuOpen(false); navigate('/audit-log'); }}
|
||||
className="w-full text-left px-3 py-2 text-sm hover:bg-secondary-50 min-h-touch focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
|
||||
role="menuitem"
|
||||
>
|
||||
{t('nav.auditLog')}
|
||||
</button>
|
||||
{hasPermission('audit:read') && (
|
||||
<button
|
||||
onClick={() => { setUserMenuOpen(false); navigate('/audit-log'); }}
|
||||
className="w-full text-left px-3 py-2 text-sm hover:bg-secondary-50 min-h-touch focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
|
||||
role="menuitem"
|
||||
>
|
||||
{t('nav.auditLog')}
|
||||
</button>
|
||||
)}
|
||||
<a
|
||||
href="/docs"
|
||||
target="_blank"
|
||||
|
||||
Reference in New Issue
Block a user