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

     1  import { addUpdatedPanelLogs } from "./state";
     2  import {
     3    EXECUTION_SCHEMA_VERSION_20220614,
     4    EXECUTION_SCHEMA_VERSION_20220929,
     5    EXECUTION_SCHEMA_VERSION_20221222,
     6  } from "../constants/versions";
     7  import { PanelDefinition, PanelsMap } from "../types";
     8  
     9  const migratePanelStatus = (
    10    panel: PanelDefinition,
    11    currentSchemaVersion: string
    12  ): PanelDefinition => {
    13    switch (currentSchemaVersion) {
    14      case "":
    15      case EXECUTION_SCHEMA_VERSION_20220614:
    16      case EXECUTION_SCHEMA_VERSION_20220929:
    17        return {
    18          ...panel,
    19          // @ts-ignore
    20          status: panel.status === "ready" ? "running" : panel.status,
    21        };
    22      case EXECUTION_SCHEMA_VERSION_20221222:
    23        // Nothing to do - already the latest statuses
    24        return panel;
    25      default:
    26        throw new Error(
    27          `Unsupported dashboard event schema ${currentSchemaVersion}`
    28        );
    29    }
    30  };
    31  
    32  const migratePanelStatuses = (
    33    panelsMap: PanelsMap,
    34    currentSchemaVersion: string
    35  ): PanelsMap => {
    36    const newPanelsMap = {};
    37    for (const [name, panel] of Object.entries(panelsMap || {})) {
    38      newPanelsMap[name] = migratePanelStatus(panel, currentSchemaVersion);
    39    }
    40    return newPanelsMap;
    41  };
    42  
    43  const updatePanelsMapWithControlEvent = (panelsMap, action) => {
    44    return {
    45      ...panelsMap,
    46      [action.control.name]: migratePanelStatus(action.control, ""),
    47    };
    48  };
    49  
    50  const controlsUpdatedEventHandler = (action, state) => {
    51    // If the dashboard has already completed,
    52    // no need to process these events
    53    if (
    54      state.state === "complete" ||
    55      !action.controls ||
    56      action.controls.length === 0
    57    ) {
    58      return state;
    59    }
    60  
    61    let panelsMap = state.panelsMap;
    62    for (const event of action.controls) {
    63      // We're not expecting execution events for this ID
    64      if (event.execution_id !== state.execution_id) {
    65        continue;
    66      }
    67  
    68      const updatedPanelsMap = updatePanelsMapWithControlEvent(panelsMap, event);
    69  
    70      if (!updatedPanelsMap) {
    71        continue;
    72      }
    73  
    74      panelsMap = updatedPanelsMap;
    75    }
    76    return {
    77      ...state,
    78      panelsMap,
    79      progress: calculateProgress(panelsMap),
    80    };
    81  };
    82  
    83  const leafNodesUpdatedEventHandler = (action, currentSchemaVersion, state) => {
    84    // If there's nothing to process, no need to mutate state
    85    if (!action || !action.nodes || action.nodes.length === 0) {
    86      return state;
    87    }
    88  
    89    let panelsLog = state.panelsLog;
    90    let panelsMap = state.panelsMap;
    91    for (const event of action.nodes) {
    92      // We're not expecting execution events for this ID
    93      if (event.execution_id !== state.execution_id) {
    94        continue;
    95      }
    96  
    97      const { dashboard_node, timestamp } = event;
    98  
    99      if (!dashboard_node || !dashboard_node.status) {
   100        continue;
   101      }
   102  
   103      panelsLog = addUpdatedPanelLogs(panelsLog, dashboard_node, timestamp);
   104      panelsMap[dashboard_node.name] = migratePanelStatus(
   105        dashboard_node,
   106        currentSchemaVersion
   107      );
   108    }
   109  
   110    const newState = {
   111      ...state,
   112      panelsLog,
   113      progress: calculateProgress(panelsMap),
   114    };
   115  
   116    if (state.state !== "complete") {
   117      newState.panelsMap = { ...panelsMap };
   118    }
   119  
   120    return newState;
   121  };
   122  
   123  const calculateProgress = (panelsMap) => {
   124    const panels: PanelDefinition[] = Object.values(panelsMap || {});
   125    let dataPanels = 0;
   126    let completeDataPanels = 0;
   127    for (const panel of panels) {
   128      const isControl = panel.panel_type === "control";
   129      const isPendingDataPanel =
   130        panel.panel_type !== "container" &&
   131        panel.panel_type !== "dashboard" &&
   132        panel.panel_type !== "benchmark";
   133      if (isControl || isPendingDataPanel) {
   134        dataPanels += 1;
   135      }
   136      if (
   137        (isControl || isPendingDataPanel) &&
   138        (panel.status === "complete" || panel.status === "error")
   139      ) {
   140        completeDataPanels += 1;
   141      }
   142    }
   143    if (dataPanels === 0) {
   144      return 100;
   145    }
   146    return Math.min(Math.ceil((completeDataPanels / dataPanels) * 100), 100);
   147  };
   148  
   149  export {
   150    controlsUpdatedEventHandler,
   151    leafNodesUpdatedEventHandler,
   152    migratePanelStatus,
   153    migratePanelStatuses,
   154  };