Add DAST, graph modules, toast notifications, and dashboard enhancements
Add DAST scanning and code knowledge graph features across the stack: - compliance-dast and compliance-graph workspace crates - Agent API handlers and routes for DAST targets/scans and graph builds - Core models and traits for DAST and graph domains - Dashboard pages for DAST targets/findings/overview and graph explorer/impact - Toast notification system with auto-dismiss for async action feedback - Button click animations and disabled states for better UX Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
79
compliance-dashboard/src/pages/dast_findings.rs
Normal file
79
compliance-dashboard/src/pages/dast_findings.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::app::Route;
|
||||
use crate::components::page_header::PageHeader;
|
||||
use crate::components::severity_badge::SeverityBadge;
|
||||
use crate::infrastructure::dast::fetch_dast_findings;
|
||||
|
||||
#[component]
|
||||
pub fn DastFindingsPage() -> Element {
|
||||
let findings = use_resource(|| async { fetch_dast_findings().await.ok() });
|
||||
|
||||
rsx! {
|
||||
PageHeader {
|
||||
title: "DAST Findings",
|
||||
description: "Vulnerabilities discovered through dynamic application security testing",
|
||||
}
|
||||
|
||||
div { class: "card",
|
||||
match &*findings.read() {
|
||||
Some(Some(data)) => {
|
||||
let finding_list = &data.data;
|
||||
if finding_list.is_empty() {
|
||||
rsx! { p { "No DAST findings yet. Run a scan to discover vulnerabilities." } }
|
||||
} else {
|
||||
rsx! {
|
||||
table { class: "table",
|
||||
thead {
|
||||
tr {
|
||||
th { "Severity" }
|
||||
th { "Type" }
|
||||
th { "Title" }
|
||||
th { "Endpoint" }
|
||||
th { "Method" }
|
||||
th { "Exploitable" }
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
for finding in finding_list {
|
||||
{
|
||||
let id = finding.get("_id").and_then(|v| v.get("$oid")).and_then(|v| v.as_str()).unwrap_or("").to_string();
|
||||
let severity = finding.get("severity").and_then(|v| v.as_str()).unwrap_or("info").to_string();
|
||||
rsx! {
|
||||
tr {
|
||||
td { SeverityBadge { severity: severity } }
|
||||
td {
|
||||
span { class: "badge",
|
||||
"{finding.get(\"vuln_type\").and_then(|v| v.as_str()).unwrap_or(\"-\")}"
|
||||
}
|
||||
}
|
||||
td {
|
||||
Link {
|
||||
to: Route::DastFindingDetailPage { id: id },
|
||||
"{finding.get(\"title\").and_then(|v| v.as_str()).unwrap_or(\"-\")}"
|
||||
}
|
||||
}
|
||||
td { code { class: "text-sm", "{finding.get(\"endpoint\").and_then(|v| v.as_str()).unwrap_or(\"-\")}" } }
|
||||
td { "{finding.get(\"method\").and_then(|v| v.as_str()).unwrap_or(\"-\")}" }
|
||||
td {
|
||||
if finding.get("exploitable").and_then(|v| v.as_bool()).unwrap_or(false) {
|
||||
span { class: "badge badge-danger", "Confirmed" }
|
||||
} else {
|
||||
span { class: "badge", "Unconfirmed" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(None) => rsx! { p { "Failed to load findings." } },
|
||||
None => rsx! { p { "Loading..." } },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user