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