@@ -241,3 +241,135 @@ export function generateVersionChangeChartData(
241241 } ) ;
242242}
243243
244+ export function generateVulnerabilityFixBySeverityChartData (
245+ results : Record < string , Record < string , number > > ,
246+ options : MetricOptions
247+ ) : { data : any [ ] ; layout : any } [ ] {
248+ const months = Object . keys ( results ) . sort ( ) ;
249+
250+ const formattedMonths = months . map ( month => {
251+ const [ year , monthPart ] = month . split ( '-' ) ;
252+ const date = new Date ( `${ year } -${ monthPart } -01` ) ;
253+ return date . toLocaleString ( 'en-US' , { month : 'short' , year : 'numeric' } ) ; // e.g., "May 2025"
254+ } ) ;
255+
256+ const allSeverities = Array . from ( new Set ( months . flatMap ( month => Object . keys ( results [ month ] ) ) ) ) ;
257+
258+ return options . chartType . map ( type => {
259+ const isLine = type === 'line' ;
260+ const isStacked = type === 'stacked' ;
261+ const isArea = type === 'stacked-area' ;
262+
263+ const traceType = isLine || isArea ? 'scatter' : 'bar' ;
264+ const commonTraceProps = {
265+ type : traceType ,
266+ mode : isLine ? 'lines+markers' : undefined ,
267+ fill : isArea ? 'tonexty' : undefined ,
268+ stackgroup : isArea ? 'one' : undefined
269+ } ;
270+
271+ const traces = allSeverities . map ( severity => ( {
272+ x : formattedMonths ,
273+ y : months . map ( month => results [ month ] ?. [ severity ] || 0 ) ,
274+ name : severity ,
275+ ...commonTraceProps
276+ } ) ) ;
277+
278+ const layout = {
279+ title : `🛡️ Fixed Vulnerabilities by Severity Over Time (${ type } )` ,
280+ barmode : isStacked ? 'stack' : ( traceType === 'bar' ? 'group' : undefined ) ,
281+ xaxis : {
282+ title : 'Month' ,
283+ tickangle : - 45 ,
284+ automargin : true
285+ } ,
286+ yaxis : {
287+ title : 'Fix Count'
288+ } ,
289+ margin : {
290+ l : 50 ,
291+ r : 30 ,
292+ t : 60 ,
293+ b : 120
294+ }
295+ } ;
296+
297+ return {
298+ data : traces ,
299+ layout
300+ } ;
301+ } ) ;
302+ }
303+
304+ export function generateVulnerabilityFixTimelinessChartData (
305+ results : Record < string , Record < string , { fixedInTime : number ; fixedLate : number } > > ,
306+ options : MetricOptions
307+ ) : { data : any [ ] ; layout : any } [ ] {
308+ const months = Object . keys ( results ) . sort ( ) ;
309+
310+ const formattedMonths = months . map ( month => {
311+ const [ year , monthPart ] = month . split ( '-' ) ;
312+ return new Date ( `${ year } -${ monthPart } -01` ) . toLocaleString ( 'en-US' , {
313+ month : 'short' ,
314+ year : 'numeric'
315+ } ) ;
316+ } ) ;
317+
318+ const allSeverities = Array . from (
319+ new Set ( months . flatMap ( m => Object . keys ( results [ m ] ) ) )
320+ ) ;
321+
322+ return options . chartType . map ( type => {
323+ const traceType = type === 'line' || type === 'stacked-area' ? 'scatter' : 'bar' ;
324+ const isStacked = type === 'stacked' ;
325+ const isArea = type === 'stacked-area' ;
326+
327+ const commonProps = {
328+ type : traceType ,
329+ mode : traceType === 'scatter' ? 'lines+markers' : undefined ,
330+ fill : isArea ? 'tonexty' : undefined ,
331+ stackgroup : isArea ? 'one' : undefined
332+ } ;
333+
334+ const traces = allSeverities . flatMap ( severity => {
335+ const fixedInTime = {
336+ x : formattedMonths ,
337+ y : months . map ( m => results [ m ] ?. [ severity ] ?. fixedInTime || 0 ) ,
338+ name : `${ severity } - Fixed In Time` ,
339+ ...commonProps
340+ } ;
341+
342+ const fixedLate = {
343+ x : formattedMonths ,
344+ y : months . map ( m => results [ m ] ?. [ severity ] ?. fixedLate || 0 ) ,
345+ name : `${ severity } - Fixed Late` ,
346+ ...commonProps
347+ } ;
348+
349+ return [ fixedInTime , fixedLate ] ;
350+ } ) ;
351+
352+ const layout = {
353+ title : `⏱️ Timeliness of Vulnerability Fixes per Month according to ISO (${ type } )` ,
354+ barmode : isStacked ? 'stack' : ( traceType === 'bar' ? 'group' : undefined ) ,
355+ xaxis : {
356+ title : 'Month' ,
357+ tickangle : - 45 ,
358+ automargin : true
359+ } ,
360+ yaxis : {
361+ title : 'Fix Count'
362+ } ,
363+ margin : {
364+ l : 50 ,
365+ r : 30 ,
366+ t : 60 ,
367+ b : 120
368+ }
369+ } ;
370+
371+ return { data : traces , layout } ;
372+ } ) ;
373+ }
374+
375+
0 commit comments