UNPKG

@grafana/ui

Version:
362 lines (359 loc) • 13.9 kB
import tinycolor from 'tinycolor2'; import { FieldType, formattedValueToString } from '@grafana/data'; import { TableCellDisplayMode, BarGaugeDisplayMode, TableCellBackgroundDisplayMode, TableCellHeight } from '@grafana/schema'; import { getTextColorForAlphaBackground } from '../../../utils/colors.mjs'; import { TABLE, COLUMN } from './constants.mjs'; function getDefaultRowHeight(theme, cellHeight) { const bodyFontSize = theme.typography.fontSize; const lineHeight = theme.typography.body.lineHeight; switch (cellHeight) { case TableCellHeight.Sm: return 36; case TableCellHeight.Md: return 42; case TableCellHeight.Lg: return TABLE.MAX_CELL_HEIGHT; } return TABLE.CELL_PADDING * 2 + bodyFontSize * lineHeight; } function isCellInspectEnabled(field) { var _a, _b, _c; return (_c = (_b = (_a = field.config) == null ? void 0 : _a.custom) == null ? void 0 : _b.inspect) != null ? _c : false; } function shouldTextWrap(field) { const cellOptions = getCellOptions(field); return Boolean(cellOptions == null ? void 0 : cellOptions.wrapText); } const spaceRegex = /[\s-]/; function getMaxWrapCell(fields, rowIdx, { colWidths, avgCharWidth, wrappedColIdxs }) { let maxLines = 1; let maxLinesIdx = -1; let maxLinesText = ""; for (let i = 0; i < colWidths.length; i++) { if (wrappedColIdxs[i]) { const field = fields[i]; const cellTextRaw = rowIdx === -1 ? getDisplayName(field) : field.values[rowIdx]; if (cellTextRaw != null) { const cellText = String(cellTextRaw); if (spaceRegex.test(cellText)) { const charsPerLine = colWidths[i] / avgCharWidth; const approxLines = cellText.length / charsPerLine; if (approxLines > maxLines) { maxLines = approxLines; maxLinesIdx = i; maxLinesText = cellText; } } } } } return { text: maxLinesText, idx: maxLinesIdx, numLines: maxLines }; } function shouldTextOverflow(field) { return field.type === FieldType.string && // Tech debt: Technically image cells are of type string, which is misleading (kinda?) // so we need to ensure we don't apply overflow hover states for type image getCellOptions(field).type !== TableCellDisplayMode.Image && !shouldTextWrap(field) && !isCellInspectEnabled(field); } function getTextAlign(field) { if (!field) { return "flex-start"; } if (field.config.custom) { const custom = field.config.custom; switch (custom.align) { case "right": return "flex-end"; case "left": return "flex-start"; case "center": return "center"; } } if (field.type === FieldType.number) { return "flex-end"; } return "flex-start"; } const DEFAULT_CELL_OPTIONS = { type: TableCellDisplayMode.Auto }; function getCellOptions(field) { var _a, _b, _c, _d; if ((_a = field.config.custom) == null ? void 0 : _a.displayMode) { return migrateTableDisplayModeToCellOptions((_b = field.config.custom) == null ? void 0 : _b.displayMode); } return (_d = (_c = field.config.custom) == null ? void 0 : _c.cellOptions) != null ? _d : DEFAULT_CELL_OPTIONS; } function getAlignmentFactor(field, displayValue, rowIndex) { var _a, _b, _c; let alignmentFactor = (_a = field.state) == null ? void 0 : _a.alignmentFactors; if (alignmentFactor) { if (formattedValueToString(alignmentFactor).length < formattedValueToString(displayValue).length) { alignmentFactor = { ...displayValue }; field.state.alignmentFactors = alignmentFactor; } return alignmentFactor; } else { alignmentFactor = { ...displayValue }; const maxIndex = Math.min(field.values.length, rowIndex + 1e3); for (let i = rowIndex + 1; i < maxIndex; i++) { const nextDisplayValue = (_c = (_b = field.display) == null ? void 0 : _b.call(field, field.values[i])) != null ? _c : field.values[i]; if (formattedValueToString(alignmentFactor).length > formattedValueToString(nextDisplayValue).length) { alignmentFactor.text = displayValue.text; } } if (field.state) { field.state.alignmentFactors = alignmentFactor; } else { field.state = { alignmentFactors: alignmentFactor }; } return alignmentFactor; } } const CELL_COLOR_DARKENING_MULTIPLIER = 10; const CELL_GRADIENT_DARKENING_MULTIPLIER = 15; const CELL_GRADIENT_HUE_ROTATION_DEGREES = 5; function getCellColors(theme, cellOptions, displayValue) { var _a; const darkeningFactor = theme.isDark ? 1 : -0.7; let textColor = void 0; let bgColor = void 0; let bgHoverColor = void 0; if (cellOptions.type === TableCellDisplayMode.ColorText) { textColor = displayValue.color; } else if (cellOptions.type === TableCellDisplayMode.ColorBackground) { const mode = (_a = cellOptions.mode) != null ? _a : TableCellBackgroundDisplayMode.Gradient; if (mode === TableCellBackgroundDisplayMode.Basic) { textColor = getTextColorForAlphaBackground(displayValue.color, theme.isDark); bgColor = tinycolor(displayValue.color).toRgbString(); bgHoverColor = tinycolor(displayValue.color).darken(CELL_COLOR_DARKENING_MULTIPLIER * darkeningFactor).toRgbString(); } else if (mode === TableCellBackgroundDisplayMode.Gradient) { const hoverColor = tinycolor(displayValue.color).darken(CELL_GRADIENT_DARKENING_MULTIPLIER * darkeningFactor).toRgbString(); const bgColor2 = tinycolor(displayValue.color).darken(CELL_COLOR_DARKENING_MULTIPLIER * darkeningFactor).spin(CELL_GRADIENT_HUE_ROTATION_DEGREES); textColor = getTextColorForAlphaBackground(displayValue.color, theme.isDark); bgColor = `linear-gradient(120deg, ${bgColor2.toRgbString()}, ${displayValue.color})`; bgHoverColor = `linear-gradient(120deg, ${bgColor2.toRgbString()}, ${hoverColor})`; } } return { textColor, bgColor, bgHoverColor }; } const extractPixelValue = (spacing) => { return typeof spacing === "number" ? spacing : parseFloat(spacing) || 0; }; const getCellLinks = (field, rowIdx) => { let links; if (field.getLinks) { links = field.getLinks({ valueRowIndex: rowIdx }); } if (!links) { return; } for (let i = 0; i < (links == null ? void 0 : links.length); i++) { if (links[i].onClick) { const origOnClick = links[i].onClick; links[i].onClick = (event) => { if (!(event.ctrlKey || event.metaKey || event.shiftKey)) { event.preventDefault(); origOnClick(event, { field, rowIndex: rowIdx }); } }; } } return links.filter((link) => link.href || link.onClick != null); }; function applySort(rows, fields, sortColumns, columnTypes = getColumnTypes(fields), hasNestedFrames = getIsNestedTable(fields)) { if (sortColumns.length === 0) { return rows; } const compareRows = (a, b) => { let result = 0; for (let i = 0; i < sortColumns.length; i++) { const { columnKey, direction } = sortColumns[i]; const compare2 = getComparator(columnTypes[columnKey]); const sortDir = direction === "ASC" ? 1 : -1; result = sortDir * compare2(a[columnKey], b[columnKey]); if (result !== 0) { break; } } return result; }; if (hasNestedFrames) { return processNestedTableRows(rows, (parents) => [...parents].sort(compareRows)); } return [...rows].sort(compareRows); } const frameToRecords = (frame) => { const fnBody = ` const rows = Array(frame.length); const values = frame.fields.map(f => f.values); let rowCount = 0; for (let i = 0; i < frame.length; i++) { rows[rowCount] = { __depth: 0, __index: i, ${frame.fields.map((field, fieldIdx) => `${JSON.stringify(getDisplayName(field))}: values[${fieldIdx}][i]`).join(",")} }; rowCount += 1; if (rows[rowCount-1]['__nestedFrames']){ const childFrame = rows[rowCount-1]['__nestedFrames']; rows[rowCount] = {__depth: 1, __index: i, data: childFrame[0]} rowCount += 1; } } return rows; `; const convert = new Function("frame", fnBody); return convert(frame); }; const compare = new Intl.Collator("en", { sensitivity: "base", numeric: true }).compare; const strCompare = (a, b) => compare(String(a != null ? a : ""), String(b != null ? b : "")); const numCompare = (a, b) => { if (a === b) { return 0; } if (a == null) { return -1; } if (b == null) { return 1; } return Number(a) - Number(b); }; const frameCompare = (a, b) => { var _a, _b; return ((_a = a == null ? void 0 : a.value) != null ? _a : 0) - ((_b = b == null ? void 0 : b.value) != null ? _b : 0); }; function getComparator(sortColumnType) { switch (sortColumnType) { // Handle sorting for frame type fields (sparklines) case FieldType.frame: return frameCompare; case FieldType.time: case FieldType.number: case FieldType.boolean: return numCompare; case FieldType.string: case FieldType.enum: default: return strCompare; } } const TABLE_CELL_GAUGE_DISPLAY_MODES_TO_DISPLAY_MODES = { [TableCellDisplayMode.BasicGauge]: BarGaugeDisplayMode.Basic, [TableCellDisplayMode.GradientGauge]: BarGaugeDisplayMode.Gradient, [TableCellDisplayMode.LcdGauge]: BarGaugeDisplayMode.Lcd }; const TABLE_CELL_COLOR_BACKGROUND_DISPLAY_MODES_TO_DISPLAY_MODES = { [TableCellDisplayMode.ColorBackground]: TableCellBackgroundDisplayMode.Gradient, [TableCellDisplayMode.ColorBackgroundSolid]: TableCellBackgroundDisplayMode.Basic }; function migrateTableDisplayModeToCellOptions(displayMode) { switch (displayMode) { // In the case of the gauge we move to a different option case TableCellDisplayMode.BasicGauge: case TableCellDisplayMode.GradientGauge: case TableCellDisplayMode.LcdGauge: return { type: TableCellDisplayMode.Gauge, mode: TABLE_CELL_GAUGE_DISPLAY_MODES_TO_DISPLAY_MODES[displayMode] }; // Also true in the case of the color background case TableCellDisplayMode.ColorBackground: case TableCellDisplayMode.ColorBackgroundSolid: return { type: TableCellDisplayMode.ColorBackground, mode: TABLE_CELL_COLOR_BACKGROUND_DISPLAY_MODES_TO_DISPLAY_MODES[displayMode] }; // catching a nonsense case: `displayMode`: 'custom' should pre-date the CustomCell. // if it doesn't, we need to just nope out and return an auto cell. case TableCellDisplayMode.Custom: return { type: TableCellDisplayMode.Auto }; default: return { type: displayMode }; } } const getIsNestedTable = (fields) => fields.some(({ type }) => type === FieldType.nestedFrames); const processNestedTableRows = (rows, processParents) => { const parentRows = []; const childRows = /* @__PURE__ */ new Map(); for (const row of rows) { if (Number(row.__depth) === 0) { parentRows.push(row); } else { childRows.set(Number(row.__index), row); } } const processedParents = processParents(parentRows); const result = []; processedParents.forEach((row) => { result.push(row); const childRow = childRows.get(Number(row.__index)); if (childRow) { result.push(childRow); } }); return result; }; const getDisplayName = (field) => { var _a, _b; return (_b = (_a = field.state) == null ? void 0 : _a.displayName) != null ? _b : field.name; }; function getVisibleFields(fields) { return fields.filter((field) => { var _a; return field.type !== FieldType.nestedFrames && ((_a = field.config.custom) == null ? void 0 : _a.hidden) !== true; }); } function getColumnTypes(fields) { return fields.reduce((acc, field) => { var _a, _b, _c; switch (field.type) { case FieldType.nestedFrames: return { ...acc, ...getColumnTypes((_c = (_b = (_a = field.values[0]) == null ? void 0 : _a[0]) == null ? void 0 : _b.fields) != null ? _c : []) }; default: return { ...acc, [getDisplayName(field)]: field.type }; } }, {}); } function computeColWidths(fields, availWidth) { let autoCount = 0; let definedWidth = 0; return fields.map((field) => { var _a, _b; const width = (_b = (_a = field.config.custom) == null ? void 0 : _a.width) != null ? _b : 0; if (width === 0) { autoCount++; } else { definedWidth += width; } return width; }).map( (width, i) => { var _a, _b; return width || Math.max((_b = (_a = fields[i].config.custom) == null ? void 0 : _a.minWidth) != null ? _b : COLUMN.DEFAULT_WIDTH, (availWidth - definedWidth) / autoCount); } ); } function getApplyToRowBgFn(fields, theme) { for (const field of fields) { const cellOptions = getCellOptions(field); const fieldDisplay = field.display; if (fieldDisplay !== void 0 && cellOptions.type === TableCellDisplayMode.ColorBackground && cellOptions.applyToRow === true) { return (rowIndex) => getCellColors(theme, cellOptions, fieldDisplay(field.values[rowIndex])); } } } function withDataLinksActionsTooltip(field, cellType) { var _a, _b, _c, _d; return cellType !== TableCellDisplayMode.DataLinks && cellType !== TableCellDisplayMode.Actions && ((_b = (_a = field.config.links) == null ? void 0 : _a.length) != null ? _b : 0) + ((_d = (_c = field.config.actions) == null ? void 0 : _c.length) != null ? _d : 0) > 1; } export { applySort, computeColWidths, extractPixelValue, frameToRecords, getAlignmentFactor, getApplyToRowBgFn, getCellColors, getCellLinks, getCellOptions, getColumnTypes, getComparator, getDefaultRowHeight, getDisplayName, getIsNestedTable, getMaxWrapCell, getTextAlign, getVisibleFields, isCellInspectEnabled, migrateTableDisplayModeToCellOptions, processNestedTableRows, shouldTextOverflow, shouldTextWrap, withDataLinksActionsTooltip }; //# sourceMappingURL=utils.mjs.map