Files
grafana/packages/grafana-ui/src/components/Table/DefaultCell.tsx
Kyle Cunningham 80e7f54166 Table Panel: Refactor Cell Options to Allow for Options per Cell Type (#59363)
* Update table data structure schema.

* Update table panel configuration options for new structure

* Fix TS errors from refactor

* Separate background and gauge display modes

* Remove the now used Bar Gauge display from the mud

* Fix types up

* Reorganize data structures

* Fix type issues.

* Start stubbing necessary code.

* Continue implementing option refactor

* Change category for cell type selection.

* Consolidate cell options

* Fix various typing issues

* Clean up dead code

* Stub handling display mode changes

* Make subOption editor dynamic

* Setup interface for sub-option editor props

* Remove unused imports

* Remove console.log call

* Persist display mode changes, stub sub options change, update comments.

* Make sure updates from cells are persisted

* Persist sub-option changes

* Update BarGaugeCell to take into account new settings.

* Add deprecated field back

* Remove unecessary options in configuration

* Update default cell to accept new settings

* Make sure color text display works

* Add deprecated property notice

* Use constant as opposed to string

* Make sure we name globally namespaced things uniquely

* Update to use unique name

* Use union type with discriminator.

* Simplify types and operation

* Update type definitons

* Update types

* Update property names in cells

* Remove React.FC usage

* Update option editor signature

* Update options structure

* Change variable name

* Fix "Color Text" display

* Remove debug statement

* Make sure we remain backwards compatible with display mode.

* Add migration for configuration.

* Export BarGaugeDisplayMode from grafana-ui

* Update import

* Fix bar gauge and dashboard migrator tests

* Fix potential undefined references causing test failures

* Fix another potential reference error in DefaultCell

* Try to fix breaking change detection.

* Cache setting changes

* Make sure we return with onChange invocation

* Fixed migrating overrides

* Fix a number of review comments

* Simplify option editors

* Fix unused imports

* Fill out comments for types

* Actually use defaultPanelConfig for editor default

* Move TableCellEditorProps alongside TableCellOptionEditor

* Update docs for table panel

* Also make sure we remove TableCellEditorProps from model file

* Stub migration tests

* Add tests for default config migration

* Add basic overrides test

* Flesh out tests a bit more

* Add inspect to same category as cell editor

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-01-12 18:42:57 +07:00

123 lines
4.8 KiB
TypeScript

import { cx } from '@emotion/css';
import React, { FC, ReactElement } from 'react';
import tinycolor from 'tinycolor2';
import { DisplayValue, Field, formattedValueToString } from '@grafana/data';
import { TableCellBackgroundDisplayMode } from '@grafana/schema';
import { getCellLinks, getTextColorForAlphaBackground } from '../../utils';
import { DataLinksContextMenu } from '../DataLinks/DataLinksContextMenu';
import { CellActions } from './CellActions';
import { TableStyles } from './styles';
import { TableCellDisplayMode, TableCellProps, TableFieldOptions } from './types';
export const DefaultCell: FC<TableCellProps> = (props) => {
const { field, cell, tableStyles, row, cellProps } = props;
const inspectEnabled = Boolean((field.config.custom as TableFieldOptions)?.inspect);
const displayValue = field.display!(cell.value);
let value: string | ReactElement;
if (React.isValidElement(cell.value)) {
value = cell.value;
} else {
value = formattedValueToString(displayValue);
}
const showFilters = field.config.filterable;
const showActions = (showFilters && cell.value !== undefined) || inspectEnabled;
const cellStyle = getCellStyle(tableStyles, field, displayValue, inspectEnabled);
const hasLinks = Boolean(getCellLinks(field, row)?.length);
return (
<div {...cellProps} className={cellStyle}>
{!hasLinks && <div className={tableStyles.cellText}>{value}</div>}
{hasLinks && (
<DataLinksContextMenu links={() => getCellLinks(field, row) || []}>
{(api) => {
return (
<div onClick={api.openMenu} className={getLinkStyle(tableStyles, field, api.targetClassName)}>
{value}
</div>
);
}}
</DataLinksContextMenu>
)}
{showActions && <CellActions {...props} previewMode="text" />}
</div>
);
};
function getCellStyle(
tableStyles: TableStyles,
field: Field,
displayValue: DisplayValue,
disableOverflowOnHover = false
) {
// How much to darken elements depends upon if we're in dark mode
const darkeningFactor = tableStyles.theme.isDark ? 1 : -0.7;
// See if we're using deprecated settings
const usingDeprecatedSettings = field.config.custom?.displayMode !== undefined;
// Setup color variables
let textColor: string | undefined = undefined;
let bgColor: string | undefined = undefined;
// Set colors using deprecated settings format
if (usingDeprecatedSettings) {
if (field.config.custom?.displayMode === TableCellDisplayMode.ColorText) {
textColor = displayValue.color;
} else if (field.config.custom?.displayMode === TableCellDisplayMode.ColorBackground) {
textColor = getTextColorForAlphaBackground(displayValue.color!, tableStyles.theme.isDark);
bgColor = tinycolor(displayValue.color).toRgbString();
} else if (
field.config.custom?.displayMode === TableCellDisplayMode.ColorBackground &&
field.config.custom?.backgroundDisplayMode === TableCellBackgroundDisplayMode.Gradient
) {
const bgColor2 = tinycolor(displayValue.color)
.darken(10 * darkeningFactor)
.spin(5);
textColor = getTextColorForAlphaBackground(displayValue.color!, tableStyles.theme.isDark);
bgColor = `linear-gradient(120deg, ${bgColor2.toRgbString()}, ${displayValue.color})`;
}
}
// Set colors using updated sub-options format
else {
const cellDisplayMode = field.config.custom?.cellOptions?.mode;
const cellDisplayType = field.config.custom?.cellOptions?.type;
if (cellDisplayType === TableCellDisplayMode.ColorText) {
textColor = displayValue.color;
} else if (cellDisplayMode === TableCellBackgroundDisplayMode.Basic) {
textColor = getTextColorForAlphaBackground(displayValue.color!, tableStyles.theme.isDark);
bgColor = tinycolor(displayValue.color).toRgbString();
} else if (cellDisplayMode === TableCellBackgroundDisplayMode.Gradient) {
const bgColor2 = tinycolor(displayValue.color)
.darken(10 * darkeningFactor)
.spin(5);
textColor = getTextColorForAlphaBackground(displayValue.color!, tableStyles.theme.isDark);
bgColor = `linear-gradient(120deg, ${bgColor2.toRgbString()}, ${displayValue.color})`;
}
}
// If we have definied colors return those styles
// Otherwise we return default styles
if (textColor !== undefined || bgColor !== undefined) {
return tableStyles.buildCellContainerStyle(textColor, bgColor, !disableOverflowOnHover);
}
return disableOverflowOnHover ? tableStyles.cellContainerNoOverflow : tableStyles.cellContainer;
}
function getLinkStyle(tableStyles: TableStyles, field: Field, targetClassName: string | undefined) {
if (field.config.custom?.displayMode === TableCellDisplayMode.Auto) {
return cx(tableStyles.cellLink, targetClassName);
}
return cx(tableStyles.cellLinkForColoredCell, targetClassName);
}