feat(phase-33): final polish V3 - navigation, performance, and documentation (T-238 to T-240)

This commit is contained in:
2026-02-10 09:21:35 +01:00
parent 35983de67e
commit 14f8485f06
14 changed files with 1446 additions and 320 deletions

View File

@@ -19,6 +19,7 @@ import {
Gauge,
ShieldCheck,
GitCompareArrows,
ScrollText,
} from "lucide-react";
import { useAuth } from "../context/AuthContext";
@@ -26,13 +27,15 @@ interface NavItem {
to: string;
label: string;
icon: React.FC<{ className?: string }>;
/** Roles allowed to see this item. undefined = everyone. */
roles?: string[];
children?: NavItem[];
}
const mainLinks: NavItem[] = [
{ to: "/dashboard", label: "Dashboard", icon: LayoutDashboard },
{ to: "/techniques", label: "ATT&CK Matrix", icon: Shield },
{ to: "/matrix", label: "Advanced Heatmap", icon: Grid3X3 },
{ to: "/executive-dashboard", label: "Executive Dashboard", icon: Gauge, roles: ["admin", "red_lead", "blue_lead"] },
{ to: "/matrix", label: "ATT&CK Matrix", icon: Grid3X3 },
{
to: "/tests",
label: "Tests",
@@ -43,19 +46,18 @@ const mainLinks: NavItem[] = [
{ to: "/test-catalog", label: "Test Catalog", icon: BookOpen },
],
},
{ to: "/executive-dashboard", label: "Executive Dashboard", icon: Gauge },
{ to: "/reports", label: "Reports", icon: BarChart3 },
{ to: "/threat-actors", label: "Threat Actors", icon: Crosshair },
{ to: "/campaigns", label: "Campaigns", icon: Zap },
{ to: "/comparison", label: "Comparison", icon: GitCompareArrows },
{ to: "/threat-actors", label: "Threat Actors", icon: Crosshair },
{ to: "/compliance", label: "Compliance", icon: ShieldCheck },
{ to: "/comparison", label: "Comparison", icon: GitCompareArrows, roles: ["admin", "red_lead", "blue_lead"] },
{ to: "/reports", label: "Reports", icon: BarChart3 },
];
const adminLinks: NavItem[] = [
const systemLinks: NavItem[] = [
{ to: "/data-sources", label: "Data Sources", icon: Database },
{ to: "/system", label: "MITRE Sync", icon: ScrollText },
{ to: "/users", label: "Users", icon: Users },
{ to: "/audit", label: "Audit Log", icon: FileText },
{ to: "/data-sources", label: "Data Sources", icon: Database },
{ to: "/system", label: "System", icon: Settings },
];
function SidebarLink({ item }: { item: NavItem }) {
@@ -117,7 +119,15 @@ function SidebarLink({ item }: { item: NavItem }) {
export default function Sidebar() {
const { user } = useAuth();
const isAdmin = user?.role === "admin";
const role = user?.role ?? "";
const isAdmin = role === "admin";
/** Returns true when the current user is allowed to see `item`. */
const canSee = (item: NavItem) => {
if (!item.roles) return true; // no restriction
if (isAdmin) return true; // admin sees everything
return item.roles.includes(role);
};
return (
<aside className="flex h-screen w-60 flex-col border-r border-gray-800 bg-gray-900">
@@ -130,19 +140,19 @@ export default function Sidebar() {
</div>
{/* Main nav */}
<nav className="flex-1 space-y-1 px-3 py-4">
{mainLinks.map((item) => (
<nav className="flex-1 space-y-1 overflow-y-auto px-3 py-4">
{mainLinks.filter(canSee).map((item) => (
<SidebarLink key={item.to + item.label} item={item} />
))}
{/* Admin section */}
{/* System / Administration section — admin only */}
{isAdmin && (
<>
<div className="my-3 border-t border-gray-800" />
<p className="mb-2 px-3 text-[10px] font-semibold uppercase tracking-widest text-gray-600">
Administration
System
</p>
{adminLinks.map((item) => (
{systemLinks.map((item) => (
<SidebarLink key={item.to} item={item} />
))}
</>
@@ -152,7 +162,7 @@ export default function Sidebar() {
{/* Footer */}
<div className="border-t border-gray-800 px-5 py-4">
<p className="truncate text-xs text-gray-500">
{user?.role ?? "—"}
{user?.username ?? "—"} · {role || "—"}
</p>
</div>
</aside>