github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/ui/dashboard/src/components/dashboards/check/common/Benchmark.ts (about) 1 import Control from "./Control"; 2 import merge from "lodash/merge"; 3 import padStart from "lodash/padStart"; 4 import { 5 AddControlResultsAction, 6 CheckControlRun, 7 CheckDynamicColsMap, 8 CheckNode, 9 CheckNodeStatus, 10 CheckNodeType, 11 CheckResult, 12 CheckSeveritySummary, 13 CheckSummary, 14 } from "./index"; 15 import { DashboardLayoutNode, PanelsMap } from "../../../../types"; 16 import { 17 LeafNodeData, 18 LeafNodeDataColumn, 19 LeafNodeDataRow, 20 } from "../../common"; 21 22 class Benchmark implements CheckNode { 23 private readonly _sortIndex: string; 24 private readonly _name: string; 25 private readonly _title: string; 26 private readonly _description?: string; 27 private readonly _benchmarks: Benchmark[]; 28 private readonly _controls: Control[]; 29 private readonly _add_control_results: AddControlResultsAction; 30 private readonly _all_control_results: CheckResult[]; 31 32 constructor( 33 sortIndex: string, 34 name: string, 35 title: string | undefined, 36 description: string | undefined, 37 benchmarks: DashboardLayoutNode[] | undefined, 38 controls: DashboardLayoutNode[] | undefined, 39 panelsMap: PanelsMap, 40 trunk: Benchmark[], 41 add_control_results?: AddControlResultsAction 42 ) { 43 this._sortIndex = sortIndex; 44 this._all_control_results = []; 45 this._name = name; 46 this._title = title || name; 47 this._description = description; 48 49 if (!add_control_results) { 50 this._add_control_results = this.add_control_results; 51 } else { 52 this._add_control_results = add_control_results; 53 } 54 55 const thisTrunk = [...trunk, this]; 56 const nestedBenchmarks: Benchmark[] = []; 57 const benchmarksToAdd = benchmarks || []; 58 const lengthMaxBenchmarkIndex = (benchmarksToAdd.length - 1).toString() 59 .length; 60 benchmarksToAdd.forEach((nestedBenchmark, benchmarkIndex) => { 61 const nestedDefinition = panelsMap[nestedBenchmark.name]; 62 // @ts-ignore 63 const benchmarks = nestedBenchmark.children?.filter( 64 (child) => child.panel_type === "benchmark" 65 ); 66 // @ts-ignore 67 const controls = nestedBenchmark.children?.filter( 68 (child) => child.panel_type === "control" 69 ); 70 nestedBenchmarks.push( 71 new Benchmark( 72 `benchmark-${padStart( 73 benchmarkIndex.toString(), 74 lengthMaxBenchmarkIndex 75 )}`, 76 nestedDefinition.name, 77 nestedDefinition.title, 78 nestedDefinition.description, 79 benchmarks, 80 controls, 81 panelsMap, 82 thisTrunk, 83 this._add_control_results 84 ) 85 ); 86 }); 87 const nestedControls: Control[] = []; 88 const controlsToAdd = controls || []; 89 const lengthMaxControlIndex = (controlsToAdd.length - 1).toString().length; 90 controlsToAdd.forEach((nestedControl, controlIndex) => { 91 // @ts-ignore 92 const control = panelsMap[nestedControl.name] as CheckControlRun; 93 nestedControls.push( 94 new Control( 95 `control-${padStart(controlIndex.toString(), lengthMaxControlIndex)}`, 96 this._name, 97 this._title, 98 this._description, 99 control.name, 100 control.title, 101 control.description, 102 control.properties?.severity || control.severity, 103 control.data, 104 control.summary, 105 control.tags, 106 control.status, 107 control.error, 108 panelsMap, 109 thisTrunk, 110 this._add_control_results 111 ) 112 ); 113 }); 114 this._benchmarks = nestedBenchmarks; 115 this._controls = nestedControls; 116 } 117 118 private add_control_results = (results: CheckResult[]) => { 119 this._all_control_results.push(...results); 120 }; 121 122 get all_control_results(): CheckResult[] { 123 return this._all_control_results; 124 } 125 126 get sort(): string { 127 return `${this._sortIndex}-${this.title}`; 128 } 129 130 get name(): string { 131 return this._name; 132 } 133 134 get title(): string { 135 return this._title || this._name; 136 } 137 138 get type(): CheckNodeType { 139 return "benchmark"; 140 } 141 142 get children(): CheckNode[] { 143 return [...this._benchmarks, ...this._controls]; 144 } 145 146 get benchmarks(): Benchmark[] { 147 return this._benchmarks; 148 } 149 150 get controls(): Control[] { 151 return this._controls; 152 } 153 154 get summary(): CheckSummary { 155 const summary = { 156 alarm: 0, 157 ok: 0, 158 info: 0, 159 skip: 0, 160 error: 0, 161 }; 162 for (const benchmark of this._benchmarks) { 163 const nestedSummary = benchmark.summary; 164 summary.alarm += nestedSummary.alarm; 165 summary.ok += nestedSummary.ok; 166 summary.info += nestedSummary.info; 167 summary.skip += nestedSummary.skip; 168 summary.error += nestedSummary.error; 169 } 170 for (const control of this._controls) { 171 const nestedSummary = control.summary; 172 summary.alarm += nestedSummary.alarm; 173 summary.ok += nestedSummary.ok; 174 summary.info += nestedSummary.info; 175 summary.skip += nestedSummary.skip; 176 summary.error += nestedSummary.error; 177 } 178 return summary; 179 } 180 181 get severity_summary(): CheckSeveritySummary { 182 return {}; 183 } 184 185 get status(): CheckNodeStatus { 186 for (const benchmark of this._benchmarks) { 187 if (benchmark.status === "running") { 188 return "running"; 189 } 190 } 191 for (const control of this._controls) { 192 if (control.status === "running") { 193 return "running"; 194 } 195 } 196 return "complete"; 197 } 198 199 get_data_table(): LeafNodeData { 200 const columns: LeafNodeDataColumn[] = [ 201 { 202 name: "group_id", 203 data_type: "TEXT", 204 }, 205 { 206 name: "title", 207 data_type: "TEXT", 208 }, 209 { 210 name: "description", 211 data_type: "TEXT", 212 }, 213 { 214 name: "control_id", 215 data_type: "TEXT", 216 }, 217 { 218 name: "control_title", 219 data_type: "TEXT", 220 }, 221 { 222 name: "control_description", 223 data_type: "TEXT", 224 }, 225 { 226 name: "severity", 227 data_type: "TEXT", 228 }, 229 { 230 name: "reason", 231 data_type: "TEXT", 232 }, 233 { 234 name: "resource", 235 data_type: "TEXT", 236 }, 237 { 238 name: "status", 239 data_type: "TEXT", 240 }, 241 ]; 242 const { dimensions, tags } = this.get_dynamic_cols(); 243 Object.keys(tags).forEach((tag) => 244 columns.push({ 245 name: tag, 246 data_type: "TEXT", 247 }) 248 ); 249 Object.keys(dimensions).forEach((dimension) => 250 columns.push({ 251 name: dimension, 252 data_type: "TEXT", 253 }) 254 ); 255 const rows = this.get_data_rows(Object.keys(tags), Object.keys(dimensions)); 256 // let rows: LeafNodeDataRow[] = []; 257 // this._benchmarks.forEach(benchmark => { 258 // rows = [...rows, ...benchmark.get_data_rows()] 259 // }) 260 // this._controls.forEach(control => { 261 // rows = [...rows, ...control.get_data_rows()] 262 // }) 263 264 return { 265 columns, 266 rows, 267 }; 268 } 269 270 get_dynamic_cols(): CheckDynamicColsMap { 271 let keys = { 272 dimensions: {}, 273 tags: {}, 274 }; 275 this._benchmarks.forEach((benchmark) => { 276 const subBenchmarkKeys = benchmark.get_dynamic_cols(); 277 keys = merge(keys, subBenchmarkKeys); 278 }); 279 this._controls.forEach((control) => { 280 const controlKeys = control.get_dynamic_cols(); 281 keys = merge(keys, controlKeys); 282 }); 283 return keys; 284 } 285 286 get_data_rows(tags: string[], dimensions: string[]): LeafNodeDataRow[] { 287 let rows: LeafNodeDataRow[] = []; 288 this._benchmarks.forEach((benchmark) => { 289 rows = [...rows, ...benchmark.get_data_rows(tags, dimensions)]; 290 }); 291 this._controls.forEach((control) => { 292 rows = [...rows, ...control.get_data_rows(tags, dimensions)]; 293 }); 294 return rows; 295 } 296 } 297 298 export default Benchmark;