1- import React from 'react' ;
2- import { ChartBarIcon , ArrowPathIcon , ExclamationCircleIcon } from '@heroicons/react/24/outline' ;
1+ import React , { useState } from 'react' ;
2+ import { ChartBarIcon , ArrowPathIcon , ExclamationCircleIcon , FunnelIcon } from '@heroicons/react/24/outline' ;
33import { Bar } from 'react-chartjs-2' ;
44import { useRisks } from '../../hooks/UseRisk' ;
55import { createChartData , createChartOptions , getSeverityColor } from '../../utils/chartConfig' ;
66import './RiskDashboard.css' ;
77
88const RiskDashboardPage = ( ) => {
99 const { risks, details, loading, error, isRefreshing, refreshRisks } = useRisks ( ) ;
10+ const [ selectedScanType , setSelectedScanType ] = useState ( 'all' ) ;
11+
12+ // Get unique scan types from details
13+ const scanTypes = [ 'all' , ...new Set ( details . map ( d => d . scan_type ) . filter ( Boolean ) ) ] ;
14+
15+ // Filter details based on selected scan type
16+ const filteredDetails = selectedScanType === 'all'
17+ ? details
18+ : details . filter ( d => d . scan_type === selectedScanType ) ;
19+
20+ // Aggregate risks by severity for filtered data
21+ const getFilteredRisks = ( ) => {
22+ if ( selectedScanType === 'all' ) return risks ;
23+
24+ const severityCounts = { ERROR : 0 , WARNING : 0 , INFO : 0 } ;
25+
26+ filteredDetails . forEach ( detail => {
27+ const severity = ( detail . severity || 'INFO' ) . toUpperCase ( ) ;
28+ if ( severity in severityCounts ) {
29+ severityCounts [ severity ] += 1 ;
30+ } else {
31+ severityCounts . INFO += 1 ;
32+ }
33+ } ) ;
34+
35+ return [
36+ { name : "Critical (ERROR)" , level : severityCounts . ERROR * 10 } ,
37+ { name : "High (WARNING)" , level : severityCounts . WARNING * 5 } ,
38+ { name : "Low (INFO)" , level : severityCounts . INFO * 2 }
39+ ] ;
40+ } ;
1041
1142 // Loading Spinner Component
1243 const LoadingSpinner = ( { message = 'Loading...' } ) => (
@@ -34,10 +65,39 @@ const RiskDashboardPage = () => {
3465 </ div >
3566 ) ;
3667
68+ // Scan Type Filter Component
69+ const ScanTypeFilter = ( ) => (
70+ < div className = "scan-type-filter" >
71+ < div className = "scan-type-filter__label" >
72+ < FunnelIcon className = "scan-type-filter__icon" />
73+ < span > Filter by Scan Type:</ span >
74+ </ div >
75+ < div className = "scan-type-filter__buttons" >
76+ { scanTypes . map ( type => (
77+ < button
78+ key = { type }
79+ className = { `scan-type-filter__button ${
80+ selectedScanType === type ? 'scan-type-filter__button--active' : ''
81+ } `}
82+ onClick = { ( ) => setSelectedScanType ( type ) }
83+ >
84+ { type === 'all' ? 'All Scans' : type . charAt ( 0 ) . toUpperCase ( ) + type . slice ( 1 ) }
85+ { type !== 'all' && (
86+ < span className = "scan-type-filter__count" >
87+ ({ details . filter ( d => d . scan_type === type ) . length } )
88+ </ span >
89+ ) }
90+ </ button >
91+ ) ) }
92+ </ div >
93+ </ div >
94+ ) ;
95+
3796 // Risk Chart Section
3897 const RiskChart = ( { risks } ) => {
39- const chartData = createChartData ( risks ) ;
40- const chartOptions = createChartOptions ( risks ) ;
98+ const filteredRisks = getFilteredRisks ( ) ;
99+ const chartData = createChartData ( filteredRisks ) ;
100+ const chartOptions = createChartOptions ( filteredRisks ) ;
41101
42102 return (
43103 < div className = "risk-chart" >
@@ -58,7 +118,7 @@ const RiskDashboardPage = () => {
58118 < div className = "vulnerability-table" >
59119 < h3 className = "vulnerability-table__title" > Vulnerability Details</ h3 >
60120 < div className = "vulnerability-table__empty" >
61- < p > No vulnerabilities found</ p >
121+ < p > No vulnerabilities found{ selectedScanType !== 'all' ? ` for ${ selectedScanType } ` : '' } </ p >
62122 </ div >
63123 </ div >
64124 ) ;
@@ -67,7 +127,7 @@ const RiskDashboardPage = () => {
67127 return (
68128 < div className = "vulnerability-table" >
69129 < h3 className = "vulnerability-table__title" >
70- Vulnerability Details ({ details . length } )
130+ Vulnerabilities Details ({ details . length } )
71131 </ h3 >
72132
73133 { /* Desktop Table */ }
@@ -76,6 +136,7 @@ const RiskDashboardPage = () => {
76136 < table className = "vulnerability-table__table" >
77137 < thead >
78138 < tr >
139+ < th > Scan Type</ th >
79140 < th > Severity</ th >
80141 < th > Problem</ th >
81142 < th > Suggestion</ th >
@@ -84,6 +145,11 @@ const RiskDashboardPage = () => {
84145 < tbody >
85146 { details . map ( ( detail , index ) => (
86147 < tr key = { index } >
148+ < td >
149+ < span className = "vulnerability-table__scan-type" >
150+ { detail . scan_type || 'N/A' }
151+ </ span >
152+ </ td >
87153 < td >
88154 < span
89155 className = "vulnerability-table__severity"
@@ -111,6 +177,9 @@ const RiskDashboardPage = () => {
111177 { details . map ( ( detail , index ) => (
112178 < div key = { index } className = "vulnerability-card" >
113179 < div className = "vulnerability-card__header" >
180+ < span className = "vulnerability-card__scan-type" >
181+ { detail . scan_type || 'N/A' }
182+ </ span >
114183 < span
115184 className = "vulnerability-card__severity"
116185 style = { {
@@ -150,8 +219,9 @@ const RiskDashboardPage = () => {
150219
151220 return (
152221 < >
222+ < ScanTypeFilter />
153223 < RiskChart risks = { risks } />
154- < VulnerabilityTable details = { details } />
224+ < VulnerabilityTable details = { filteredDetails } />
155225 </ >
156226 ) ;
157227 } ;
0 commit comments