// CIL[BEGIN chunk_id="workbenchsidebar_workbenchsidebar_1785096505" type="component" identity="WorkbenchSidebar" parent="none"] // CIL[DOC-MACRO purpose="Render the Workbench sidebar navigation with role switching and incident badge"] // CIL[DOC-RESPONSIBILITY responsibility="Display navigation links, role selector, and active incident count for the Workbench app"] // CIL[DOC-CONTEXT module="workbench.components" layer="frontend-component" related_files="[\"custom/apps/workbench/hooks/useWorkbenchRole.ts\",\"custom/apps/workbench/index.tsx\"]"] // CIL[DOC-CONTRACT inputs="React.ComponentProps" outputs="JSX sidebar" errors="none" side_effects="navigates via router, fetches incident count"] // CIL[DOC-MICRO logic_summary="Renders a shadcn Sidebar with menu sections, a role-select dropdown, and an incident badge fetched from admin-data" notable_decisions="[]"] // CIL[DOC-CONFIDENCE pass="first" score="0.90" flags="none"] // CIL[DOC-STABILITY stability="stable"] // CIL[DOC-AUDIENCE audience="developer"] import * as React from 'react' import { useEffect, useState } from 'react' import { useNavigate, useLocation } from 'react-router-dom' import { useAppPath } from '@core/hooks/useAppPath' import { LayoutDashboard, Siren, ClipboardList, Map, Calendar, ListTodo, CircleParking, BookOpen, FlaskConical, Gauge, ChevronRight, ChevronDown, Library, ScrollText, Inbox, Lightbulb, Search, FolderGit2, Users, } from 'lucide-react' import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarRail, SidebarSeparator, } from '@core/components/ui/sidebar' import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from '@core/components/ui/collapsible' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@core/components/ui/select' import { Badge } from '@core/components/ui/badge' import { apiFetch } from '@core/lib/api' import { useWorkbenchRole } from '../hooks/useWorkbenchRole' import { useAuth } from '@core/contexts/AuthContext' const ROLE_LABELS: Record = { product: 'Product', engineering: 'Engineering', devops: 'DevOps', qa: 'QA', delivery: 'Delivery', docs: 'Docs', support: 'Support', sales: 'Sales', management: 'Management', proserve: 'Proserve', } type NavItem = { title: string url: string icon: React.ElementType isRole?: boolean } const GLOBAL_ITEMS: NavItem[] = [ { title: 'Command Center', url: '/dashboard', icon: LayoutDashboard, isRole: false }, ] const INTAKE_ITEMS: NavItem[] = [ { title: 'Ideas', url: '/intake/ideas', icon: Lightbulb, isRole: false }, { title: 'Discovery Board', url: '/intake/discovery-board', icon: Search, isRole: false }, ] const ROADMAP_ITEMS: NavItem[] = [ { title: 'Initiatives', url: '/planning/initiatives-board', icon: Map, isRole: false }, { title: 'Epics', url: '/planning/epics-board', icon: Map, isRole: false }, ] const ROLE_VIEWS: NavItem[] = [ { title: 'Dashboard', url: '/dashboard', icon: Gauge }, { title: 'Kanban Board', url: '/board', icon: ClipboardList }, ] const PLANNING_ITEMS: NavItem[] = [ { title: 'Prioritization', url: '/prioritization', icon: ListTodo }, { title: 'Sprints', url: '/prioritization/sprints', icon: Calendar }, { title: 'Backlog', url: '/prioritization/backlog', icon: ListTodo }, { title: 'Parking Lot', url: '/prioritization/parking-lot', icon: CircleParking }, ] const SPECIALTY_ITEMS: NavItem[] = [ { title: 'Docs Kanban', url: '/docs-tickets', icon: BookOpen }, { title: 'Test Plan Kanban', url: '/test-plans', icon: FlaskConical }, ] const DEVOPS_ITEMS: NavItem[] = [ { title: 'DevOps Dashboard', url: '/devops/dashboard', icon: Gauge, isRole: false }, ] const CIL_ITEMS: NavItem[] = [ { title: 'CIL Projects', url: '/knowledge/cil/projects', icon: FolderGit2, isRole: false }, ] const CROSS_ROLE_ITEMS: NavItem[] = [ { title: 'Knowledge Base', url: '/knowledge/dashboard', icon: Library, isRole: false }, { title: 'Logging', url: '/logging/logs', icon: ScrollText, isRole: false }, ] const RESOLVED_INCIDENT_STATUSES = ['resolved', 'postmortem_complete'] function buildUrl(item: NavItem, appPath: (p: string) => string, role: string) { return appPath(item.isRole === false ? item.url : `/work/${role}${item.url}`) } function isActive(item: NavItem, pathname: string, appPath: (p: string) => string, role: string) { return pathname.startsWith(buildUrl(item, appPath, role)) } export function WorkbenchSidebar(props: React.ComponentProps) { const navigate = useNavigate() const location = useLocation() const appPath = useAppPath() const { role, selectRole, roles } = useWorkbenchRole() const { user } = useAuth() const isTeamAdmin = user?.is_system_admin || user?.role === 'engineering_admin' || user?.roles?.some((r: string) => r === 'engineering_admin') const [incidentCount, setIncidentCount] = useState(0) const [intakeOpen, setIntakeOpen] = useState(false) const [roadmapOpen, setRoadmapOpen] = useState(false) const [workOpen, setWorkOpen] = useState(false) const [devopsOpen, setDevopsOpen] = useState(false) const [cilOpen, setCilOpen] = useState(false) const [crossRoleOpen, setCrossRoleOpen] = useState(false) const [planningOpen, setPlanningOpen] = useState(false) useEffect(() => { let cancelled = false apiFetch('/api/admin-data?entity=items&type_slug=workbench_work_item&limit=200') .then(r => (r.ok ? r.json() : { data: [] })) .then(json => { if (cancelled) return const items = Array.isArray(json?.data) ? json.data : [] const active = items.filter( (item: any) => item.data?.work_type === 'incident_followup' && !RESOLVED_INCIDENT_STATUSES.includes(item.data?.incident_status) ).length setIncidentCount(active) }) .catch(() => { if (!cancelled) setIncidentCount(0) }) return () => { cancelled = true } }, []) return ( navigate(appPath('/dashboard'))}>
Wb
Workbench {ROLE_LABELS[role]}
{incidentCount > 0 && ( navigate(appPath('/incident/dashboard'))} className="text-red-600 hover:bg-red-50 hover:text-red-700 border border-red-300" > Incident {incidentCount} )} {GLOBAL_ITEMS.map(item => ( navigate(buildUrl(item, appPath, role))} > {item.title} ))} Intake {intakeOpen ? : } {INTAKE_ITEMS.map(item => ( navigate(buildUrl(item, appPath, role))} > {item.title} ))} Planning {roadmapOpen ? : } {ROADMAP_ITEMS.map(item => ( navigate(buildUrl(item, appPath, role))} > {item.title} ))} Work {workOpen ? : }
{ROLE_VIEWS.map(item => ( navigate(buildUrl(item, appPath, role))} > {item.title} ))} Planning {planningOpen ? : } {PLANNING_ITEMS.map(item => ( navigate(buildUrl(item, appPath, role))} > {item.title} ))} {SPECIALTY_ITEMS.map(item => ( navigate(buildUrl(item, appPath, role))} > {item.title} ))}
DevOps {devopsOpen ? : } {DEVOPS_ITEMS.map(item => ( navigate(buildUrl(item, appPath, role))} > {item.title} ))} CIL {cilOpen ? : } {CIL_ITEMS.map(item => ( navigate(buildUrl(item, appPath, role))} > {item.title} ))} Cross-Role {crossRoleOpen ? : } {CROSS_ROLE_ITEMS.map(item => ( navigate(buildUrl(item, appPath, role))} > {item.title} ))} {isTeamAdmin && ( navigate(appPath('/team'))} > Team )}
) } // CIL[END chunk_id="workbenchsidebar_workbenchsidebar_1785096505"]