diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json
index e7eecdd6f4c..a8fd784f58c 100644
--- a/packages/grafana-ui/package.json
+++ b/packages/grafana-ui/package.json
@@ -84,6 +84,7 @@
"@types/react-table": "7.7.20",
"calculate-size": "1.1.1",
"classnames": "2.5.1",
+ "clsx": "^2.1.1",
"d3": "7.9.0",
"date-fns": "4.1.0",
"downshift": "^9.0.6",
diff --git a/packages/grafana-ui/src/components/Table/TableNG/Cells/AutoCell.tsx b/packages/grafana-ui/src/components/Table/TableNG/Cells/AutoCell.tsx
index 71293bbc06e..45427f703e8 100644
--- a/packages/grafana-ui/src/components/Table/TableNG/Cells/AutoCell.tsx
+++ b/packages/grafana-ui/src/components/Table/TableNG/Cells/AutoCell.tsx
@@ -1,65 +1,13 @@
-import { css } from '@emotion/css';
-import { Property } from 'csstype';
+import { formattedValueToString } from '@grafana/data';
-import { GrafanaTheme2, formattedValueToString } from '@grafana/data';
-
-import { useStyles2 } from '../../../../themes/ThemeContext';
import { renderSingleLink } from '../../DataLinksActionsTooltip';
-import { TableCellOptions, TableCellDisplayMode } from '../../types';
import { useSingleLink } from '../hooks';
import { AutoCellProps } from '../types';
-export default function AutoCell({ value, field, justifyContent, rowIdx, cellOptions }: AutoCellProps) {
- const styles = useStyles2(getStyles, justifyContent);
-
+export default function AutoCell({ value, field, rowIdx }: AutoCellProps) {
const displayValue = field.display!(value);
const formattedValue = formattedValueToString(displayValue);
const link = useSingleLink(field, rowIdx);
- return (
-
- {link == null ? formattedValue : renderSingleLink(link, formattedValue, getLinkStyle(styles, cellOptions))}
-
- );
+ return link != null ? renderSingleLink(link, formattedValue) : formattedValue;
}
-
-const getLinkStyle = (styles: ReturnType, cellOptions: TableCellOptions) => {
- if (cellOptions.type === TableCellDisplayMode.Auto) {
- return styles.linkCell;
- }
-
- return styles.cellLinkForColoredCell;
-};
-
-const getStyles = (theme: GrafanaTheme2, justifyContent: Property.JustifyContent | undefined) => ({
- cell: css({
- display: 'flex',
- justifyContent: justifyContent,
- a: {
- color: 'inherit',
- },
- }),
- cellLinkForColoredCell: css({
- cursor: 'pointer',
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- userSelect: 'text',
- whiteSpace: 'nowrap',
- fontWeight: theme.typography.fontWeightMedium,
- textDecoration: 'underline',
- }),
- linkCell: css({
- cursor: 'pointer',
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- userSelect: 'text',
- whiteSpace: 'nowrap',
- color: `${theme.colors.text.link} !important`,
- fontWeight: theme.typography.fontWeightMedium,
- paddingRight: theme.spacing(1.5),
- '&:hover': {
- textDecoration: 'underline',
- color: theme.colors.text.link,
- },
- }),
-});
diff --git a/packages/grafana-ui/src/components/Table/TableNG/Cells/DataLinksCell.tsx b/packages/grafana-ui/src/components/Table/TableNG/Cells/DataLinksCell.tsx
index d1612de97c8..a83a623ee88 100644
--- a/packages/grafana-ui/src/components/Table/TableNG/Cells/DataLinksCell.tsx
+++ b/packages/grafana-ui/src/components/Table/TableNG/Cells/DataLinksCell.tsx
@@ -16,7 +16,7 @@ export const DataLinksCell = ({ field, rowIdx }: DataLinksCellProps) => {
{links &&
links.map((link, idx) => {
return !link.href && link.onClick == null ? (
-
+
{link.title}
) : (
@@ -34,25 +34,6 @@ export const DataLinksCell = ({ field, rowIdx }: DataLinksCellProps) => {
const getStyles = (theme: GrafanaTheme2) => ({
linkCell: css({
- cursor: 'pointer',
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- userSelect: 'text',
- whiteSpace: 'nowrap',
- color: theme.colors.text.link,
- fontWeight: theme.typography.fontWeightMedium,
- paddingRight: theme.spacing(1.5),
- a: {
- color: theme.colors.text.link,
- },
- '&:hover': {
- textDecoration: 'underline',
- color: theme.colors.text.link,
- },
- }),
- cellLinkEmpty: css({
- overflow: 'hidden',
- textOverflow: 'ellipsis',
userSelect: 'text',
whiteSpace: 'nowrap',
fontWeight: theme.typography.fontWeightMedium,
diff --git a/packages/grafana-ui/src/components/Table/TableNG/Cells/renderers.tsx b/packages/grafana-ui/src/components/Table/TableNG/Cells/renderers.tsx
index d1bdcdad4a2..fe4bc7e3f0c 100644
--- a/packages/grafana-ui/src/components/Table/TableNG/Cells/renderers.tsx
+++ b/packages/grafana-ui/src/components/Table/TableNG/Cells/renderers.tsx
@@ -29,13 +29,7 @@ const GAUGE_RENDERER: TableCellRenderer = (props) => (
);
const AUTO_RENDERER: TableCellRenderer = (props) => (
-
+
);
const SPARKLINE_RENDERER: TableCellRenderer = (props) => (
diff --git a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx
index 5590dad8e3e..ea128eddafb 100644
--- a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx
+++ b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx
@@ -1,7 +1,8 @@
import 'react-data-grid/lib/styles.css';
-import { css, cx } from '@emotion/css';
+import { css } from '@emotion/css';
+import { clsx } from 'clsx';
import { Property } from 'csstype';
-import { Key, ReactNode, useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
+import { CSSProperties, Key, ReactNode, useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
import {
Cell,
CellRendererProps,
@@ -34,7 +35,7 @@ import { Pagination } from '../../Pagination/Pagination';
import { PanelContext, usePanelContext } from '../../PanelChrome';
import { DataLinksActionsTooltip } from '../DataLinksActionsTooltip';
import { TableCellInspector, TableCellInspectorMode } from '../TableCellInspector';
-import { CellColors, TableCellDisplayMode } from '../types';
+import { TableCellDisplayMode } from '../types';
import { DataLinksActionsTooltipState } from '../utils';
import { HeaderCell } from './Cells/HeaderCell';
@@ -279,6 +280,11 @@ export function TableNG(props: TableNGProps) {
let lastRowIdx = -1;
let _rowHeight = 0;
+ // shared when whole row will be styled by a single cell's color
+ let rowCellStyle: Partial = {
+ color: undefined,
+ background: undefined,
+ };
f.forEach((field, i) => {
const cellOptions = getCellOptions(field);
@@ -304,7 +310,7 @@ export function TableNG(props: TableNGProps) {
const justifyContent = getTextAlign(field);
const footerStyles = getFooterStyles(justifyContent);
const displayName = getDisplayName(field);
- const headerCellClass = getHeaderCellStyles(theme, justifyContent).headerCell;
+ const headerCellClass = getHeaderCellStyles(theme, justifyContent);
const renderFieldCell = getCellRenderer(field, cellOptions);
const cellInspect = isCellInspectEnabled(field);
@@ -314,7 +320,7 @@ export function TableNG(props: TableNGProps) {
// helps us avoid string cx and emotion per-cell
const cellActionClassName = showActions
- ? cx(
+ ? clsx(
'table-cell-actions',
styles.cellActions,
justifyContent === 'flex-end' ? styles.cellActionsEnd : styles.cellActionsStart
@@ -324,41 +330,63 @@ export function TableNG(props: TableNGProps) {
const shouldOverflow = shouldTextOverflow(field);
const shouldWrap = shouldTextWrap(field);
const withTooltip = withDataLinksActionsTooltip(field, cellType);
+ const canBeColorized =
+ cellType === TableCellDisplayMode.ColorBackground || cellType === TableCellDisplayMode.ColorText;
result.colsWithTooltip[displayName] = withTooltip;
+ // get static cell class based on col props
+
+ let cellClass = '';
+
+ switch (cellType) {
+ case TableCellDisplayMode.Auto:
+ case TableCellDisplayMode.ColorBackground:
+ case TableCellDisplayMode.ColorText:
+ case TableCellDisplayMode.DataLinks:
+ cellClass = getCellStyles(theme, justifyContent, shouldWrap, shouldOverflow, withTooltip, canBeColorized);
+ break;
+ }
+
+ // TODO: in future extend this to ensure a non-classic color scheme is set with AutoCell
+
// this fires first
const renderCellRoot = (key: Key, props: CellRendererProps): ReactNode => {
const rowIdx = props.row.__index;
- const value = props.row[props.column.key];
// meh, this should be cached by the renderRow() call?
if (rowIdx !== lastRowIdx) {
_rowHeight = typeof rowHeight === 'function' ? rowHeight(props.row) : rowHeight;
lastRowIdx = rowIdx;
+
+ rowCellStyle.color = undefined;
+ rowCellStyle.background = undefined;
+
+ // generate shared styles for whole row
+ if (applyToRowBgFn != null) {
+ let { textColor, bgColor } = applyToRowBgFn(rowIdx);
+ rowCellStyle.color = textColor;
+ rowCellStyle.background = bgColor;
+ }
}
- let colors: CellColors;
+ let style: CSSProperties | undefined;
- if (applyToRowBgFn != null) {
- colors = applyToRowBgFn(props.rowIdx);
- } else if (cellType !== TableCellDisplayMode.Auto) {
+ if (rowCellStyle.color != null || rowCellStyle.background != null) {
+ style = rowCellStyle;
+ }
+ // apply background for cell types which can have a background and have proper
+ else if (canBeColorized) {
+ const value = props.row[props.column.key];
const displayValue = field.display!(value); // this fires here to get colors, then again to get rendered value?
- colors = getCellColors(theme, cellOptions, displayValue);
- } else {
- colors = {};
+ let { textColor, bgColor } = getCellColors(theme, cellOptions, displayValue);
+ style = {
+ color: textColor,
+ background: bgColor,
+ };
}
- const cellStyle = getCellStyles(theme, field, _rowHeight, shouldWrap, shouldOverflow, withTooltip, colors);
-
- return (
- |
- );
+ return | ; // TODO: remove expensive concat
};
result.cellRootRenderers[displayName] = renderCellRoot;
@@ -518,8 +546,8 @@ export function TableNG(props: TableNGProps) {
return (
{...commonDataGridProps}
- className={cx(styles.grid, styles.gridNested)}
- headerRowClass={cx(styles.headerRow, { [styles.displayNone]: !hasNestedHeaders })}
+ className={clsx(styles.grid, styles.gridNested)}
+ headerRowClass={clsx(styles.headerRow, { [styles.displayNone]: !hasNestedHeaders })}
headerRowHeight={hasNestedHeaders ? defaultHeaderHeight : 0}
columns={nestedColumns}
rows={expandedRecords}
@@ -584,7 +612,7 @@ export function TableNG(props: TableNGProps) {
className={styles.grid}
columns={structureRevColumns}
rows={paginatedRows}
- headerRowClass={cx(styles.headerRow, { [styles.displayNone]: noHeader })}
+ headerRowClass={clsx(styles.headerRow, { [styles.displayNone]: noHeader })}
headerRowHeight={headerHeight}
onCellClick={({ column, row }, { clientX, clientY, preventGridDefault }) => {
// Note: could be column.field; JS says yes, but TS says no!
@@ -836,8 +864,8 @@ const getFooterStyles = (justifyContent: Property.JustifyContent) => ({
}),
});
-const getHeaderCellStyles = (theme: GrafanaTheme2, justifyContent: Property.JustifyContent) => ({
- headerCell: css({
+const getHeaderCellStyles = (theme: GrafanaTheme2, justifyContent: Property.JustifyContent) =>
+ css({
display: 'flex',
gap: theme.spacing(0.5),
zIndex: theme.zIndex.tooltip - 1,
@@ -847,45 +875,56 @@ const getHeaderCellStyles = (theme: GrafanaTheme2, justifyContent: Property.Just
'&:last-child': {
borderInlineEnd: 'none',
},
- }),
-});
+ });
const getCellStyles = (
theme: GrafanaTheme2,
- field: Field,
- rowHeight: number,
+ justifyContent: Property.JustifyContent,
shouldWrap: boolean,
shouldOverflow: boolean,
hasTooltip: boolean,
- colors: CellColors
-) => {
- return {
- cell: css({
- textOverflow: 'initial',
- background: colors.bgColor ?? 'inherit',
- alignContent: 'center',
- justifyContent: getTextAlign(field),
- paddingInline: TABLE.CELL_PADDING,
- height: '100%',
- minHeight: rowHeight, // min height interacts with the fit-content property on the overflow container
- ...(shouldWrap && { whiteSpace: 'pre-line' }),
- ...(hasTooltip && { cursor: 'pointer' }),
- '&:last-child': {
- borderInlineEnd: 'none',
+ isColorized: boolean
+) =>
+ css({
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent,
+ paddingInline: TABLE.CELL_PADDING,
+ minHeight: '100%',
+ backgroundClip: 'padding-box !important', // helps when cells have a bg color
+ ...(shouldWrap && { whiteSpace: 'pre-line' }),
+ ...(hasTooltip && { cursor: 'pointer' }),
+
+ '&:last-child': {
+ borderInlineEnd: 'none',
+ },
+
+ // should omit if no cell actions, and no shouldOverflow
+ '&:hover': {
+ '.table-cell-actions': {
+ display: 'flex',
},
- '&:hover': {
- background: colors.bgHoverColor,
- '.table-cell-actions': {
- display: 'flex',
- },
- ...(shouldOverflow && {
- zIndex: theme.zIndex.tooltip - 2,
- whiteSpace: 'pre-line',
- height: 'fit-content',
- minWidth: 'fit-content',
- paddingBlock: (rowHeight - TABLE.LINE_HEIGHT) / 2 - 1,
- }),
- },
- }),
- };
-};
+ ...(shouldOverflow && {
+ zIndex: theme.zIndex.tooltip - 2,
+ whiteSpace: 'pre-line',
+ height: 'fit-content',
+ minWidth: 'fit-content',
+ }),
+ },
+
+ [hasTooltip ? '&' : 'a']: {
+ cursor: 'pointer',
+ ...(isColorized
+ ? {
+ color: 'inherit',
+ textDecoration: 'underline',
+ }
+ : {
+ color: theme.colors.text.link,
+ textDecoration: 'none',
+ '&:hover': {
+ textDecoration: 'underline',
+ },
+ }),
+ },
+ });
diff --git a/packages/grafana-ui/src/components/Table/TableNG/types.ts b/packages/grafana-ui/src/components/Table/TableNG/types.ts
index 65d40d3c4d1..742d495b806 100644
--- a/packages/grafana-ui/src/components/Table/TableNG/types.ts
+++ b/packages/grafana-ui/src/components/Table/TableNG/types.ts
@@ -246,9 +246,7 @@ export interface CellColors {
export interface AutoCellProps {
field: Field;
value: TableCellValue;
- justifyContent: Property.JustifyContent;
rowIdx: number;
- cellOptions: TableCellOptions;
}
export interface ActionCellProps {
diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts
index 302ef067224..59e58541744 100644
--- a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts
+++ b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts
@@ -188,7 +188,6 @@ describe('TableNG utils', () => {
const colors = getCellColors(theme, field, displayValue);
expect(colors.bgColor).toBe('rgb(255, 0, 0)');
expect(colors.textColor).toBe('rgb(247, 248, 250)');
- expect(colors.bgHoverColor).toBe('rgb(255, 36, 36)');
});
it('should handle color background gradient mode', () => {
@@ -206,7 +205,6 @@ describe('TableNG utils', () => {
const colors = getCellColors(theme, field, displayValue);
expect(colors.bgColor).toBe('linear-gradient(120deg, rgb(255, 54, 36), #ff0000)');
expect(colors.textColor).toBe('rgb(247, 248, 250)');
- expect(colors.bgHoverColor).toBe('linear-gradient(120deg, rgb(255, 54, 36), rgb(255, 54, 54))');
});
});
diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.ts
index a99ec3edab7..1cd6d279856 100644
--- a/packages/grafana-ui/src/components/Table/TableNG/utils.ts
+++ b/packages/grafana-ui/src/components/Table/TableNG/utils.ts
@@ -230,7 +230,6 @@ export function getAlignmentFactor(
/* ------------------------- Cell color calculation ------------------------- */
const CELL_COLOR_DARKENING_MULTIPLIER = 10;
-const CELL_GRADIENT_DARKENING_MULTIPLIER = 15;
const CELL_GRADIENT_HUE_ROTATION_DEGREES = 5;
/**
@@ -248,7 +247,7 @@ export function getCellColors(
// Setup color variables
let textColor: string | undefined = undefined;
let bgColor: string | undefined = undefined;
- let bgHoverColor: string | undefined = undefined;
+ // let bgHoverColor: string | undefined = undefined;
if (cellOptions.type === TableCellDisplayMode.ColorText) {
textColor = displayValue.color;
@@ -258,23 +257,23 @@ export function getCellColors(
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();
+ // 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 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})`;
+ // bgHoverColor = `linear-gradient(120deg, ${bgColor2.toRgbString()}, ${hoverColor})`;
}
}
- return { textColor, bgColor, bgHoverColor };
+ return { textColor, bgColor };
}
/**
diff --git a/yarn.lock b/yarn.lock
index 3b7ead9baf2..cdd4a49083c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3747,6 +3747,7 @@ __metadata:
calculate-size: "npm:1.1.1"
chance: "npm:^1.1.13"
classnames: "npm:2.5.1"
+ clsx: "npm:^2.1.1"
common-tags: "npm:1.8.2"
core-js: "npm:3.40.0"
css-loader: "npm:7.1.2"