import { useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { FileText, Download, BarChart3, Shield, Wrench, Loader2, Filter, ChevronDown, } from "lucide-react"; import { getCoverageSummary, getTestResults, getRemediationStatus, type CoverageReport, type TestResultsReport, type RemediationReport, type ReportFilters, } from "../api/reports"; type ReportType = "coverage" | "test-results" | "remediation"; const reportTypes: { id: ReportType; label: string; icon: React.ReactNode; desc: string }[] = [ { id: "coverage", label: "Coverage Summary", icon: , desc: "Technique coverage status across the MITRE ATT&CK framework", }, { id: "test-results", label: "Test Results", icon: , desc: "Detailed test execution results with state and detection breakdowns", }, { id: "remediation", label: "Remediation Status", icon: , desc: "Remediation progress across all tests with assigned steps", }, ]; export default function ReportsPage() { const [selectedType, setSelectedType] = useState("coverage"); const [filters, setFilters] = useState({}); const [showFilters, setShowFilters] = useState(false); const coverageQuery = useQuery({ queryKey: ["reports", "coverage", filters], queryFn: () => getCoverageSummary(filters), enabled: selectedType === "coverage", }); const testResultsQuery = useQuery({ queryKey: ["reports", "test-results", filters], queryFn: () => getTestResults(filters), enabled: selectedType === "test-results", }); const remediationQuery = useQuery({ queryKey: ["reports", "remediation", filters], queryFn: () => getRemediationStatus(filters), enabled: selectedType === "remediation", }); const isLoading = (selectedType === "coverage" && coverageQuery.isLoading) || (selectedType === "test-results" && testResultsQuery.isLoading) || (selectedType === "remediation" && remediationQuery.isLoading); const handleDownloadJson = () => { let data: CoverageReport | TestResultsReport | RemediationReport | undefined; if (selectedType === "coverage") data = coverageQuery.data; if (selectedType === "test-results") data = testResultsQuery.data; if (selectedType === "remediation") data = remediationQuery.data; if (!data) return; const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `aegis_${selectedType}_${new Date().toISOString().slice(0, 10)}.json`; a.click(); URL.revokeObjectURL(url); }; const handleDownloadCsv = () => { const token = localStorage.getItem("token"); const params = new URLSearchParams(); if (filters.tactic) params.set("tactic", filters.tactic); if (filters.platform) params.set("platform", filters.platform); window.open( `/api/v1/reports/coverage-csv?${params.toString()}${token ? `&token=${token}` : ""}`, "_blank", ); }; return (
{/* Header */}

Reports

Generate and download coverage, test results, and remediation reports

{selectedType === "coverage" && ( )}
{/* Report type selector */}
{reportTypes.map((rt) => ( ))}
{/* Filters */}
{showFilters && (
{(selectedType === "coverage" || selectedType === "test-results") && ( <>
setFilters({ ...filters, tactic: e.target.value || undefined })} className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-white" />
setFilters({ ...filters, platform: e.target.value || undefined })} className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-white" />
)} {selectedType === "test-results" && ( <>
setFilters({ ...filters, date_from: e.target.value || undefined })} className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-white" />
setFilters({ ...filters, date_to: e.target.value || undefined })} className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-white" />
)} {selectedType === "remediation" && (
)}
)}
{/* Report content */} {isLoading ? (
) : ( <> {selectedType === "coverage" && coverageQuery.data && ( )} {selectedType === "test-results" && testResultsQuery.data && ( )} {selectedType === "remediation" && remediationQuery.data && ( )} )}
); } // ── Sub-views ────────────────────────────────────────────────────── function CoverageReportView({ report }: { report: CoverageReport }) { const s = report.summary; return (
{/* Summary cards */}
{/* Table */}
{report.techniques.map((t) => ( ))}
MITRE ID Name Tactic Status Tests
{t.mitre_id} {t.name} {t.tactic} {t.total_tests}
); } function TestResultsView({ report }: { report: TestResultsReport }) { const s = report.summary; return (
{/* Detection results breakdown */} {Object.keys(s.by_detection_result).length > 0 && (

Detection Results

{Object.entries(s.by_detection_result).map(([key, val]) => (

{val}

{key.replace(/_/g, " ")}

))}
)} {/* Table */}
{report.tests.map((t) => ( ))}
Name State Platform Detection Red Val. Blue Val.
{t.name} {t.platform || "—"} {t.detection_result?.replace(/_/g, " ") || "—"}
); } function RemediationView({ report }: { report: RemediationReport }) { const s = report.summary; return (
{report.tests.map((t) => ( ))}
Name Test State Remediation Status Steps
{t.name} {t.remediation_steps || "—"}
); } // ── Shared components ────────────────────────────────────────────── function StatCard({ label, value, color = "text-white", }: { label: string; value: number | string; color?: string; }) { return (

{label}

{value}

); } const statusColors: Record = { validated: "bg-green-500/10 text-green-400 border-green-500/30", partial: "bg-yellow-500/10 text-yellow-400 border-yellow-500/30", in_progress: "bg-blue-500/10 text-blue-400 border-blue-500/30", not_covered: "bg-red-500/10 text-red-400 border-red-500/30", not_evaluated: "bg-gray-500/10 text-gray-400 border-gray-500/30", draft: "bg-gray-500/10 text-gray-400 border-gray-500/30", red_executing: "bg-orange-500/10 text-orange-400 border-orange-500/30", blue_evaluating: "bg-indigo-500/10 text-indigo-400 border-indigo-500/30", in_review: "bg-yellow-500/10 text-yellow-400 border-yellow-500/30", rejected: "bg-red-500/10 text-red-400 border-red-500/30", }; function StatusBadge({ status }: { status: string }) { return ( {status.replace(/_/g, " ")} ); } function ValidationBadge({ status }: { status: string | null }) { if (!status) return ; const colors: Record = { approved: "text-green-400", rejected: "text-red-400", pending: "text-yellow-400", }; return {status}; } function RemediationBadge({ status }: { status: string | null }) { if (!status) return ; const colors: Record = { pending: "bg-yellow-500/10 text-yellow-400 border-yellow-500/30", in_progress: "bg-blue-500/10 text-blue-400 border-blue-500/30", completed: "bg-green-500/10 text-green-400 border-green-500/30", not_applicable: "bg-gray-500/10 text-gray-400 border-gray-500/30", }; return ( {status.replace(/_/g, " ")} ); }