Files
compliance-scanner-agent/compliance-dashboard/src/pages/dast_findings.rs
Sharang Parnerkar cea8f59e10 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>
2026-03-04 13:53:50 +01:00

80 lines
4.1 KiB
Rust

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..." } },
}
}
}
}