161 lines
5.8 KiB
TypeScript
161 lines
5.8 KiB
TypeScript
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>
|
|
);
|
|
}
|