d49c4aa009
T-119: TestCatalogPage with search, filters (source/platform/severity), template cards grid, and pagination T-120: TestFromTemplateForm modal with pre-filled fields from template, required field validation, and redirect on creation T-121: Integrate Available Test Templates section in TechniqueDetailPage with Run This Test buttons; fix missing testStateBadgeColors for new states Also: add backend entrypoint.sh for automatic Alembic migrations + seed on container startup, add curl to Dockerfile for healthcheck
71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
import { NavLink } from "react-router-dom";
|
|
import {
|
|
LayoutDashboard,
|
|
Shield,
|
|
FlaskConical,
|
|
BookOpen,
|
|
Settings,
|
|
Users,
|
|
FileText,
|
|
} from "lucide-react";
|
|
import { useAuth } from "../context/AuthContext";
|
|
|
|
const baseLinks = [
|
|
{ to: "/dashboard", label: "Dashboard", icon: LayoutDashboard },
|
|
{ to: "/techniques", label: "Techniques", icon: Shield },
|
|
{ to: "/tests", label: "Tests", icon: FlaskConical },
|
|
{ to: "/test-catalog", label: "Test Catalog", icon: BookOpen },
|
|
];
|
|
|
|
const adminLinks = [
|
|
{ to: "/users", label: "Users", icon: Users },
|
|
{ to: "/audit", label: "Audit Log", icon: FileText },
|
|
{ to: "/system", label: "System", icon: Settings },
|
|
];
|
|
|
|
export default function Sidebar() {
|
|
const { user } = useAuth();
|
|
const isAdmin = user?.role === "admin";
|
|
|
|
const links = isAdmin ? [...baseLinks, ...adminLinks] : baseLinks;
|
|
|
|
return (
|
|
<aside className="flex h-screen w-60 flex-col border-r border-gray-800 bg-gray-900">
|
|
{/* Logo */}
|
|
<div className="flex h-16 items-center gap-2 px-5">
|
|
<Shield className="h-7 w-7 text-cyan-400" />
|
|
<span className="text-lg font-bold tracking-wide text-white">
|
|
Aegis
|
|
</span>
|
|
</div>
|
|
|
|
{/* Nav links */}
|
|
<nav className="flex-1 space-y-1 px-3 py-4">
|
|
{links.map(({ to, label, icon: Icon }) => (
|
|
<NavLink
|
|
key={to}
|
|
to={to}
|
|
className={({ isActive }) =>
|
|
`flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors ${
|
|
isActive
|
|
? "bg-cyan-500/10 text-cyan-400"
|
|
: "text-gray-400 hover:bg-gray-800 hover:text-gray-200"
|
|
}`
|
|
}
|
|
>
|
|
<Icon className="h-5 w-5" />
|
|
{label}
|
|
</NavLink>
|
|
))}
|
|
</nav>
|
|
|
|
{/* Footer */}
|
|
<div className="border-t border-gray-800 px-5 py-4">
|
|
<p className="truncate text-xs text-gray-500">
|
|
{user?.role ?? "—"}
|
|
</p>
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|