Initial commit: Compliance Scanner Agent
Autonomous security and compliance scanning agent for git repositories. Features: SAST (Semgrep), SBOM (Syft), CVE monitoring (OSV.dev/NVD), GDPR/OAuth pattern detection, LLM triage, issue creation (GitHub/GitLab/Jira), PR reviews, and Dioxus fullstack dashboard. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
104
compliance-dashboard/src/pages/overview.rs
Normal file
104
compliance-dashboard/src/pages/overview.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::components::page_header::PageHeader;
|
||||
use crate::components::stat_card::StatCard;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
use crate::infrastructure::stats::fetch_overview_stats;
|
||||
|
||||
#[component]
|
||||
pub fn OverviewPage() -> Element {
|
||||
let stats = use_resource(move || async move {
|
||||
#[cfg(feature = "server")]
|
||||
{
|
||||
fetch_overview_stats().await.ok()
|
||||
}
|
||||
#[cfg(not(feature = "server"))]
|
||||
{
|
||||
crate::infrastructure::stats::fetch_overview_stats().await.ok()
|
||||
}
|
||||
});
|
||||
|
||||
rsx! {
|
||||
PageHeader {
|
||||
title: "Overview",
|
||||
description: "Security and compliance scanning dashboard",
|
||||
}
|
||||
|
||||
match &*stats.read() {
|
||||
Some(Some(s)) => rsx! {
|
||||
div { class: "stat-cards",
|
||||
StatCard { label: "Repositories", value: s.total_repositories.to_string() }
|
||||
StatCard { label: "Total Findings", value: s.total_findings.to_string() }
|
||||
StatCard {
|
||||
label: "Critical",
|
||||
value: s.critical_findings.to_string(),
|
||||
color: "var(--danger)",
|
||||
}
|
||||
StatCard {
|
||||
label: "High",
|
||||
value: s.high_findings.to_string(),
|
||||
color: "#f97316",
|
||||
}
|
||||
StatCard {
|
||||
label: "Medium",
|
||||
value: s.medium_findings.to_string(),
|
||||
color: "var(--warning)",
|
||||
}
|
||||
StatCard {
|
||||
label: "Low",
|
||||
value: s.low_findings.to_string(),
|
||||
color: "var(--success)",
|
||||
}
|
||||
StatCard { label: "Dependencies", value: s.total_sbom_entries.to_string() }
|
||||
StatCard { label: "CVE Alerts", value: s.total_cve_alerts.to_string() }
|
||||
StatCard { label: "Tracker Issues", value: s.total_issues.to_string() }
|
||||
}
|
||||
|
||||
div { class: "card",
|
||||
div { class: "card-header", "Severity Distribution" }
|
||||
div {
|
||||
style: "display: flex; gap: 8px; align-items: flex-end; height: 200px; padding: 16px;",
|
||||
SeverityBar { label: "Critical", count: s.critical_findings, max: s.total_findings, color: "var(--danger)" }
|
||||
SeverityBar { label: "High", count: s.high_findings, max: s.total_findings, color: "#f97316" }
|
||||
SeverityBar { label: "Medium", count: s.medium_findings, max: s.total_findings, color: "var(--warning)" }
|
||||
SeverityBar { label: "Low", count: s.low_findings, max: s.total_findings, color: "var(--success)" }
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(None) => rsx! {
|
||||
div { class: "card",
|
||||
p { style: "color: var(--text-secondary);",
|
||||
"Unable to load stats. Make sure the agent API is running."
|
||||
}
|
||||
}
|
||||
},
|
||||
None => rsx! {
|
||||
div { class: "loading", "Loading overview..." }
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn SeverityBar(label: String, count: u64, max: u64, color: String) -> Element {
|
||||
let height_pct = if max > 0 { (count as f64 / max as f64) * 100.0 } else { 0.0 };
|
||||
let height = format!("{}%", height_pct.max(2.0));
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
style: "flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;",
|
||||
div {
|
||||
style: "font-size: 14px; font-weight: 600;",
|
||||
"{count}"
|
||||
}
|
||||
div {
|
||||
style: "width: 100%; background: {color}; border-radius: 4px 4px 0 0; height: {height}; min-height: 4px; transition: height 0.3s;",
|
||||
}
|
||||
div {
|
||||
style: "font-size: 11px; color: var(--text-secondary);",
|
||||
"{label}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user