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;