diff --git a/.betterer.results b/.betterer.results index fc658ccf0c8..40e87849b9b 100644 --- a/.betterer.results +++ b/.betterer.results @@ -830,7 +830,8 @@ exports[`better eslint`] = { ], "packages/grafana-ui/src/components/Table/types.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"] + [0, 0, 0, "Unexpected any. Specify a different type.", "1"], + [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], "packages/grafana-ui/src/components/Table/utils.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], diff --git a/packages/grafana-ui/src/components/Table/CellActions.tsx b/packages/grafana-ui/src/components/Table/CellActions.tsx index 222c441d5e2..8c70d56a481 100644 --- a/packages/grafana-ui/src/components/Table/CellActions.tsx +++ b/packages/grafana-ui/src/components/Table/CellActions.tsx @@ -1,4 +1,4 @@ -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; import * as React from 'react'; import { IconSize } from '../../types/icon'; @@ -6,7 +6,7 @@ import { IconButton } from '../IconButton/IconButton'; import { Stack } from '../Layout/Stack/Stack'; import { TooltipPlacement } from '../Tooltip'; -import { TableCellInspector, TableCellInspectorMode } from './TableCellInspector'; +import { TableCellInspectorMode } from './TableCellInspector'; import { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR, TableCellProps } from './types'; import { getTextAlign } from './utils'; @@ -20,9 +20,14 @@ interface CommonButtonProps { tooltipPlacement: TooltipPlacement; } -export function CellActions({ field, cell, previewMode, showFilters, onCellFilterAdded }: CellActionProps) { - const [isInspecting, setIsInspecting] = useState(false); - +export function CellActions({ + field, + cell, + previewMode, + showFilters, + onCellFilterAdded, + setInspectCell, +}: CellActionProps) { const isRightAligned = getTextAlign(field) === 'flex-end'; const inspectEnabled = Boolean(field.config.custom?.inspect); const commonButtonProps: CommonButtonProps = { @@ -48,37 +53,27 @@ export function CellActions({ field, cell, previewMode, showFilters, onCellFilte ); return ( - <> -
- - {inspectEnabled && ( - { - setIsInspecting(true); - }} - {...commonButtonProps} - /> - )} - {showFilters && ( - - )} - {showFilters && ( - - )} - -
- - {isInspecting && ( - { - setIsInspecting(false); - }} - /> - )} - +
+ + {inspectEnabled && ( + { + if (setInspectCell) { + setInspectCell({ value: cell.value, mode: previewMode }); + } + }} + {...commonButtonProps} + /> + )} + {showFilters && ( + + )} + {showFilters && ( + + )} + +
); } diff --git a/packages/grafana-ui/src/components/Table/DefaultCell.tsx b/packages/grafana-ui/src/components/Table/DefaultCell.tsx index d37f37d5abc..652aae07f0c 100644 --- a/packages/grafana-ui/src/components/Table/DefaultCell.tsx +++ b/packages/grafana-ui/src/components/Table/DefaultCell.tsx @@ -1,5 +1,5 @@ import { cx } from '@emotion/css'; -import { ReactElement, useState } from 'react'; +import { ReactElement } from 'react'; import * as React from 'react'; import { DisplayValue, formattedValueToString } from '@grafana/data'; @@ -28,18 +28,10 @@ export const DefaultCell = (props: TableCellProps) => { const hasLinks = Boolean(getCellLinks(field, row)?.length); const hasActions = Boolean(actions?.length); const clearButtonStyle = useStyles2(clearLinkButtonStyles); - const [hover, setHover] = useState(false); let value: string | ReactElement; const OG_TWEET_LENGTH = 140; // 🙏 - const onMouseLeave = () => { - setHover(false); - }; - const onMouseEnter = () => { - setHover(true); - }; - if (cellOptions.type === TableCellDisplayMode.Custom) { const CustomCellComponent: React.ComponentType = cellOptions.cellComponent; value = ; @@ -88,13 +80,7 @@ export const DefaultCell = (props: TableCellProps) => { const { key, ...rest } = cellProps; return ( -
+
{hasLinks || hasActions ? ( getCellLinks(field, row) || []} actions={actions}> {(api) => { @@ -118,9 +104,7 @@ export const DefaultCell = (props: TableCellProps) => {
{value}
)} - {hover && showActions && ( - - )} + {showActions && }
); }; diff --git a/packages/grafana-ui/src/components/Table/RowsList.tsx b/packages/grafana-ui/src/components/Table/RowsList.tsx index 646b4781fbe..b15745d3b82 100644 --- a/packages/grafana-ui/src/components/Table/RowsList.tsx +++ b/packages/grafana-ui/src/components/Table/RowsList.tsx @@ -24,7 +24,13 @@ import { usePanelContext } from '../PanelChrome'; import { ExpandedRow, getExpandedRowHeight } from './ExpandedRow'; import { TableCell } from './TableCell'; import { TableStyles } from './styles'; -import { CellColors, GetActionsFunction, TableFieldOptions, TableFilterActionCallback } from './types'; +import { + CellColors, + GetActionsFunction, + TableFieldOptions, + TableFilterActionCallback, + TableInspectCellCallback, +} from './types'; import { calculateAroundPointThreshold, getCellColors, @@ -57,6 +63,7 @@ interface RowsListProps { textWrapField?: Field; getActions?: GetActionsFunction; replaceVariables?: InterpolateFunction; + setInspectCell?: TableInspectCellCallback; } export const RowsList = (props: RowsListProps) => { @@ -85,6 +92,7 @@ export const RowsList = (props: RowsListProps) => { textWrapField, getActions, replaceVariables, + setInspectCell, } = props; const [rowHighlightIndex, setRowHighlightIndex] = useState(initialRowIndex); @@ -346,6 +354,7 @@ export const RowsList = (props: RowsListProps) => { height={Number(style.height)} getActions={getActions} replaceVariables={replaceVariables} + setInspectCell={setInspectCell} /> ))}
@@ -374,6 +383,7 @@ export const RowsList = (props: RowsListProps) => { timeRange, getActions, replaceVariables, + setInspectCell, ] ); diff --git a/packages/grafana-ui/src/components/Table/Table.tsx b/packages/grafana-ui/src/components/Table/Table.tsx index 54d61990463..2d8a040dc65 100644 --- a/packages/grafana-ui/src/components/Table/Table.tsx +++ b/packages/grafana-ui/src/components/Table/Table.tsx @@ -22,10 +22,11 @@ import { Pagination } from '../Pagination/Pagination'; import { FooterRow } from './FooterRow'; import { HeaderRow } from './HeaderRow'; import { RowsList } from './RowsList'; +import { TableCellInspector } from './TableCellInspector'; import { useFixScrollbarContainer, useResetVariableListSizeCache } from './hooks'; import { getInitialState, useTableStateReducer } from './reducer'; import { useTableStyles } from './styles'; -import { FooterItem, GrafanaTableState, Props } from './types'; +import { FooterItem, GrafanaTableState, InspectCell, Props } from './types'; import { getColumns, sortCaseInsensitive, @@ -72,6 +73,7 @@ export const Table = memo((props: Props) => { const headerHeight = noHeader ? 0 : tableStyles.rowHeight; const [footerItems, setFooterItems] = useState(footerValues); const noValuesDisplayText = fieldConfig?.defaults?.noValue ?? NO_DATA_TEXT; + const [inspectCell, setInspectCell] = useState(null); const footerHeight = useMemo(() => { const EXTENDED_ROW_HEIGHT = FOOTER_ROW_HEIGHT; @@ -324,66 +326,82 @@ export const Table = memo((props: Props) => { } return ( -
- -
- {!noHeader && ( - - )} - {itemCount > 0 ? ( -
- +
+ +
+ {!noHeader && ( + + )} + {itemCount > 0 ? ( +
+ +
+ ) : ( +
+ {noValuesDisplayText} +
+ )} + {footerItems && ( + -
- ) : ( -
- {noValuesDisplayText} -
- )} - {footerItems && ( - - )} -
- - {paginationEl} -
+ )} +
+
+ {paginationEl} +
+ + {inspectCell !== null && ( + { + setInspectCell(null); + }} + /> + )} + ); }); diff --git a/packages/grafana-ui/src/components/Table/TableCell.tsx b/packages/grafana-ui/src/components/Table/TableCell.tsx index 8fa154d519e..1ca230db4d4 100644 --- a/packages/grafana-ui/src/components/Table/TableCell.tsx +++ b/packages/grafana-ui/src/components/Table/TableCell.tsx @@ -3,7 +3,7 @@ import { Cell } from 'react-table'; import { TimeRange, DataFrame, InterpolateFunction } from '@grafana/data'; import { TableStyles } from './styles'; -import { GetActionsFunction, GrafanaTableColumn, TableFilterActionCallback } from './types'; +import { GetActionsFunction, GrafanaTableColumn, TableFilterActionCallback, TableInspectCellCallback } from './types'; export interface Props { cell: Cell; @@ -20,6 +20,7 @@ export interface Props { height?: number; getActions?: GetActionsFunction; replaceVariables?: InterpolateFunction; + setInspectCell?: TableInspectCellCallback; } export const TableCell = ({ @@ -35,6 +36,7 @@ export const TableCell = ({ height, getActions, replaceVariables, + setInspectCell, }: Props) => { const cellProps = cell.getCellProps(); const field = (cell.column as unknown as GrafanaTableColumn).field; @@ -78,6 +80,7 @@ export const TableCell = ({ textWrapped, height, actions, + setInspectCell, })} ); diff --git a/packages/grafana-ui/src/components/Table/types.ts b/packages/grafana-ui/src/components/Table/types.ts index 94d0c1183a2..ce1a0809f9d 100644 --- a/packages/grafana-ui/src/components/Table/types.ts +++ b/packages/grafana-ui/src/components/Table/types.ts @@ -14,6 +14,7 @@ import { } from '@grafana/data'; import * as schema from '@grafana/schema'; +import { TableCellInspectorMode } from './TableCellInspector'; import { TableStyles } from './styles'; export { @@ -33,6 +34,8 @@ export interface TableRow { [x: string]: any; } +export type InspectCell = { value: any; mode: TableCellInspectorMode }; + export const FILTER_FOR_OPERATOR = '='; export const FILTER_OUT_OPERATOR = '!='; export type AdHocFilterOperator = typeof FILTER_FOR_OPERATOR | typeof FILTER_OUT_OPERATOR; @@ -40,6 +43,7 @@ export type AdHocFilterItem = { key: string; value: string; operator: AdHocFilte export type TableFilterActionCallback = (item: AdHocFilterItem) => void; export type TableColumnResizeActionCallback = (fieldDisplayName: string, width: number) => void; export type TableSortByActionCallback = (state: TableSortByFieldState[]) => void; +export type TableInspectCellCallback = (state: InspectCell) => void; export interface TableSortByFieldState { displayName: string; @@ -54,6 +58,7 @@ export interface TableCellProps extends CellProps { innerWidth: number; frame: DataFrame; actions?: ActionModel[]; + setInspectCell?: TableInspectCellCallback; } export type CellComponent = FC;