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:
107
compliance-dashboard/src/pages/dast_overview.rs
Normal file
107
compliance-dashboard/src/pages/dast_overview.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::app::Route;
|
||||
use crate::components::page_header::PageHeader;
|
||||
use crate::infrastructure::dast::{fetch_dast_findings, fetch_dast_scan_runs};
|
||||
|
||||
#[component]
|
||||
pub fn DastOverviewPage() -> Element {
|
||||
let scan_runs = use_resource(|| async { fetch_dast_scan_runs().await.ok() });
|
||||
let findings = use_resource(|| async { fetch_dast_findings().await.ok() });
|
||||
|
||||
rsx! {
|
||||
PageHeader {
|
||||
title: "DAST Overview",
|
||||
description: "Dynamic Application Security Testing — scan running applications for vulnerabilities",
|
||||
}
|
||||
|
||||
div { class: "grid grid-cols-3 gap-4 mb-6",
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value",
|
||||
match &*scan_runs.read() {
|
||||
Some(Some(data)) => {
|
||||
let count = data.total.unwrap_or(0);
|
||||
rsx! { "{count}" }
|
||||
},
|
||||
_ => rsx! { "—" },
|
||||
}
|
||||
}
|
||||
div { class: "stat-label", "Total Scans" }
|
||||
}
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value",
|
||||
match &*findings.read() {
|
||||
Some(Some(data)) => {
|
||||
let count = data.total.unwrap_or(0);
|
||||
rsx! { "{count}" }
|
||||
},
|
||||
_ => rsx! { "—" },
|
||||
}
|
||||
}
|
||||
div { class: "stat-label", "DAST Findings" }
|
||||
}
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value", "—" }
|
||||
div { class: "stat-label", "Active Targets" }
|
||||
}
|
||||
}
|
||||
|
||||
div { class: "flex gap-4 mb-4",
|
||||
Link {
|
||||
to: Route::DastTargetsPage {},
|
||||
class: "btn btn-primary",
|
||||
"Manage Targets"
|
||||
}
|
||||
Link {
|
||||
to: Route::DastFindingsPage {},
|
||||
class: "btn btn-secondary",
|
||||
"View Findings"
|
||||
}
|
||||
}
|
||||
|
||||
div { class: "card",
|
||||
h3 { "Recent Scan Runs" }
|
||||
match &*scan_runs.read() {
|
||||
Some(Some(data)) => {
|
||||
let runs = &data.data;
|
||||
if runs.is_empty() {
|
||||
rsx! { p { "No scan runs yet." } }
|
||||
} else {
|
||||
rsx! {
|
||||
table { class: "table",
|
||||
thead {
|
||||
tr {
|
||||
th { "Target" }
|
||||
th { "Status" }
|
||||
th { "Phase" }
|
||||
th { "Findings" }
|
||||
th { "Exploitable" }
|
||||
th { "Started" }
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
for run in runs {
|
||||
tr {
|
||||
td { "{run.get(\"target_id\").and_then(|v| v.as_str()).unwrap_or(\"-\")}" }
|
||||
td {
|
||||
span { class: "badge",
|
||||
"{run.get(\"status\").and_then(|v| v.as_str()).unwrap_or(\"unknown\")}"
|
||||
}
|
||||
}
|
||||
td { "{run.get(\"current_phase\").and_then(|v| v.as_str()).unwrap_or(\"-\")}" }
|
||||
td { "{run.get(\"findings_count\").and_then(|v| v.as_u64()).unwrap_or(0)}" }
|
||||
td { "{run.get(\"exploitable_count\").and_then(|v| v.as_u64()).unwrap_or(0)}" }
|
||||
td { "{run.get(\"started_at\").and_then(|v| v.as_str()).unwrap_or(\"-\")}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(None) => rsx! { p { "Failed to load scan runs." } },
|
||||
None => rsx! { p { "Loading..." } },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user