TableNG [Bug Bash]: Cell inspect and filter on the field level (#103004)

* fix: cell inspect + filter at the field level, not defaults

* chore: defensive against missing custom config

* chore: reconfigure tests

* hide inspect block if nothing to show

---------

Co-authored-by: Adela Almasan <adela.almasan@grafana.com>
Co-authored-by: Ihor Yeromin <yeryomin.igor@gmail.com>
This commit is contained in:
Alex Spencer 2025-04-03 08:28:19 -06:00 committed by GitHub
parent 413378dd3a
commit d6ec8ab8b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 50 additions and 27 deletions

View File

@ -20,7 +20,6 @@ interface HeaderCellProps {
justifyContent: Property.JustifyContent; justifyContent: Property.JustifyContent;
filter: FilterType; filter: FilterType;
setFilter: React.Dispatch<React.SetStateAction<FilterType>>; setFilter: React.Dispatch<React.SetStateAction<FilterType>>;
filterable: boolean;
onColumnResize?: TableColumnResizeActionCallback; onColumnResize?: TableColumnResizeActionCallback;
headerCellRefs: React.MutableRefObject<Record<string, HTMLDivElement>>; headerCellRefs: React.MutableRefObject<Record<string, HTMLDivElement>>;
crossFilterOrder: React.MutableRefObject<string[]>; crossFilterOrder: React.MutableRefObject<string[]>;
@ -37,7 +36,6 @@ const HeaderCell: React.FC<HeaderCellProps> = ({
justifyContent, justifyContent,
filter, filter,
setFilter, setFilter,
filterable,
onColumnResize, onColumnResize,
headerCellRefs, headerCellRefs,
crossFilterOrder, crossFilterOrder,
@ -47,6 +45,8 @@ const HeaderCell: React.FC<HeaderCellProps> = ({
const styles = useStyles2(getStyles, justifyContent); const styles = useStyles2(getStyles, justifyContent);
const headerRef = useRef<HTMLDivElement>(null); const headerRef = useRef<HTMLDivElement>(null);
const filterable = field.config?.custom?.filterable ?? false;
let isColumnFilterable = filterable; let isColumnFilterable = filterable;
if (field.config.custom?.filterable !== filterable) { if (field.config.custom?.filterable !== filterable) {
isColumnFilterable = field.config.custom?.filterable || false; isColumnFilterable = field.config.custom?.filterable || false;

View File

@ -32,12 +32,13 @@ export function TableCellNG(props: TableCellNGProps) {
shouldTextOverflow, shouldTextOverflow,
setIsInspecting, setIsInspecting,
setContextMenuProps, setContextMenuProps,
cellInspect,
getActions, getActions,
rowBg, rowBg,
onCellFilterAdded, onCellFilterAdded,
} = props; } = props;
const cellInspect = field.config?.custom?.inspect ?? false;
const { config: fieldConfig } = field; const { config: fieldConfig } = field;
const defaultCellOptions: TableAutoCellOptions = { type: TableCellDisplayMode.Auto }; const defaultCellOptions: TableAutoCellOptions = { type: TableCellDisplayMode.Auto };
const cellOptions = fieldConfig.custom?.cellOptions ?? defaultCellOptions; const cellOptions = fieldConfig.custom?.cellOptions ?? defaultCellOptions;
@ -148,6 +149,7 @@ export function TableCellNG(props: TableCellNGProps) {
tableCellDiv?.style.setProperty('z-index', String(theme.zIndex.tooltip)); tableCellDiv?.style.setProperty('z-index', String(theme.zIndex.tooltip));
tableCellDiv?.style.setProperty('white-space', 'normal'); tableCellDiv?.style.setProperty('white-space', 'normal');
tableCellDiv?.style.setProperty('min-height', `${height}px`); tableCellDiv?.style.setProperty('min-height', `${height}px`);
tableCellDiv?.style.setProperty('width', `${divWidth}px`);
} }
}; };
@ -179,7 +181,7 @@ export function TableCellNG(props: TableCellNGProps) {
return ( return (
<div ref={divWidthRef} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} className={styles.cell}> <div ref={divWidthRef} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} className={styles.cell}>
{cell} {cell}
{isHovered && ( {isHovered && (cellInspect || showFilters) && (
<div className={styles.cellActions}> <div className={styles.cellActions}>
{cellInspect && ( {cellInspect && (
<IconButton <IconButton

View File

@ -1249,24 +1249,26 @@ describe('TableNG', () => {
describe('Cell inspection', () => { describe('Cell inspection', () => {
it('shows inspect icon when hovering over a cell with inspection enabled', () => { it('shows inspect icon when hovering over a cell with inspection enabled', () => {
const fieldConfig = { const inspectDataFrame = {
defaults: { ...createBasicDataFrame(),
fields: createBasicDataFrame().fields.map((field) => ({
...field,
config: {
...field.config,
custom: { custom: {
...field.config.custom,
inspect: true, inspect: true,
cellOptions: {
wrapText: false,
}, },
}, },
}, })),
overrides: [],
}; };
// Render the component // Render the component
const { container } = render( const { container } = render(
<TableNG <TableNG
enableVirtualization={false} enableVirtualization={false}
fieldConfig={fieldConfig} // fieldConfig={inspectDataFrame.fields[0].config}
data={createBasicDataFrame()} data={inspectDataFrame}
width={800} width={800}
height={600} height={600}
/> />

View File

@ -610,7 +610,6 @@ export function mapFrameToDataGrid({
sortColumnsRef, sortColumnsRef,
styles, styles,
textWrap, textWrap,
fieldConfig,
theme, theme,
timeRange, timeRange,
getActions, getActions,
@ -621,9 +620,6 @@ export function mapFrameToDataGrid({
const columns: TableColumn[] = []; const columns: TableColumn[] = [];
const hasNestedFrames = getIsNestedTable(frame); const hasNestedFrames = getIsNestedTable(frame);
const cellInspect = fieldConfig?.defaults?.custom?.inspect ?? false;
const filterable = fieldConfig?.defaults?.custom?.filterable ?? false;
// If nested frames, add expansion control column // If nested frames, add expansion control column
if (hasNestedFrames) { if (hasNestedFrames) {
const expanderField: Field = { const expanderField: Field = {
@ -756,13 +752,12 @@ export function mapFrameToDataGrid({
defaultRowHeight, defaultRowHeight,
TABLE.CELL_PADDING, TABLE.CELL_PADDING,
textWrap, textWrap,
cellInspect, field,
cellType cellType
) )
} }
setIsInspecting={setIsInspecting} setIsInspecting={setIsInspecting}
setContextMenuProps={setContextMenuProps} setContextMenuProps={setContextMenuProps}
cellInspect={cellInspect}
getActions={getActions} getActions={getActions}
rowBg={rowBg} rowBg={rowBg}
onCellFilterAdded={onCellFilterAdded} onCellFilterAdded={onCellFilterAdded}
@ -803,7 +798,6 @@ export function mapFrameToDataGrid({
justifyContent={justifyColumnContent} justifyContent={justifyColumnContent}
filter={filter} filter={filter}
setFilter={setFilter} setFilter={setFilter}
filterable={filterable}
onColumnResize={onColumnResize} onColumnResize={onColumnResize}
headerCellRefs={headerCellRefs} headerCellRefs={headerCellRefs}
crossFilterOrder={crossFilterOrder} crossFilterOrder={crossFilterOrder}

View File

@ -134,7 +134,6 @@ export interface BaseTableProps {
export interface TableNGProps extends BaseTableProps {} export interface TableNGProps extends BaseTableProps {}
export interface TableCellNGProps { export interface TableCellNGProps {
cellInspect: boolean;
field: Field; field: Field;
frame: DataFrame; frame: DataFrame;
getActions?: GetActionsFunction; getActions?: GetActionsFunction;

View File

@ -1047,7 +1047,13 @@ describe('TableNG utils', () => {
40, // defaultRowHeight 40, // defaultRowHeight
8, // padding 8, // padding
false, // textWrap false, // textWrap
false, // cellInspect {
config: {
custom: {
inspect: false,
},
},
} as Field,
TableCellDisplayMode.Auto // cellType TableCellDisplayMode.Auto // cellType
); );
@ -1073,7 +1079,13 @@ describe('TableNG utils', () => {
40, // defaultRowHeight 40, // defaultRowHeight
8, // padding 8, // padding
false, // textWrap false, // textWrap
false, // cellInspect {
config: {
custom: {
inspect: false,
},
},
} as Field,
TableCellDisplayMode.Auto // cellType TableCellDisplayMode.Auto // cellType
); );
@ -1098,7 +1110,13 @@ describe('TableNG utils', () => {
40, // defaultRowHeight 40, // defaultRowHeight
8, // padding 8, // padding
true, // textWrap ENABLED true, // textWrap ENABLED
false, // cellInspect {
config: {
custom: {
inspect: true,
},
},
} as Field,
TableCellDisplayMode.Auto // cellType TableCellDisplayMode.Auto // cellType
); );
@ -1123,7 +1141,13 @@ describe('TableNG utils', () => {
40, // defaultRowHeight 40, // defaultRowHeight
8, // padding 8, // padding
false, // textWrap false, // textWrap
true, // cellInspect ENABLED {
config: {
custom: {
inspect: true,
},
},
} as Field,
TableCellDisplayMode.Auto // cellType TableCellDisplayMode.Auto // cellType
); );

View File

@ -169,9 +169,11 @@ export function shouldTextOverflow(
defaultRowHeight: number, defaultRowHeight: number,
padding: number, padding: number,
textWrap: boolean, textWrap: boolean,
cellInspect: boolean, field: Field,
cellType: TableCellDisplayMode cellType: TableCellDisplayMode
): boolean { ): boolean {
const cellInspect = field.config?.custom?.inspect ?? false;
// Tech debt: Technically image cells are of type string, which is misleading (kinda?) // 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 fo type image // so we need to ensure we don't apply overflow hover states fo type image
if (textWrap || cellInspect || cellType === TableCellDisplayMode.Image || !isTextCell(key, columnTypes)) { if (textWrap || cellInspect || cellType === TableCellDisplayMode.Image || !isTextCell(key, columnTypes)) {