github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/ui/dashboard/src/utils/state.ts (about)

     1  import dayjs from "dayjs";
     2  import sortBy from "lodash/sortBy";
     3  import {
     4    AvailableDashboard,
     5    AvailableDashboardsDictionary,
     6    DashboardDefinition,
     7    DashboardRunState,
     8    DashboardsCollection,
     9    DependencyPanelProperties,
    10    PanelDefinition,
    11    PanelLog,
    12    PanelsLog,
    13    PanelsMap,
    14  } from "../types";
    15  import {
    16    EdgeProperties,
    17    KeyValueStringPairs,
    18    NodeProperties,
    19  } from "../components/dashboards/common/types";
    20  
    21  const buildDashboards = (
    22    dashboards: AvailableDashboardsDictionary,
    23    benchmarks: AvailableDashboardsDictionary,
    24    snapshots: KeyValueStringPairs
    25  ): DashboardsCollection => {
    26    const dashboardsMap = {};
    27    const builtDashboards: AvailableDashboard[] = [];
    28  
    29    for (const [, dashboard] of Object.entries(dashboards)) {
    30      const builtDashboard: AvailableDashboard = {
    31        title: dashboard.title,
    32        full_name: dashboard.full_name,
    33        short_name: dashboard.short_name,
    34        type: "dashboard",
    35        tags: dashboard.tags,
    36        mod_full_name: dashboard.mod_full_name,
    37        is_top_level: true,
    38      };
    39      dashboardsMap[builtDashboard.full_name] = builtDashboard;
    40      builtDashboards.push(builtDashboard);
    41    }
    42  
    43    for (const [, benchmark] of Object.entries(benchmarks)) {
    44      const builtBenchmark: AvailableDashboard = {
    45        title: benchmark.title,
    46        full_name: benchmark.full_name,
    47        short_name: benchmark.short_name,
    48        type: "benchmark",
    49        tags: benchmark.tags,
    50        mod_full_name: benchmark.mod_full_name,
    51        is_top_level: benchmark.is_top_level,
    52        trunks: benchmark.trunks,
    53        children: benchmark.children,
    54      };
    55      dashboardsMap[builtBenchmark.full_name] = builtBenchmark;
    56      builtDashboards.push(builtBenchmark);
    57    }
    58  
    59    for (const snapshot of Object.keys(snapshots || {})) {
    60      const builtSnapshot: AvailableDashboard = {
    61        title: snapshot,
    62        full_name: snapshot,
    63        short_name: snapshot,
    64        type: "snapshot",
    65        tags: {},
    66        is_top_level: true,
    67      };
    68      dashboardsMap[builtSnapshot.full_name] = builtSnapshot;
    69      builtDashboards.push(builtSnapshot);
    70    }
    71  
    72    return {
    73      dashboards: sortBy(builtDashboards, [
    74        (dashboard) =>
    75          dashboard.title
    76            ? dashboard.title.toLowerCase()
    77            : dashboard.full_name.toLowerCase(),
    78      ]),
    79      dashboardsMap,
    80    };
    81  };
    82  
    83  const panelLogTitle = (panel: PanelDefinition) => {
    84    switch (panel.panel_type) {
    85      case "with":
    86        const dependencyPanelProperties = (panel.properties ||
    87          {}) as DependencyPanelProperties;
    88        return panel.title
    89          ? panel.title
    90          : dependencyPanelProperties && dependencyPanelProperties.name
    91          ? dependencyPanelProperties.name
    92          : panel.name;
    93      case "edge":
    94        if (panel.title) {
    95          return panel.title;
    96        }
    97        const edgeProperties = (panel.properties || {}) as EdgeProperties;
    98        if (edgeProperties.category) {
    99          if (edgeProperties.category.title) {
   100            return edgeProperties.category.title as string;
   101          }
   102          return edgeProperties.category.name as string;
   103        }
   104        return panel.name;
   105      case "node":
   106        if (panel.title) {
   107          return panel.title;
   108        }
   109        const nodeProperties = (panel.properties || {}) as NodeProperties;
   110        if (nodeProperties.category) {
   111          if (nodeProperties.category.title) {
   112            return nodeProperties.category.title as string;
   113          }
   114          return nodeProperties.category.name as string;
   115        }
   116        return panel.name;
   117      default:
   118        return panel.title || panel.name;
   119    }
   120  };
   121  
   122  const buildPanelLog = (
   123    panel: PanelDefinition,
   124    timestamp: string,
   125    executionTime?: number
   126  ): PanelLog => {
   127    return {
   128      error: panel.status === "error" ? panel.error : null,
   129      executionTime,
   130      status: panel.status as DashboardRunState,
   131      timestamp,
   132      title: panelLogTitle(panel),
   133    };
   134  };
   135  
   136  const buildPanelsLog = (panels: PanelsMap, timestamp: string) => {
   137    const panelsLog: PanelsLog = {};
   138    for (const [name, panel] of Object.entries(panels || {})) {
   139      panelsLog[name] = [buildPanelLog(panel, timestamp)];
   140    }
   141    return panelsLog;
   142  };
   143  
   144  const calculateExecutionTime = (
   145    timestamp: string,
   146    panel: PanelDefinition,
   147    panelLogs: PanelLog[]
   148  ): number | undefined => {
   149    let overallTime: number | undefined = undefined;
   150    if (panel.status === "complete") {
   151      const runningLog = panelLogs.find((l) => l.status === "running");
   152      if (runningLog) {
   153        overallTime = dayjs(timestamp).diff(runningLog.timestamp);
   154      }
   155    }
   156    return overallTime;
   157  };
   158  
   159  const addUpdatedPanelLogs = (
   160    panelsLog: PanelsLog,
   161    panel: PanelDefinition,
   162    timestamp: string
   163  ) => {
   164    const newPanelsLog = { ...panelsLog };
   165    const newPanelLog = [...(newPanelsLog[panel.name] || [])];
   166    if (newPanelLog.find((l) => l.status === panel.status)) {
   167      return newPanelsLog;
   168    } else {
   169      const overallTime = calculateExecutionTime(timestamp, panel, newPanelLog);
   170      newPanelLog.push(buildPanelLog(panel, timestamp, overallTime));
   171    }
   172    newPanelsLog[panel.name] = newPanelLog;
   173    return newPanelsLog;
   174  };
   175  
   176  const updatePanelsLogFromCompletedPanels = (
   177    panelsLog: PanelsLog,
   178    panels: PanelsMap,
   179    timestamp: string
   180  ) => {
   181    const newPanelsLog = { ...panelsLog };
   182    for (const [panelName, panel] of Object.entries(panels || {})) {
   183      const newPanelLog = [...(newPanelsLog[panelName] || [])];
   184      // If we have an existing panel log for the same status, don't log it
   185      if (newPanelLog.find((l) => l.status === panel.status)) {
   186        continue;
   187      }
   188      const overallTime = calculateExecutionTime(timestamp, panel, newPanelLog);
   189      newPanelLog.push(buildPanelLog(panel, timestamp, overallTime));
   190      newPanelsLog[panelName] = newPanelLog;
   191    }
   192  
   193    return newPanelsLog;
   194  };
   195  
   196  const buildSelectedDashboardInputsFromSearchParams = (searchParams) => {
   197    const selectedDashboardInputs = {};
   198    // @ts-ignore
   199    for (const entry of searchParams.entries()) {
   200      if (!entry[0].startsWith("input")) {
   201        continue;
   202      }
   203      selectedDashboardInputs[entry[0]] = entry[1];
   204    }
   205    return selectedDashboardInputs;
   206  };
   207  
   208  const updateSelectedDashboard = (
   209    selectedDashboard: AvailableDashboard | null,
   210    newDashboards: AvailableDashboard[]
   211  ) => {
   212    if (!selectedDashboard) {
   213      return null;
   214    }
   215    const matchingDashboard = newDashboards.find(
   216      (dashboard) => dashboard.full_name === selectedDashboard.full_name
   217    );
   218    if (matchingDashboard) {
   219      return matchingDashboard;
   220    } else {
   221      return null;
   222    }
   223  };
   224  
   225  const wrapDefinitionInArtificialDashboard = (
   226    definition: PanelDefinition,
   227    layout: any
   228  ): DashboardDefinition => {
   229    const { title: defTitle, ...definitionWithoutTitle } = definition;
   230    const { title: layoutTitle, ...layoutWithoutTitle } = layout;
   231    return {
   232      artificial: true,
   233      name: definition.name,
   234      title: definition.title,
   235      panel_type: "dashboard",
   236      children: [
   237        {
   238          ...definitionWithoutTitle,
   239          ...layoutWithoutTitle,
   240        },
   241      ],
   242      dashboard: definition.dashboard,
   243    };
   244  };
   245  
   246  export {
   247    addUpdatedPanelLogs,
   248    buildDashboards,
   249    buildPanelsLog,
   250    buildSelectedDashboardInputsFromSearchParams,
   251    panelLogTitle,
   252    updatePanelsLogFromCompletedPanels,
   253    updateSelectedDashboard,
   254    wrapDefinitionInArtificialDashboard,
   255  };