Table: Optimization - render icons on hover (#76906)

* only render icons on hover
* Table: Optimization - remove plaintext cell wrapper (#76916)

* remove inner wrapper div from plain text cells
* reuse result of typeof value === 'string'
---------

Co-authored-by: Galen <galen.kistler@grafana.com>

---------

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
Galen Kistler 2023-10-23 11:12:40 -05:00 committed by GitHub
parent 3a9eb33b14
commit 88957c7f44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 12 deletions

View File

@ -1,5 +1,5 @@
import { cx } from '@emotion/css'; import { cx } from '@emotion/css';
import React, { ReactElement } from 'react'; import React, { ReactElement, useState } from 'react';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { DisplayValue, formattedValueToString } from '@grafana/data'; import { DisplayValue, formattedValueToString } from '@grafana/data';
@ -24,11 +24,18 @@ export const DefaultCell = (props: TableCellProps) => {
const showFilters = props.onCellFilterAdded && field.config.filterable; const showFilters = props.onCellFilterAdded && field.config.filterable;
const showActions = (showFilters && cell.value !== undefined) || inspectEnabled; const showActions = (showFilters && cell.value !== undefined) || inspectEnabled;
const cellOptions = getCellOptions(field); const cellOptions = getCellOptions(field);
const cellStyle = getCellStyle(tableStyles, cellOptions, displayValue, inspectEnabled);
const hasLinks = Boolean(getCellLinks(field, row)?.length); const hasLinks = Boolean(getCellLinks(field, row)?.length);
const clearButtonStyle = useStyles2(clearLinkButtonStyles); const clearButtonStyle = useStyles2(clearLinkButtonStyles);
const [hover, setHover] = useState(false);
let value: string | ReactElement; let value: string | ReactElement;
const onMouseLeave = () => {
setHover(false);
};
const onMouseEnter = () => {
setHover(true);
};
if (cellOptions.type === TableCellDisplayMode.Custom) { if (cellOptions.type === TableCellDisplayMode.Custom) {
const CustomCellComponent: React.ComponentType<CustomCellRendererProps> = cellOptions.cellComponent; const CustomCellComponent: React.ComponentType<CustomCellRendererProps> = cellOptions.cellComponent;
value = <CustomCellComponent field={field} value={cell.value} rowIndex={row.index} frame={frame} />; value = <CustomCellComponent field={field} value={cell.value} rowIndex={row.index} frame={frame} />;
@ -40,9 +47,22 @@ export const DefaultCell = (props: TableCellProps) => {
} }
} }
const isStringValue = typeof value === 'string';
const cellStyle = getCellStyle(tableStyles, cellOptions, displayValue, inspectEnabled, isStringValue);
if (isStringValue && cellProps.style?.justifyContent === 'flex-end') {
cellProps.style!.textAlign = 'right';
}
return ( return (
<div {...cellProps} className={cellStyle}> <div
{!hasLinks && <div className={tableStyles.cellText}>{value}</div>} {...cellProps}
onMouseEnter={showActions ? onMouseEnter : undefined}
onMouseLeave={showActions ? onMouseLeave : undefined}
className={cellStyle}
>
{!hasLinks && (isStringValue ? `${value}` : <div className={tableStyles.cellText}>{value}</div>)}
{hasLinks && ( {hasLinks && (
<DataLinksContextMenu links={() => getCellLinks(field, row) || []}> <DataLinksContextMenu links={() => getCellLinks(field, row) || []}>
@ -63,7 +83,7 @@ export const DefaultCell = (props: TableCellProps) => {
</DataLinksContextMenu> </DataLinksContextMenu>
)} )}
{showActions && <CellActions {...props} previewMode="text" showFilters={showFilters} />} {hover && showActions && <CellActions {...props} previewMode="text" showFilters={showFilters} />}
</div> </div>
); );
}; };
@ -72,7 +92,8 @@ function getCellStyle(
tableStyles: TableStyles, tableStyles: TableStyles,
cellOptions: TableCellOptions, cellOptions: TableCellOptions,
displayValue: DisplayValue, displayValue: DisplayValue,
disableOverflowOnHover = false disableOverflowOnHover = false,
isStringValue = false
) { ) {
// How much to darken elements depends upon if we're in dark mode // How much to darken elements depends upon if we're in dark mode
const darkeningFactor = tableStyles.theme.isDark ? 1 : -0.7; const darkeningFactor = tableStyles.theme.isDark ? 1 : -0.7;
@ -101,10 +122,14 @@ function getCellStyle(
// If we have definied colors return those styles // If we have definied colors return those styles
// Otherwise we return default styles // Otherwise we return default styles
if (textColor !== undefined || bgColor !== undefined) { if (textColor !== undefined || bgColor !== undefined) {
return tableStyles.buildCellContainerStyle(textColor, bgColor, !disableOverflowOnHover); return tableStyles.buildCellContainerStyle(textColor, bgColor, !disableOverflowOnHover, isStringValue);
} }
return disableOverflowOnHover ? tableStyles.cellContainerNoOverflow : tableStyles.cellContainer; if (isStringValue) {
return disableOverflowOnHover ? tableStyles.cellContainerTextNoOverflow : tableStyles.cellContainerText;
} else {
return disableOverflowOnHover ? tableStyles.cellContainerNoOverflow : tableStyles.cellContainer;
}
} }
function getLinkStyle(tableStyles: TableStyles, cellOptions: TableCellOptions, targetClassName: string | undefined) { function getLinkStyle(tableStyles: TableStyles, cellOptions: TableCellOptions, targetClassName: string | undefined) {

View File

@ -11,14 +11,30 @@ export function useTableStyles(theme: GrafanaTheme2, cellHeightOption: TableCell
const rowHeight = cellHeight + 2; const rowHeight = cellHeight + 2;
const headerHeight = 28; const headerHeight = 28;
const buildCellContainerStyle = (color?: string, background?: string, overflowOnHover?: boolean) => { const buildCellContainerStyle = (
color?: string,
background?: string,
overflowOnHover?: boolean,
asCellText?: boolean
) => {
return css({ return css({
label: overflowOnHover ? 'cellContainerOverflow' : 'cellContainerNoOverflow', label: overflowOnHover ? 'cellContainerOverflow' : 'cellContainerNoOverflow',
padding: `${cellPadding}px`, padding: `${cellPadding}px`,
width: '100%', width: '100%',
// Cell height need to account for row border // Cell height need to account for row border
height: `${rowHeight - 1}px`, height: `${rowHeight - 1}px`,
display: 'flex',
display: asCellText ? 'block' : 'flex',
...(asCellText
? {
overflow: 'hidden',
textOverflow: 'ellipsis',
userSelect: 'text',
whiteSpace: 'nowrap',
}
: {}),
alignItems: 'center', alignItems: 'center',
borderRight: `1px solid ${borderColor}`, borderRight: `1px solid ${borderColor}`,
@ -141,8 +157,11 @@ export function useTableStyles(theme: GrafanaTheme2, cellHeightOption: TableCell
color: theme.colors.text.link, color: theme.colors.text.link,
}, },
}), }),
cellContainer: buildCellContainerStyle(undefined, undefined, true), cellContainerText: buildCellContainerStyle(undefined, undefined, true, true),
cellContainerNoOverflow: buildCellContainerStyle(undefined, undefined, false), cellContainerTextNoOverflow: buildCellContainerStyle(undefined, undefined, false, true),
cellContainer: buildCellContainerStyle(undefined, undefined, true, false),
cellContainerNoOverflow: buildCellContainerStyle(undefined, undefined, false, false),
cellText: css({ cellText: css({
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',