feat(ui): rebuild Sidebar with Fleet/Config/Admin structure
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,30 +7,17 @@ import {
|
|||||||
Settings,
|
Settings,
|
||||||
ChevronLeft,
|
ChevronLeft,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
Bell,
|
|
||||||
BellRing,
|
|
||||||
Download,
|
Download,
|
||||||
Terminal,
|
Terminal,
|
||||||
FileCode,
|
FileCode,
|
||||||
FileText,
|
|
||||||
MapPin,
|
|
||||||
LayoutDashboard,
|
LayoutDashboard,
|
||||||
Network,
|
|
||||||
Wrench,
|
|
||||||
ClipboardList,
|
ClipboardList,
|
||||||
Calendar,
|
Wifi,
|
||||||
Key,
|
BarChart3,
|
||||||
Layers,
|
|
||||||
Shield,
|
|
||||||
ShieldCheck,
|
|
||||||
|
|
||||||
Eye,
|
|
||||||
Info,
|
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { useAuth, isSuperAdmin, isTenantAdmin } from '@/lib/auth'
|
import { useAuth, isSuperAdmin, isTenantAdmin } from '@/lib/auth'
|
||||||
import { useUIStore } from '@/lib/store'
|
import { useUIStore } from '@/lib/store'
|
||||||
import { AlertBadge } from '@/components/alerts/AlertBadge'
|
|
||||||
import { RugLogo } from '@/components/brand/RugLogo'
|
import { RugLogo } from '@/components/brand/RugLogo'
|
||||||
|
|
||||||
interface NavItem {
|
interface NavItem {
|
||||||
@@ -38,7 +25,6 @@ interface NavItem {
|
|||||||
href: string
|
href: string
|
||||||
icon: React.FC<{ className?: string }>
|
icon: React.FC<{ className?: string }>
|
||||||
exact?: boolean
|
exact?: boolean
|
||||||
badge?: React.ReactNode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NavSection {
|
interface NavSection {
|
||||||
@@ -109,12 +95,12 @@ export function Sidebar() {
|
|||||||
visible: true,
|
visible: true,
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: 'Dashboard',
|
label: 'Overview',
|
||||||
href: '/',
|
href: '/',
|
||||||
icon: LayoutDashboard,
|
icon: LayoutDashboard,
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
// Only show Devices for non-super_admin (super_admin uses Organizations in Admin)
|
// Only show Devices for non-super_admin with a tenant_id
|
||||||
...(!isSuperAdmin(user) && user?.tenant_id
|
...(!isSuperAdmin(user) && user?.tenant_id
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
@@ -125,31 +111,26 @@ export function Sidebar() {
|
|||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
{
|
{
|
||||||
label: 'Map',
|
label: 'Wireless',
|
||||||
href: '/map',
|
href: '/wireless',
|
||||||
icon: MapPin,
|
icon: Wifi,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Traffic',
|
||||||
|
href: '/traffic',
|
||||||
|
icon: BarChart3,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Manage',
|
label: 'Config',
|
||||||
visible: true,
|
visible: true,
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: 'Config Editor',
|
label: 'Editor',
|
||||||
href: '/config-editor',
|
href: '/config-editor',
|
||||||
icon: Terminal,
|
icon: Terminal,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Batch Config',
|
|
||||||
href: '/batch-config',
|
|
||||||
icon: Wrench,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Bulk Commands',
|
|
||||||
href: '/bulk-commands',
|
|
||||||
icon: Layers,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Templates',
|
label: 'Templates',
|
||||||
href: '/templates',
|
href: '/templates',
|
||||||
@@ -160,63 +141,6 @@ export function Sidebar() {
|
|||||||
href: '/firmware',
|
href: '/firmware',
|
||||||
icon: Download,
|
icon: Download,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Maintenance',
|
|
||||||
href: '/maintenance',
|
|
||||||
icon: Calendar,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'VPN',
|
|
||||||
href: '/vpn',
|
|
||||||
icon: Shield,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Certificates',
|
|
||||||
href: '/certificates',
|
|
||||||
icon: ShieldCheck,
|
|
||||||
},
|
|
||||||
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Monitor',
|
|
||||||
visible: true,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: 'Topology',
|
|
||||||
href: '/topology',
|
|
||||||
icon: Network,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Alerts',
|
|
||||||
href: '/alerts',
|
|
||||||
icon: Bell,
|
|
||||||
badge: <AlertBadge />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Alert Rules',
|
|
||||||
href: '/alert-rules',
|
|
||||||
icon: BellRing,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Audit Trail',
|
|
||||||
href: '/audit',
|
|
||||||
icon: ClipboardList,
|
|
||||||
},
|
|
||||||
...(isTenantAdmin(user)
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
label: 'Transparency',
|
|
||||||
href: '/transparency',
|
|
||||||
icon: Eye,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
{
|
|
||||||
label: 'Reports',
|
|
||||||
href: '/reports',
|
|
||||||
icon: FileText,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -242,20 +166,15 @@ export function Sidebar() {
|
|||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
{
|
{
|
||||||
label: 'API Keys',
|
label: 'Audit Log',
|
||||||
href: '/settings/api-keys',
|
href: '/audit',
|
||||||
icon: Key,
|
icon: ClipboardList,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Settings',
|
label: 'Settings',
|
||||||
href: '/settings',
|
href: '/settings',
|
||||||
icon: Settings,
|
icon: Settings,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'About',
|
|
||||||
href: '/about',
|
|
||||||
icon: Info,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -310,8 +229,8 @@ export function Sidebar() {
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2.5 px-3 py-2 mx-1 rounded-md text-sm transition-colors min-h-[44px]',
|
'flex items-center gap-2.5 px-3 py-2 mx-1 rounded-md text-sm transition-colors min-h-[44px]',
|
||||||
active
|
active
|
||||||
? 'bg-accent-muted text-accent'
|
? 'bg-[hsl(var(--accent-muted))] text-accent rounded-md'
|
||||||
: 'text-text-secondary hover:text-text-primary hover:bg-elevated/50',
|
: 'text-text-muted hover:text-text-primary hover:bg-elevated/50 rounded-md',
|
||||||
showCollapsed && 'justify-center px-0',
|
showCollapsed && 'justify-center px-0',
|
||||||
)}
|
)}
|
||||||
title={showCollapsed ? item.label : undefined}
|
title={showCollapsed ? item.label : undefined}
|
||||||
@@ -320,10 +239,7 @@ export function Sidebar() {
|
|||||||
>
|
>
|
||||||
<Icon className="h-4 w-4 flex-shrink-0" aria-hidden="true" />
|
<Icon className="h-4 w-4 flex-shrink-0" aria-hidden="true" />
|
||||||
{!showCollapsed && (
|
{!showCollapsed && (
|
||||||
<>
|
<span className="truncate">{item.label}</span>
|
||||||
<span className="truncate">{item.label}</span>
|
|
||||||
{item.badge && <span className="ml-auto">{item.badge}</span>}
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
@@ -332,6 +248,13 @@ export function Sidebar() {
|
|||||||
))}
|
))}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
{/* Version identifier */}
|
||||||
|
{!showCollapsed && (
|
||||||
|
<div className="px-3 py-1 text-center">
|
||||||
|
<span className="font-mono text-[9px] text-text-muted">TOD v9.5</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Collapse toggle (hidden on mobile) */}
|
{/* Collapse toggle (hidden on mobile) */}
|
||||||
<button
|
<button
|
||||||
onClick={toggleSidebar}
|
onClick={toggleSidebar}
|
||||||
@@ -354,9 +277,10 @@ export function Sidebar() {
|
|||||||
{/* Desktop sidebar */}
|
{/* Desktop sidebar */}
|
||||||
<aside
|
<aside
|
||||||
data-testid="sidebar"
|
data-testid="sidebar"
|
||||||
|
data-sidebar
|
||||||
className={cn(
|
className={cn(
|
||||||
'hidden lg:flex flex-col border-r border-border bg-sidebar transition-all duration-200',
|
'hidden lg:flex flex-col border-r border-border bg-sidebar transition-all duration-200',
|
||||||
sidebarCollapsed ? 'w-12' : 'w-60',
|
sidebarCollapsed ? 'w-14' : 'w-[180px]',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{sidebarContent(sidebarCollapsed)}
|
{sidebarContent(sidebarCollapsed)}
|
||||||
@@ -374,7 +298,7 @@ export function Sidebar() {
|
|||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
aria-label="Navigation"
|
aria-label="Navigation"
|
||||||
className="lg:hidden fixed inset-y-0 left-0 z-50 w-60 flex flex-col bg-sidebar border-r border-border shadow-xl"
|
className="lg:hidden fixed inset-y-0 left-0 z-50 w-[180px] flex flex-col bg-sidebar border-r border-border shadow-xl"
|
||||||
>
|
>
|
||||||
{sidebarContent(false)}
|
{sidebarContent(false)}
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
Reference in New Issue
Block a user