From 193c48d0311438cf5b8ee8017b9655a867391c73 Mon Sep 17 00:00:00 2001 From: kitos Date: Fri, 29 May 2026 12:45:59 +0200 Subject: [PATCH] feat(sidebar): add Techniques page to menu under ATT&CK group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /techniques (technique browser with filters) was an orphaned route — only reachable via 'Back to techniques' button or direct URL. Now exposed in the sidebar as part of a new ATT&CK group: ATT&CK ▾ Techniques → /techniques Coverage Matrix → /matrix Review Queue → /techniques/review-queue (leads+admin only) Child role filtering added to SidebarLink. Review Queue badge moved to the ATT&CK group header. --- frontend/src/components/Sidebar.tsx | 36 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 158cab1..3c6c95f 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -16,6 +16,7 @@ import { Crosshair, Zap, Grid3X3, + List, Gauge, ShieldCheck, GitCompareArrows, @@ -37,8 +38,16 @@ interface NavItem { const mainLinks: NavItem[] = [ { to: "/dashboard", label: "Dashboard", icon: LayoutDashboard }, { to: "/executive-dashboard", label: "Executive Dashboard", icon: Gauge, roles: ["admin", "red_lead", "blue_lead", "viewer"] }, - { to: "/matrix", label: "ATT&CK Matrix", icon: Grid3X3 }, - { to: "/techniques/review-queue", label: "Review Queue", icon: ClipboardCheck, roles: ["admin", "red_lead", "blue_lead"] }, + { + to: "/matrix", + label: "ATT&CK", + icon: Grid3X3, + children: [ + { to: "/techniques", label: "Techniques", icon: List }, + { to: "/matrix", label: "Coverage Matrix", icon: Grid3X3 }, + { to: "/techniques/review-queue", label: "Review Queue", icon: ClipboardCheck, roles: ["admin", "red_lead", "blue_lead"] }, + ], + }, { to: "/tests", label: "Tests", @@ -66,8 +75,18 @@ const systemLinks: NavItem[] = [ function SidebarLink({ item, badge }: { item: NavItem; badge?: number }) { const [expanded, setExpanded] = useState(false); + const { user } = useAuth(); + const role = user?.role ?? ""; + const isAdmin = role === "admin"; + + const childCanSee = (child: NavItem) => { + if (!child.roles) return true; + if (isAdmin) return true; + return child.roles.includes(role); + }; if (item.children) { + const visibleChildren = item.children.filter(childCanSee); return (
{expanded && (
- {item.children.map((child) => ( + {visibleChildren.map((child) => ( ))}