{"version":3,"file":"utils.mjs","sources":["../../../../../src/components/Table/TableNG/utils.ts"],"sourcesContent":["import { css } from '@emotion/css';\nimport { Property } from 'csstype';\nimport React from 'react';\nimport { SortColumn, SortDirection } from 'react-data-grid';\nimport tinycolor from 'tinycolor2';\nimport { varPreLine } from 'uwrap';\n\nimport {\n  FieldType,\n  Field,\n  formattedValueToString,\n  reduceField,\n  GrafanaTheme2,\n  DisplayValue,\n  LinkModel,\n  DisplayValueAlignmentFactors,\n  DataFrame,\n} from '@grafana/data';\nimport {\n  BarGaugeDisplayMode,\n  TableAutoCellOptions,\n  TableCellBackgroundDisplayMode,\n  TableCellDisplayMode,\n  TableCellHeight,\n  TableCellOptions,\n  TableSortByFieldState,\n} from '@grafana/schema';\n\nimport { TableCellInspectorMode } from '../..';\nimport { getTextColorForAlphaBackground } from '../../../utils';\n\nimport { TABLE } from './constants';\nimport {\n  CellColors,\n  TableRow,\n  TableFieldOptionsType,\n  ColumnTypes,\n  FilterType,\n  FrameToRowsConverter,\n  TableNGProps,\n  Comparator,\n  TableFooterCalc,\n} from './types';\n\n/* ---------------------------- Cell calculations --------------------------- */\nexport function getCellHeight(\n  text: string,\n  cellWidth: number, // width of the cell without padding\n  ctx: CanvasRenderingContext2D,\n  lineHeight: number,\n  defaultRowHeight: number,\n  padding = 0\n) {\n  const PADDING = padding * 2;\n\n  if (typeof text === 'string') {\n    const words = text.split(/\\s/);\n    const lines = [];\n    let currentLine = '';\n\n    // Let's just wrap the lines and see how well the measurement works\n    for (let i = 0; i < words.length; i++) {\n      const currentWord = words[i];\n      // TODO: this method is not accurate\n      let lineWidth = ctx.measureText(currentLine + ' ' + currentWord).width;\n\n      // if line width is less than the cell width, add the word to the current line and continue\n      // else add the current line to the lines array and start a new line with the current word\n      if (lineWidth < cellWidth) {\n        currentLine += ' ' + currentWord;\n      } else {\n        lines.push({\n          width: lineWidth,\n          line: currentLine,\n        });\n\n        currentLine = currentWord;\n      }\n\n      // if we are at the last word, add the current line to the lines array\n      if (i === words.length - 1) {\n        lines.push({\n          width: lineWidth,\n          line: currentLine,\n        });\n      }\n    }\n\n    if (lines.length === 1) {\n      return defaultRowHeight;\n    }\n\n    // TODO: double padding to adjust osContext.measureText() results\n    const height = lines.length * lineHeight + PADDING * 2;\n\n    return height;\n  }\n\n  return defaultRowHeight;\n}\n\nexport type CellHeightCalculator = (text: string, cellWidth: number) => number;\n\nexport function getCellHeightCalculator(\n  // should be pre-configured with font and letterSpacing\n  ctx: CanvasRenderingContext2D,\n  lineHeight: number,\n  defaultRowHeight: number,\n  padding = 0\n) {\n  const { count } = varPreLine(ctx);\n\n  return (text: string, cellWidth: number) => {\n    const effectiveCellWidth = Math.max(cellWidth, 20); // Minimum width to work with\n    const TOTAL_PADDING = padding * 2;\n    const numLines = count(text, effectiveCellWidth);\n    const totalHeight = numLines * lineHeight + TOTAL_PADDING;\n    return Math.max(totalHeight, defaultRowHeight);\n  };\n}\n\nexport function getDefaultRowHeight(theme: GrafanaTheme2, cellHeight: TableCellHeight | undefined): number {\n  const bodyFontSize = theme.typography.fontSize;\n  const lineHeight = theme.typography.body.lineHeight;\n\n  switch (cellHeight) {\n    case TableCellHeight.Sm:\n      return 36;\n    case TableCellHeight.Md:\n      return 42;\n    case TableCellHeight.Lg:\n      return TABLE.MAX_CELL_HEIGHT;\n  }\n\n  return TABLE.CELL_PADDING * 2 + bodyFontSize * lineHeight;\n}\n\n/**\n * getRowHeight determines cell height based on cell width + text length. Used\n * for when textWrap is enabled.\n */\nexport function getRowHeight(\n  row: TableRow,\n  calc: CellHeightCalculator,\n  avgCharWidth: number,\n  defaultRowHeight: number,\n  fieldsData: {\n    headersLength: number;\n    textWraps: { [key: string]: boolean };\n    columnTypes: ColumnTypes;\n    columnWidths: Record<string, number>;\n    fieldDisplayType: Record<string, TableCellDisplayMode>;\n  }\n): number {\n  let maxLines = 1;\n  let maxLinesCol = '';\n\n  for (const key in row) {\n    if (\n      fieldsData.columnTypes[key] === FieldType.string &&\n      fieldsData.textWraps[key] &&\n      fieldsData.fieldDisplayType[key] !== TableCellDisplayMode.Image\n    ) {\n      const cellText = row[key] as string;\n\n      if (cellText != null) {\n        const charsPerLine = fieldsData.columnWidths[key] / avgCharWidth;\n        const approxLines = cellText.length / charsPerLine;\n\n        if (approxLines > maxLines) {\n          maxLines = approxLines;\n          maxLinesCol = key;\n        }\n      }\n    }\n  }\n\n  return maxLinesCol === '' ? defaultRowHeight : calc(row[maxLinesCol] as string, fieldsData.columnWidths[maxLinesCol]);\n}\n\nexport function isTextCell(key: string, columnTypes: Record<string, string>): boolean {\n  return columnTypes[key] === FieldType.string;\n}\n\nexport function shouldTextOverflow(\n  key: string,\n  row: TableRow,\n  columnTypes: ColumnTypes,\n  headerCellRefs: React.MutableRefObject<Record<string, HTMLDivElement>>,\n  ctx: CanvasRenderingContext2D,\n  lineHeight: number,\n  defaultRowHeight: number,\n  padding: number,\n  textWrap: boolean,\n  field: Field,\n  cellType: TableCellDisplayMode\n): boolean {\n  const cellInspect = field.config?.custom?.inspect ?? false;\n\n  // Tech debt: Technically image cells are of type string, which is misleading (kinda?)\n  // so we need to ensure we don't apply overflow hover states fo type image\n  if (textWrap || cellInspect || cellType === TableCellDisplayMode.Image || !isTextCell(key, columnTypes)) {\n    return false;\n  }\n\n  return true;\n}\n\nexport function getTextAlign(field?: Field): Property.JustifyContent {\n  if (!field) {\n    return 'flex-start';\n  }\n\n  if (field.config.custom) {\n    const custom: TableFieldOptionsType = field.config.custom;\n\n    switch (custom.align) {\n      case 'right':\n        return 'flex-end';\n      case 'left':\n        return 'flex-start';\n      case 'center':\n        return 'center';\n    }\n  }\n\n  if (field.type === FieldType.number) {\n    return 'flex-end';\n  }\n\n  return 'flex-start';\n}\n\nconst defaultCellOptions: TableAutoCellOptions = { type: TableCellDisplayMode.Auto };\n\nexport function getCellOptions(field: Field): TableCellOptions {\n  if (field.config.custom?.displayMode) {\n    return migrateTableDisplayModeToCellOptions(field.config.custom?.displayMode);\n  }\n\n  if (!field.config.custom?.cellOptions) {\n    return defaultCellOptions;\n  }\n\n  return field.config.custom.cellOptions;\n}\n\n/**\n * Getting gauge or sparkline values to align is very tricky without looking at all values and passing them through display processor.\n * For very large tables that could pretty expensive. So this is kind of a compromise. We look at the first 1000 rows and cache the longest value.\n * If we have a cached value we just check if the current value is longer and update the alignmentFactor. This can obviously still lead to\n * unaligned gauges but it should a lot less common.\n **/\nexport function getAlignmentFactor(\n  field: Field,\n  displayValue: DisplayValue,\n  rowIndex: number\n): DisplayValueAlignmentFactors {\n  let alignmentFactor = field.state?.alignmentFactors;\n\n  if (alignmentFactor) {\n    // check if current alignmentFactor is still the longest\n    if (formattedValueToString(alignmentFactor).length < formattedValueToString(displayValue).length) {\n      alignmentFactor = { ...displayValue };\n      field.state!.alignmentFactors = alignmentFactor;\n    }\n    return alignmentFactor;\n  } else {\n    // look at the next 1000 rows\n    alignmentFactor = { ...displayValue };\n    const maxIndex = Math.min(field.values.length, rowIndex + 1000);\n\n    for (let i = rowIndex + 1; i < maxIndex; i++) {\n      const nextDisplayValue = field.display!(field.values[i]);\n      if (formattedValueToString(alignmentFactor).length > formattedValueToString(nextDisplayValue).length) {\n        alignmentFactor.text = displayValue.text;\n      }\n    }\n\n    if (field.state) {\n      field.state.alignmentFactors = alignmentFactor;\n    } else {\n      field.state = { alignmentFactors: alignmentFactor };\n    }\n\n    return alignmentFactor;\n  }\n}\n\n/* ------------------------------ Footer calculations ------------------------------ */\nexport function getFooterItemNG(rows: TableRow[], field: Field, options: TableFooterCalc | undefined): string {\n  if (options === undefined) {\n    return '';\n  }\n\n  if (field.type !== FieldType.number) {\n    return '';\n  }\n\n  // Check if reducer array exists and has at least one element\n  if (!options.reducer || !options.reducer.length) {\n    return '';\n  }\n\n  // If fields array is specified, only show footer for fields included in that array\n  if (options.fields && options.fields.length > 0) {\n    if (!options.fields.includes(field.name)) {\n      return '';\n    }\n  }\n\n  const calc = options.reducer[0];\n  const value = reduceField({\n    field: {\n      ...field,\n      values: rows.map((row) => row[getDisplayName(field)]),\n    },\n    reducers: options.reducer,\n  })[calc];\n\n  const formattedValue = formattedValueToString(field.display!(value));\n\n  return formattedValue;\n}\n\nexport const getFooterStyles = (justifyContent: Property.JustifyContent) => ({\n  footerCell: css({\n    display: 'flex',\n    justifyContent: justifyContent || 'space-between',\n  }),\n});\n\n/* ------------------------- Cell color calculation ------------------------- */\nconst CELL_COLOR_DARKENING_MULTIPLIER = 10;\nconst CELL_GRADIENT_DARKENING_MULTIPLIER = 15;\nconst CELL_GRADIENT_HUE_ROTATION_DEGREES = 5;\n\nexport function getCellColors(\n  theme: GrafanaTheme2,\n  cellOptions: TableCellOptions,\n  displayValue: DisplayValue\n): CellColors {\n  // Convert RGBA hover color to hex to prevent transparency issues on cell hover\n  const autoCellBackgroundHoverColor = convertRGBAToHex(theme.colors.background.primary, theme.colors.action.hover);\n\n  // How much to darken elements depends upon if we're in dark mode\n  const darkeningFactor = theme.isDark ? 1 : -0.7;\n\n  // Setup color variables\n  let textColor: string | undefined = undefined;\n  let bgColor: string | undefined = undefined;\n  let bgHoverColor: string = autoCellBackgroundHoverColor;\n\n  if (cellOptions.type === TableCellDisplayMode.ColorText) {\n    textColor = displayValue.color;\n  } else if (cellOptions.type === TableCellDisplayMode.ColorBackground) {\n    const mode = cellOptions.mode ?? TableCellBackgroundDisplayMode.Gradient;\n\n    if (mode === TableCellBackgroundDisplayMode.Basic) {\n      textColor = getTextColorForAlphaBackground(displayValue.color!, theme.isDark);\n      bgColor = tinycolor(displayValue.color).toRgbString();\n      bgHoverColor = tinycolor(displayValue.color)\n        .darken(CELL_COLOR_DARKENING_MULTIPLIER * darkeningFactor)\n        .toRgbString();\n    } else if (mode === TableCellBackgroundDisplayMode.Gradient) {\n      const hoverColor = tinycolor(displayValue.color)\n        .darken(CELL_GRADIENT_DARKENING_MULTIPLIER * darkeningFactor)\n        .toRgbString();\n      const bgColor2 = tinycolor(displayValue.color)\n        .darken(CELL_COLOR_DARKENING_MULTIPLIER * darkeningFactor)\n        .spin(CELL_GRADIENT_HUE_ROTATION_DEGREES);\n      textColor = getTextColorForAlphaBackground(displayValue.color!, theme.isDark);\n      bgColor = `linear-gradient(120deg, ${bgColor2.toRgbString()}, ${displayValue.color})`;\n      bgHoverColor = `linear-gradient(120deg, ${bgColor2.toRgbString()}, ${hoverColor})`;\n    }\n  }\n\n  return { textColor, bgColor, bgHoverColor };\n}\n\n/** Extracts numeric pixel value from theme spacing */\nexport const extractPixelValue = (spacing: string | number): number => {\n  return typeof spacing === 'number' ? spacing : parseFloat(spacing) || 0;\n};\n\n/** Converts an RGBA color to hex by blending it with a background color */\nexport const convertRGBAToHex = (backgroundColor: string, rgbaColor: string): string => {\n  const bg = tinycolor(backgroundColor);\n  const rgba = tinycolor(rgbaColor);\n  return tinycolor.mix(bg, rgba, rgba.getAlpha() * 100).toHexString();\n};\n\n/* ------------------------------- Data links ------------------------------- */\n/**\n * @internal\n */\nexport const getCellLinks = (field: Field, rowIdx: number) => {\n  let links: Array<LinkModel<unknown>> | undefined;\n  if (field.getLinks) {\n    links = field.getLinks({\n      valueRowIndex: rowIdx,\n    });\n  }\n\n  if (!links) {\n    return;\n  }\n\n  for (let i = 0; i < links?.length; i++) {\n    if (links[i].onClick) {\n      const origOnClick = links[i].onClick;\n\n      links[i].onClick = (event) => {\n        // Allow opening in new tab\n        if (!(event.ctrlKey || event.metaKey || event.shiftKey)) {\n          event.preventDefault();\n          origOnClick!(event, {\n            field,\n            rowIndex: rowIdx,\n          });\n        }\n      };\n    }\n  }\n\n  return links;\n};\n\n/* ----------------------------- Data grid sorting ---------------------------- */\nexport const handleSort = (\n  columnKey: string,\n  direction: SortDirection,\n  isMultiSort: boolean,\n  setSortColumns: React.Dispatch<React.SetStateAction<readonly SortColumn[]>>,\n  sortColumnsRef: React.MutableRefObject<readonly SortColumn[]>\n) => {\n  let currentSortColumn: SortColumn | undefined;\n\n  const updatedSortColumns = sortColumnsRef.current.filter((column) => {\n    const isCurrentColumn = column.columnKey === columnKey;\n    if (isCurrentColumn) {\n      currentSortColumn = column;\n    }\n    return !isCurrentColumn;\n  });\n\n  // sorted column exists and is descending -> remove it to reset sorting\n  if (currentSortColumn && currentSortColumn.direction === 'DESC') {\n    setSortColumns(updatedSortColumns);\n    sortColumnsRef.current = updatedSortColumns;\n  } else {\n    // new sort column or changed direction\n    if (isMultiSort) {\n      setSortColumns([...updatedSortColumns, { columnKey, direction }]);\n      sortColumnsRef.current = [...updatedSortColumns, { columnKey, direction }];\n    } else {\n      setSortColumns([{ columnKey, direction }]);\n      sortColumnsRef.current = [{ columnKey, direction }];\n    }\n  }\n};\n\n/* ----------------------------- Data grid mapping ---------------------------- */\nexport const frameToRecords = (frame: DataFrame): TableRow[] => {\n  const fnBody = `\n    const rows = Array(frame.length);\n    const values = frame.fields.map(f => f.values);\n    let rowCount = 0;\n    for (let i = 0; i < frame.length; i++) {\n      rows[rowCount] = {\n        __depth: 0,\n        __index: i,\n        ${frame.fields.map((field, fieldIdx) => `${JSON.stringify(getDisplayName(field))}: values[${fieldIdx}][i]`).join(',')}\n      };\n      rowCount += 1;\n      if (rows[rowCount-1]['Nested frames']){\n        const childFrame = rows[rowCount-1]['Nested frames'];\n        rows[rowCount] = {__depth: 1, __index: i, data: childFrame[0]}\n        rowCount += 1;\n      }\n    }\n    return rows;\n  `;\n\n  // Creates a function that converts a DataFrame into an array of TableRows\n  // Uses new Function() for performance as it's faster than creating rows using loops\n  const convert = new Function('frame', fnBody) as unknown as FrameToRowsConverter;\n  return convert(frame);\n};\n\nexport interface MapFrameToGridOptions extends TableNGProps {\n  columnTypes: ColumnTypes;\n  columnWidth: number | string;\n  crossFilterOrder: React.MutableRefObject<string[]>;\n  crossFilterRows: React.MutableRefObject<{ [key: string]: TableRow[] }>;\n  defaultLineHeight: number;\n  defaultRowHeight: number;\n  expandedRows: number[];\n  filter: FilterType;\n  headerCellRefs: React.MutableRefObject<Record<string, HTMLDivElement>>;\n  isCountRowsSet: boolean;\n  ctx: CanvasRenderingContext2D;\n  onSortByChange?: (sortBy: TableSortByFieldState[]) => void;\n  rows: TableRow[];\n  setContextMenuProps: (props: { value: string; top?: number; left?: number; mode?: TableCellInspectorMode }) => void;\n  setFilter: React.Dispatch<React.SetStateAction<FilterType>>;\n  setIsInspecting: (isInspecting: boolean) => void;\n  setSortColumns: React.Dispatch<React.SetStateAction<readonly SortColumn[]>>;\n  sortColumnsRef: React.MutableRefObject<readonly SortColumn[]>;\n  styles: { cell: string; cellWrapped: string; dataGrid: string };\n  textWraps: Record<string, boolean>;\n  theme: GrafanaTheme2;\n  showTypeIcons?: boolean;\n}\n\n/* ----------------------------- Data grid comparator ---------------------------- */\n// The numeric: true option is used to sort numbers as strings correctly. It recognizes numeric sequences\n// within strings and sorts numerically instead of lexicographically.\nconst compare = new Intl.Collator('en', { sensitivity: 'base', numeric: true }).compare;\nexport function getComparator(sortColumnType: FieldType): Comparator {\n  switch (sortColumnType) {\n    // Handle sorting for frame type fields (sparklines)\n    case FieldType.frame:\n      return (a, b) => {\n        // @ts-ignore The values are DataFrameWithValue\n        return (a?.value ?? 0) - (b?.value ?? 0);\n      };\n    case FieldType.time:\n    case FieldType.number:\n    case FieldType.boolean:\n      return (a, b) => {\n        if (a === b) {\n          return 0;\n        }\n        if (a == null) {\n          return -1;\n        }\n        if (b == null) {\n          return 1;\n        }\n        return Number(a) - Number(b);\n      };\n    case FieldType.string:\n    case FieldType.enum:\n    default:\n      return (a, b) => compare(String(a ?? ''), String(b ?? ''));\n  }\n}\n\n/* ---------------------------- Miscellaneous ---------------------------- */\n/**\n * Migrates table cell display mode to new object format.\n *\n * @param displayMode The display mode of the cell\n * @returns TableCellOptions object in the correct format\n * relative to the old display mode.\n */\nexport function migrateTableDisplayModeToCellOptions(displayMode: TableCellDisplayMode): TableCellOptions {\n  switch (displayMode) {\n    // In the case of the gauge we move to a different option\n    case 'basic':\n    case 'gradient-gauge':\n    case 'lcd-gauge':\n      let gaugeMode = BarGaugeDisplayMode.Basic;\n\n      if (displayMode === 'gradient-gauge') {\n        gaugeMode = BarGaugeDisplayMode.Gradient;\n      } else if (displayMode === 'lcd-gauge') {\n        gaugeMode = BarGaugeDisplayMode.Lcd;\n      }\n\n      return {\n        type: TableCellDisplayMode.Gauge,\n        mode: gaugeMode,\n      };\n    // Also true in the case of the color background\n    case 'color-background':\n    case 'color-background-solid':\n      let mode = TableCellBackgroundDisplayMode.Basic;\n\n      // Set the new mode field, somewhat confusingly the\n      // color-background mode is for gradient display\n      if (displayMode === 'color-background') {\n        mode = TableCellBackgroundDisplayMode.Gradient;\n      }\n\n      return {\n        type: TableCellDisplayMode.ColorBackground,\n        mode: mode,\n      };\n    default:\n      return {\n        // @ts-ignore\n        type: displayMode,\n      };\n  }\n}\n\n/** Returns true if the DataFrame contains nested frames */\nexport const getIsNestedTable = (dataFrame: DataFrame): boolean =>\n  dataFrame.fields.some(({ type }) => type === FieldType.nestedFrames);\n\n/** Processes nested table rows */\nexport const processNestedTableRows = (\n  rows: TableRow[],\n  processParents: (parents: TableRow[]) => TableRow[]\n): TableRow[] => {\n  // Separate parent and child rows\n  // Array for parentRows: enables sorting and maintains order for iteration\n  // Map for childRows: provides O(1) lookup by parent index when reconstructing the result\n  const parentRows: TableRow[] = [];\n  const childRows: Map<number, TableRow> = new Map();\n\n  rows.forEach((row) => {\n    if (Number(row.__depth) === 0) {\n      parentRows.push(row);\n    } else {\n      childRows.set(Number(row.__index), row);\n    }\n  });\n\n  // Process parent rows (filter or sort)\n  const processedParents = processParents(parentRows);\n\n  // Reconstruct the result\n  const result: TableRow[] = [];\n  processedParents.forEach((row) => {\n    result.push(row);\n    const childRow = childRows.get(Number(row.__index));\n    if (childRow) {\n      result.push(childRow);\n    }\n  });\n\n  return result;\n};\n\nexport const getDisplayName = (field: Field): string => {\n  return field.state?.displayName ?? field.name;\n};\n"],"names":[],"mappings":"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"}