167 lines
6.1 KiB
Rust
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 (¤t_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" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|