GeoIntel release gates / Compile, test, contracts and builds (push) Successful in 1m49s
GeoIntel release gates / Python and npm vulnerability policy (push) Successful in 21s
GeoIntel release gates / Production AI image, SBOM and container scan (push) Successful in 5m39s
GeoIntel release gates / Deploy exact gated revision to Unraid (push) Failing after 58m43s
92 lines
2.5 KiB
TypeScript
92 lines
2.5 KiB
TypeScript
import {
|
|
Activity,
|
|
Bot,
|
|
Database,
|
|
Download,
|
|
Map,
|
|
ScanSearch,
|
|
Settings,
|
|
ShieldCheck,
|
|
type LucideIcon,
|
|
} from 'lucide-react'
|
|
import type { WorkspaceKey } from '../overview/OverviewWorkspace'
|
|
import { GeoIntelMark } from '../brand/GeoIntelBrand'
|
|
|
|
export interface WorkspaceNavigationItem {
|
|
key: WorkspaceKey
|
|
label: string
|
|
navigationLabel?: string
|
|
description: string
|
|
}
|
|
|
|
export interface WorkspaceNavigationGroup {
|
|
label: string
|
|
keys: WorkspaceKey[]
|
|
}
|
|
|
|
interface WorkbenchNavigationProps {
|
|
activeWorkspace: WorkspaceKey
|
|
groups: WorkspaceNavigationGroup[]
|
|
items: WorkspaceNavigationItem[]
|
|
onSelect: (workspace: WorkspaceKey) => void
|
|
}
|
|
|
|
const workspaceIcons: Record<WorkspaceKey, LucideIcon> = {
|
|
map: Map,
|
|
data: Database,
|
|
assistant: Bot,
|
|
analysis: ShieldCheck,
|
|
ai: ScanSearch,
|
|
exports: Download,
|
|
overview: Activity,
|
|
system: Settings,
|
|
}
|
|
|
|
export function WorkbenchNavigation({
|
|
activeWorkspace,
|
|
groups,
|
|
items,
|
|
onSelect,
|
|
}: WorkbenchNavigationProps): JSX.Element {
|
|
return (
|
|
<aside className="workbench-sidebar" aria-label="Navigatie van de werkruimte">
|
|
<div className="sidebar-brand" aria-label="GeoIntel">
|
|
<GeoIntelMark className="brand-mark" />
|
|
<span className="sidebar-brand-copy">
|
|
<strong>GeoIntel</strong>
|
|
</span>
|
|
</div>
|
|
|
|
<nav aria-label="Hoofdonderdelen">
|
|
{groups.map((group) => (
|
|
<div className="nav-group" key={group.label}>
|
|
<p className="nav-section-label">{group.label}</p>
|
|
{group.keys.map((key) => {
|
|
const item = items.find((candidate) => candidate.key === key)
|
|
if (!item) {
|
|
return null
|
|
}
|
|
const Icon = workspaceIcons[item.key]
|
|
return (
|
|
<button
|
|
key={item.key}
|
|
type="button"
|
|
className={item.key === activeWorkspace ? 'nav-item nav-item-active' : 'nav-item'}
|
|
onClick={() => onSelect(item.key)}
|
|
aria-current={item.key === activeWorkspace ? 'page' : undefined}
|
|
aria-label={`Open ${item.label}: ${item.description}`}
|
|
title={item.description}
|
|
data-testid={`workspace-nav-${item.key}`}
|
|
>
|
|
<Icon className="nav-item-icon" aria-hidden="true" strokeWidth={1.8} />
|
|
<span>{item.navigationLabel ?? item.label}</span>
|
|
</button>
|
|
)
|
|
})}
|
|
</div>
|
|
))}
|
|
</nav>
|
|
</aside>
|
|
)
|
|
}
|