traceability

This commit is contained in:
2026-01-25 14:22:22 +01:00
commit f965340abe
109 changed files with 25321 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
import { useState } from "react";
import {
FileText,
Search,
GitBranch,
CheckSquare,
AlertTriangle,
Target,
Layers,
Bug,
TestTube,
Calendar,
Milestone,
FolderKanban,
BookOpen,
LayoutDashboard,
ChevronDown,
ChevronRight,
} from "lucide-react";
import { NavLink } from "@/components/NavLink";
import { useLocation } from "react-router-dom";
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
useSidebar,
} from "@/components/ui/sidebar";
import { cn } from "@/lib/utils";
const mainItems = [
{ title: "Dashboard", url: "/", icon: LayoutDashboard },
{ title: "Traceability Matrix", url: "/matrix", icon: GitBranch },
{ title: "Documentation", url: "/documentation", icon: BookOpen },
{ title: "Gap Analysis", url: "/analysis", icon: Search },
];
const almItems = [
{ title: "Features", url: "/alm/feature", icon: Target, type: "feature" },
{ title: "Requirements", url: "/alm/requirements", icon: CheckSquare, type: "requirements" },
{ title: "SW Requirements", url: "/alm/swreq", icon: FileText, type: "swreq" },
{ title: "Test Cases", url: "/alm/test-case", icon: TestTube, type: "test case" },
{ title: "Epics", url: "/alm/epic", icon: Layers, type: "epic" },
{ title: "User Stories", url: "/alm/user-story", icon: FolderKanban, type: "user story" },
{ title: "Tasks", url: "/alm/task", icon: CheckSquare, type: "task" },
{ title: "Bugs", url: "/alm/bug", icon: Bug, type: "bug" },
{ title: "Risks", url: "/alm/risk", icon: AlertTriangle, type: "risk" },
{ title: "Milestones", url: "/alm/milestone", icon: Milestone, type: "milestone" },
{ title: "Phases", url: "/alm/phase", icon: Calendar, type: "phase" },
];
export function AppSidebar() {
const { state } = useSidebar();
const collapsed = state === "collapsed";
const location = useLocation();
const currentPath = location.pathname;
const [almExpanded, setAlmExpanded] = useState(
almItems.some((item) => currentPath.startsWith(item.url))
);
return (
<Sidebar collapsible="icon" className="border-r border-sidebar-border bg-sidebar-background">
<SidebarContent className="pt-4">
{/* Logo/Header */}
<div className="px-4 pb-4 border-b border-sidebar-border mb-4">
<div className="flex items-center gap-3">
<img
src="/images/nabd-logo.png"
alt="NABD Solutions"
className={cn(
"transition-all duration-200",
collapsed ? "h-8 w-8 object-contain" : "h-10"
)}
/>
{!collapsed && (
<div className="flex flex-col">
<span className="font-bold text-base text-sidebar-foreground">Traceability</span>
<span className="text-xs text-sidebar-foreground/60">ASF Sensor Hub</span>
</div>
)}
</div>
</div>
{/* Main Navigation */}
<SidebarGroup>
<SidebarGroupLabel className="text-sidebar-foreground/60">Navigation</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{mainItems.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild>
<NavLink
to={item.url}
end={item.url === "/"}
className={cn(
"flex items-center gap-2 px-2 py-1.5 rounded-md transition-colors",
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
"text-sidebar-foreground"
)}
activeClassName="bg-sidebar-accent text-sidebar-primary font-medium"
>
<item.icon className="h-4 w-4 shrink-0" />
{!collapsed && <span>{item.title}</span>}
</NavLink>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
{/* ALM Items */}
<SidebarGroup>
<SidebarGroupLabel
className="cursor-pointer flex items-center justify-between text-sidebar-foreground/60 hover:text-sidebar-foreground"
onClick={() => setAlmExpanded(!almExpanded)}
>
<span>ALM Traceability</span>
{!collapsed && (
almExpanded ? (
<ChevronDown className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
)
)}
</SidebarGroupLabel>
{(almExpanded || collapsed) && (
<SidebarGroupContent>
<SidebarMenu>
{almItems.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild>
<NavLink
to={item.url}
className={cn(
"flex items-center gap-2 px-2 py-1.5 rounded-md transition-colors",
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
"text-sidebar-foreground"
)}
activeClassName="bg-sidebar-accent text-sidebar-primary font-medium"
>
<item.icon className="h-4 w-4 shrink-0" />
{!collapsed && <span>{item.title}</span>}
</NavLink>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
)}
</SidebarGroup>
</SidebarContent>
</Sidebar>
);
}