github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/ui/dashboard/src/components/dashboards/check/Benchmark/index.tsx (about) 1 import Card, { CardProps, CardType } from "../../Card"; 2 import CheckGrouping from "../CheckGrouping"; 3 import ContainerTitle from "../../titles/ContainerTitle"; 4 import Error from "../../Error"; 5 import Grid from "../../layout/Grid"; 6 import Panel from "../../layout/Panel"; 7 import PanelControls from "../../layout/Panel/PanelControls"; 8 import usePanelControls from "../../../../hooks/usePanelControls"; 9 import { 10 BenchmarkTreeProps, 11 CheckDisplayGroup, 12 CheckNode, 13 CheckSummary, 14 } from "../common"; 15 import { 16 CheckGroupingProvider, 17 useCheckGrouping, 18 } from "../../../../hooks/useCheckGrouping"; 19 import { default as BenchmarkType } from "../common/Benchmark"; 20 import { getComponent, registerComponent } from "../../index"; 21 import { noop } from "../../../../utils/func"; 22 import { PanelDefinition } from "../../../../types"; 23 import { useDashboard } from "../../../../hooks/useDashboard"; 24 import { useMemo, useState } from "react"; 25 import { Width } from "../../common"; 26 27 const Table = getComponent("table"); 28 29 type BenchmarkTableViewProps = { 30 benchmark: BenchmarkType; 31 definition: PanelDefinition; 32 }; 33 34 type InnerCheckProps = { 35 benchmark: BenchmarkType; 36 definition: PanelDefinition; 37 grouping: CheckNode; 38 groupingConfig: CheckDisplayGroup[]; 39 firstChildSummaries: CheckSummary[]; 40 showControls: boolean; 41 withTitle: boolean; 42 }; 43 44 const Benchmark = (props: InnerCheckProps) => { 45 const { dashboard } = useDashboard(); 46 const benchmarkDataTable = useMemo(() => { 47 if ( 48 !props.benchmark || 49 !props.grouping || 50 props.grouping.status !== "complete" 51 ) { 52 return undefined; 53 } 54 return props.benchmark.get_data_table(); 55 }, [props.benchmark, props.grouping]); 56 const [referenceElement, setReferenceElement] = useState(null); 57 const [showBenchmarkControls, setShowBenchmarkControls] = useState(false); 58 const definitionWithData = useMemo(() => { 59 return { 60 ...props.definition, 61 data: benchmarkDataTable, 62 }; 63 }, [benchmarkDataTable, props.definition]); 64 const { panelControls: benchmarkControls } = usePanelControls( 65 definitionWithData, 66 props.showControls 67 ); 68 69 const summaryCards = useMemo(() => { 70 if (!props.grouping) { 71 return []; 72 } 73 74 const totalSummary = props.firstChildSummaries.reduce( 75 (cumulative, current) => { 76 cumulative.error += current.error; 77 cumulative.alarm += current.alarm; 78 cumulative.ok += current.ok; 79 cumulative.info += current.info; 80 cumulative.skip += current.skip; 81 return cumulative; 82 }, 83 { error: 0, alarm: 0, ok: 0, info: 0, skip: 0 } 84 ); 85 const summary_cards = [ 86 { 87 name: `${props.definition.name}.container.summary.ok`, 88 width: 2, 89 display_type: totalSummary.ok > 0 ? "ok" : null, 90 properties: { 91 label: "OK", 92 value: totalSummary.ok, 93 icon: "materialsymbols-solid:check_circle", 94 }, 95 }, 96 { 97 name: `${props.definition.name}.container.summary.alarm`, 98 width: 2, 99 display_type: totalSummary.alarm > 0 ? "alert" : null, 100 properties: { 101 label: "Alarm", 102 value: totalSummary.alarm, 103 icon: "materialsymbols-solid:notifications", 104 }, 105 }, 106 { 107 name: `${props.definition.name}.container.summary.error`, 108 width: 2, 109 display_type: totalSummary.error > 0 ? "alert" : null, 110 properties: { 111 label: "Error", 112 value: totalSummary.error, 113 icon: "materialsymbols-solid:error", 114 }, 115 }, 116 { 117 name: `${props.definition.name}.container.summary.info`, 118 width: 2, 119 display_type: totalSummary.info > 0 ? "info" : null, 120 properties: { 121 label: "Info", 122 value: totalSummary.info, 123 icon: "materialsymbols-solid:info", 124 }, 125 }, 126 { 127 name: `${props.definition.name}.container.summary.skip`, 128 width: 2, 129 properties: { 130 label: "Skipped", 131 value: totalSummary.skip, 132 icon: "materialsymbols-solid:arrow_circle_right", 133 }, 134 }, 135 ]; 136 137 const severity_summary = props.grouping.severity_summary; 138 const criticalRaw = severity_summary["critical"]; 139 const highRaw = severity_summary["high"]; 140 const critical = criticalRaw || 0; 141 const high = highRaw || 0; 142 143 // If we have at least 1 critical or undefined control defined in this run 144 if (criticalRaw !== undefined || highRaw !== undefined) { 145 const total = critical + high; 146 summary_cards.push({ 147 name: `${props.definition.name}.container.summary.severity`, 148 width: 2, 149 display_type: total > 0 ? "severity" : "", 150 properties: { 151 label: "Critical / High", 152 value: total, 153 icon: "materialsymbols-solid:warning", 154 }, 155 }); 156 } 157 return summary_cards; 158 }, [props.firstChildSummaries, props.grouping, props.definition.name]); 159 160 if (!props.grouping) { 161 return null; 162 } 163 164 return ( 165 <Grid 166 name={props.definition.name} 167 width={props.definition.width} 168 events={{ 169 onMouseEnter: props.showControls 170 ? () => setShowBenchmarkControls(true) 171 : noop, 172 onMouseLeave: () => setShowBenchmarkControls(false), 173 }} 174 setRef={setReferenceElement} 175 > 176 {!dashboard?.artificial && ( 177 <ContainerTitle title={props.benchmark.title} /> 178 )} 179 {showBenchmarkControls && ( 180 <PanelControls 181 referenceElement={referenceElement} 182 controls={benchmarkControls} 183 /> 184 )} 185 <Grid name={`${props.definition.name}.container.summary`}> 186 {summaryCards.map((summaryCard) => { 187 const cardProps: CardProps = { 188 name: summaryCard.name, 189 dashboard: props.definition.dashboard, 190 display_type: summaryCard.display_type as CardType, 191 panel_type: "card", 192 properties: summaryCard.properties, 193 status: "complete", 194 width: summaryCard.width as Width, 195 }; 196 return ( 197 <Panel 198 key={summaryCard.name} 199 definition={cardProps} 200 parentType="benchmark" 201 showControls={false} 202 > 203 <Card {...cardProps} /> 204 </Panel> 205 ); 206 })} 207 </Grid> 208 <Grid name={`${props.definition.name}.container.tree`}> 209 <BenchmarkTree 210 name={`${props.definition.name}.container.tree.results`} 211 dashboard={props.definition.dashboard} 212 panel_type="benchmark_tree" 213 properties={{ 214 grouping: props.grouping, 215 first_child_summaries: props.firstChildSummaries, 216 }} 217 status="complete" 218 /> 219 </Grid> 220 </Grid> 221 ); 222 }; 223 224 const BenchmarkTree = (props: BenchmarkTreeProps) => { 225 if (!props.properties || !props.properties.first_child_summaries) { 226 return null; 227 } 228 229 return <CheckGrouping node={props.properties.grouping} />; 230 }; 231 232 const BenchmarkTableView = ({ 233 benchmark, 234 definition, 235 }: BenchmarkTableViewProps) => { 236 const benchmarkDataTable = useMemo( 237 () => benchmark.get_data_table(), 238 [benchmark] 239 ); 240 241 return ( 242 <Panel 243 definition={{ 244 name: definition.name, 245 dashboard: definition.dashboard, 246 panel_type: "table", 247 width: definition.width, 248 children: definition.children, 249 data: benchmarkDataTable, 250 status: benchmarkDataTable ? "complete" : "running", 251 }} 252 parentType="benchmark" 253 > 254 <Table 255 name={`${definition.name}.table`} 256 panel_type="table" 257 data={benchmarkDataTable} 258 /> 259 </Panel> 260 ); 261 }; 262 263 const Inner = ({ showControls, withTitle }) => { 264 const { 265 benchmark, 266 definition, 267 grouping, 268 groupingsConfig, 269 firstChildSummaries, 270 } = useCheckGrouping(); 271 272 if (!definition || !benchmark || !grouping) { 273 return null; 274 } 275 276 if (!definition.display_type || definition.display_type === "benchmark") { 277 return ( 278 <Benchmark 279 benchmark={benchmark} 280 definition={definition} 281 grouping={grouping} 282 groupingConfig={groupingsConfig} 283 firstChildSummaries={firstChildSummaries} 284 showControls={showControls} 285 withTitle={withTitle} 286 /> 287 ); 288 // @ts-ignore 289 } else if (definition.display_type === "table") { 290 return <BenchmarkTableView benchmark={benchmark} definition={definition} />; 291 } else { 292 return ( 293 <Panel 294 definition={{ 295 name: definition.name, 296 dashboard: definition.dashboard, 297 panel_type: "benchmark", 298 width: definition.width, 299 status: "error", 300 }} 301 parentType="benchmark" 302 > 303 <Error 304 error={`Unsupported benchmark type ${definition.display_type}`} 305 /> 306 </Panel> 307 ); 308 } 309 }; 310 311 type BenchmarkProps = PanelDefinition & { 312 showControls: boolean; 313 withTitle: boolean; 314 }; 315 316 const BenchmarkWrapper = (props: BenchmarkProps) => { 317 return ( 318 <CheckGroupingProvider definition={props}> 319 <Inner showControls={props.showControls} withTitle={props.withTitle} /> 320 </CheckGroupingProvider> 321 ); 322 }; 323 324 registerComponent("benchmark", BenchmarkWrapper); 325 326 export default BenchmarkWrapper;