mirror of https://github.com/grafana/grafana.git
				
				
				
			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:
		
							parent
							
								
									413378dd3a
								
							
						
					
					
						commit
						d6ec8ab8b1
					
				| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue