Files
compliance-scanner-agent/compliance-dashboard/src/components/sidebar.rs
Sharang Parnerkar a529e9af0c
All checks were successful
CI / Check (push) Successful in 11m4s
CI / Detect Changes (push) Successful in 2s
CI / Deploy Agent (push) Has been skipped
CI / Deploy Dashboard (push) Successful in 2s
CI / Deploy Docs (push) Has been skipped
CI / Deploy MCP (push) Has been skipped
ci: consolidate CI into single job; fix sidebar footer (#14)
2026-03-13 09:44:32 +00:00

167 lines
6.1 KiB
Rust

use compliance_core::models::auth::AuthInfo;
use dioxus::prelude::*;
use dioxus_free_icons::icons::bs_icons::*;
use dioxus_free_icons::Icon;
use crate::app::Route;
struct NavItem {
label: &'static str,
route: Route,
icon: Element,
}
#[component]
pub fn Sidebar() -> Element {
let current_route = use_route::<Route>();
let mut collapsed = use_signal(|| true);
let nav_items = [
NavItem {
label: "Overview",
route: Route::OverviewPage {},
icon: rsx! { Icon { icon: BsSpeedometer2, width: 18, height: 18 } },
},
NavItem {
label: "Repositories",
route: Route::RepositoriesPage {},
icon: rsx! { Icon { icon: BsFolder2Open, width: 18, height: 18 } },
},
NavItem {
label: "Findings",
route: Route::FindingsPage {},
icon: rsx! { Icon { icon: BsShieldExclamation, width: 18, height: 18 } },
},
NavItem {
label: "SBOM",
route: Route::SbomPage {},
icon: rsx! { Icon { icon: BsBoxSeam, width: 18, height: 18 } },
},
NavItem {
label: "Issues",
route: Route::IssuesPage {},
icon: rsx! { Icon { icon: BsListTask, width: 18, height: 18 } },
},
NavItem {
label: "DAST",
route: Route::DastOverviewPage {},
icon: rsx! { Icon { icon: BsBug, width: 18, height: 18 } },
},
NavItem {
label: "Pentest",
route: Route::PentestDashboardPage {},
icon: rsx! { Icon { icon: BsLightningCharge, width: 18, height: 18 } },
},
NavItem {
label: "Settings",
route: Route::SettingsPage {},
icon: rsx! { Icon { icon: BsGear, width: 18, height: 18 } },
},
];
let docs_url = option_env!("DOCS_URL").unwrap_or("/docs");
let sidebar_class = if collapsed() {
"sidebar collapsed"
} else {
"sidebar"
};
rsx! {
nav { class: "{sidebar_class}",
div { class: "sidebar-header",
Icon { icon: BsShieldCheck, width: 24, height: 24 }
if !collapsed() {
h1 { "Compliance Scanner" }
}
}
div { class: "sidebar-nav",
for item in nav_items {
{
let is_active = match (&current_route, &item.route) {
(Route::FindingDetailPage { .. }, Route::FindingsPage {}) => true,
(Route::DastTargetsPage {}, Route::DastOverviewPage {}) => true,
(Route::DastFindingsPage {}, Route::DastOverviewPage {}) => true,
(Route::DastFindingDetailPage { .. }, Route::DastOverviewPage {}) => true,
(Route::PentestSessionPage { .. }, Route::PentestDashboardPage {}) => true,
(a, b) => a == b,
};
let class = if is_active { "nav-item active" } else { "nav-item" };
rsx! {
Link {
to: item.route.clone(),
class: class,
{item.icon}
if !collapsed() {
span { "{item.label}" }
}
}
}
}
}
}
a {
href: "{docs_url}",
target: "_blank",
class: "nav-item",
Icon { icon: BsBook, width: 18, height: 18 }
if !collapsed() {
span { "Docs" }
}
}
// Spacer pushes footer to the bottom
div { class: "sidebar-spacer" }
button {
class: "sidebar-toggle",
onclick: move |_| collapsed.set(!collapsed()),
if collapsed() {
Icon { icon: BsChevronRight, width: 14, height: 14 }
} else {
Icon { icon: BsChevronLeft, width: 14, height: 14 }
}
}
{
let auth_info = use_context::<Signal<AuthInfo>>();
let info = auth_info();
let initials = info.name.chars().next().unwrap_or('U').to_uppercase().to_string();
rsx! {
div { class: "sidebar-user",
div { class: "user-avatar",
if info.avatar_url.is_empty() {
span { class: "avatar-initials", "{initials}" }
} else {
img { src: "{info.avatar_url}", alt: "avatar", class: "avatar-img" }
}
}
if !collapsed() {
div { class: "user-info",
span { class: "user-name", "{info.name}" }
a {
href: "/logout",
class: "logout-link",
"Sign out"
}
}
}
if collapsed() {
a {
href: "/logout",
class: "logout-btn-icon",
title: "Sign out",
Icon { icon: BsBoxArrowRight, width: 14, height: 14 }
}
}
}
if !collapsed() {
div { class: "sidebar-legal",
a { href: "/privacy", "Privacy" }
span { class: "legal-dot", "·" }
a { href: "/impressum", "Impressum" }
}
}
}
}
}
}
}