All files / src/pages/flowsheet-page/flowsheet/LeftSideBar PanelItems.tsx

86.84% Statements 33/38
73.33% Branches 11/15
83.33% Functions 5/6
88.57% Lines 31/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141                                103x 103x 103x 103x 103x                   103x                       103x                       103x                           103x       103x   823x 823x   795x       5x         28x       33x       103x   103x   16171x   4532x             4532x 4532x 4532x           4532x 4532x     103x 2060x 927x       6798x       4120x 4120x                    
import {
  Circle,
  CircleGauge,
  Flame,
  Package,
  Shuffle,
  Sigma,
} from "lucide-react";
import type { ElementType } from "react";
import {
  type CoreFlowsheetTemplatesListApiResponse,
  ObjectTypeEnum,
} from "@/api/apiStore.gen";
import { rawUnitOpConfigs, type UnitOpJsonConfig } from "@/data/unitOpConfigs";
import { useTemplates } from "@/hooks/useTemplate";
 
const IconPressureChanger = CircleGauge;
const IconMixer = Shuffle;
const IconExchanger = Flame;
const IconSolid = Circle;
const IconLogical = Sigma;
 
export type PanelType = {
  type: string;
  label: string;
  icon: ElementType;
  objects: ObjectTypeEnum[];
  templates?: CoreFlowsheetTemplatesListApiResponse;
};
 
const PANEL_LABELS: Record<string, string> = {
  pressure_changer: "Pressure Changer",
  heating_and_cooling: "Heating and Cooling",
  mixer: "Mixer",
  separation: "Separation",
  special: "Special",
  machine_learning: "Machine Learning",
  generators: "Generators",
  power_system: "Power System",
  convertors: "Convertors",
};
 
const PANEL_ICONS: Record<string, ElementType> = {
  pressure_changer: IconPressureChanger,
  heating_and_cooling: IconExchanger,
  mixer: IconMixer,
  separation: IconSolid,
  special: IconSolid,
  machine_learning: IconSolid,
  generators: IconLogical,
  power_system: IconLogical,
  convertors: IconLogical,
};
 
const PANEL_ORDER = [
  "chemical/reactors",
  "chemical/pressure_changer",
  "chemical/mixer",
  "chemical/heating_and_cooling",
  "chemical/separation",
  "chemical/special",
  "chemical/machine_learning",
  "energy/generators",
  "energy/power_system",
  "energy/convertors",
  "energy",
];
 
const objectTypeValues = new Set<string>(
  Object.values(ObjectTypeEnum) as string[],
);
 
export const PANEL_DATA: PanelType[] = buildPanelData();
 
export function usePanelData(): PanelType[] {
  const { templates } = useTemplates();
 
  if (!templates || templates.length === 0) {
    return PANEL_DATA;
  }
 
  return [
    {
      type: "template",
      label: "Template Modules",
      icon: Package,
      objects: [],
      templates: templates,
    },
    ...PANEL_DATA,
  ];
}
 
function buildPanelData(): PanelType[] {
  const panelMap = new Map<string, PanelType>();
 
  Object.values(rawUnitOpConfigs)
    .filter(shouldShowInPanel)
    .sort((left, right) => left.displayType.localeCompare(right.displayType))
    .forEach((config) => {
      const categoryPath = config.categoryPath;
      if (
        categoryPath.length === 0 ||
        !objectTypeValues.has(config.objectType)
      ) {
        return;
      }
      const panelKey = categoryPath.join("/");
      const groupKey = categoryPath[categoryPath.length - 1] ?? categoryPath[0];
      const panel = panelMap.get(panelKey) ?? {
        type: categoryPath[0],
        label: PANEL_LABELS[groupKey] ?? titleCase(groupKey),
        icon: PANEL_ICONS[groupKey] ?? IconSolid,
        objects: [] as ObjectTypeEnum[],
      };
      panel.objects.push(config.objectType as ObjectTypeEnum);
      panelMap.set(panelKey, panel);
    });
 
  return [...panelMap.entries()]
    .sort(([left], [right]) => panelSortIndex(left) - panelSortIndex(right))
    .map(([, panel]) => panel);
}
 
function shouldShowInPanel(config: UnitOpJsonConfig): boolean {
  return config.frontend?.showInPanel === true;
}
 
function panelSortIndex(panelKey: string): number {
  const index = PANEL_ORDER.indexOf(panelKey);
  return index === -1 ? PANEL_ORDER.length : index;
}
 
function titleCase(value: string): string {
  return value
    .split("_")
    .filter(Boolean)
    .map((word) => word.slice(0, 1).toUpperCase() + word.slice(1))
    .join(" ");
}