Table: Fix regression with Filter popup expression selection (#111777)

This commit is contained in:
Paul Marbach
2025-09-29 23:06:47 -05:00
committed by GitHub
parent d0e3e91b03
commit 9b722efe57
6 changed files with 19 additions and 29 deletions
-15
View File
@@ -861,21 +861,6 @@
"count": 1
}
},
"packages/grafana-ui/src/components/Table/TableNG/Filter/Filter.tsx": {
"@typescript-eslint/no-explicit-any": {
"count": 1
}
},
"packages/grafana-ui/src/components/Table/TableNG/Filter/FilterPopup.tsx": {
"@typescript-eslint/no-explicit-any": {
"count": 3
}
},
"packages/grafana-ui/src/components/Table/TableNG/Filter/utils.ts": {
"@typescript-eslint/no-explicit-any": {
"count": 1
}
},
"packages/grafana-ui/src/components/Table/TableNG/TableNG.test.tsx": {
"@typescript-eslint/no-explicit-any": {
"count": 2
@@ -20,13 +20,14 @@ export interface Props<T> extends HTMLAttributes<HTMLButtonElement> {
narrow?: boolean;
variant?: ToolbarButtonVariant;
tooltip?: string;
root?: HTMLElement;
}
/**
* @deprecated Use Combobox or Dropdown instead
*/
const ButtonSelectComponent = <T,>(props: Props<T>) => {
const { className, options, value, onChange, narrow, variant, ...restProps } = props;
const { className, options, value, onChange, narrow, variant, root, ...restProps } = props;
const [isOpen, setIsOpen] = useState(false);
const renderMenu = () => (
@@ -50,7 +51,7 @@ const ButtonSelectComponent = <T,>(props: Props<T>) => {
);
return (
<Dropdown overlay={renderMenu} placement="bottom-end">
<Dropdown root={root} overlay={renderMenu} placement="bottom-end">
<ToolbarButton className={className} isOpen={isOpen} narrow={narrow} variant={variant} {...restProps}>
{value?.label || (value?.value != null ? String(value?.value) : null)}
</ToolbarButton>
@@ -25,12 +25,13 @@ export interface Props {
overlay: React.ReactElement | (() => React.ReactElement);
placement?: TooltipPlacement;
children: React.ReactElement;
root?: HTMLElement;
/** Amount in pixels to nudge the dropdown vertically and horizontally, respectively. */
offset?: [number, number];
onVisibleChange?: (state: boolean) => void;
}
export const Dropdown = React.memo(({ children, overlay, placement, offset, onVisibleChange }: Props) => {
export const Dropdown = React.memo(({ children, overlay, placement, offset, root, onVisibleChange }: Props) => {
const [show, setShow] = useState(false);
const transitionRef = useRef(null);
const floatingUIPlacement = getPlacement(placement);
@@ -84,7 +85,7 @@ export const Dropdown = React.memo(({ children, overlay, placement, offset, onVi
...getReferenceProps(),
})}
{show && (
<Portal>
<Portal root={root}>
<FloatingFocusManager context={context}>
{/*
this is handling bubbled events from the inner overlay
@@ -14,9 +14,9 @@ import { FilterPopup } from './FilterPopup';
interface Props {
name: string;
rows: any[];
rows: TableRow[];
filter: FilterType;
setFilter: (value: FilterType) => void;
setFilter: React.Dispatch<React.SetStateAction<FilterType>>;
field?: Field;
crossFilterOrder: string[];
crossFilterRows: { [key: string]: TableRow[] };
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
import React, { useCallback, useMemo, useState } from 'react';
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { Field, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -12,7 +12,7 @@ import { ButtonSelect } from '../../../Dropdown/ButtonSelect';
import { FilterInput } from '../../../FilterInput/FilterInput';
import { Label } from '../../../Forms/Label';
import { Stack } from '../../../Layout/Stack/Stack';
import { FilterType } from '../types';
import { FilterType, TableRow } from '../types';
import { getDisplayName } from '../utils';
import { FilterList } from './FilterList';
@@ -36,9 +36,9 @@ const OPERATORS = Object.values(operatorSelectableValues);
interface Props {
name: string;
rows: any[];
filterValue: any;
setFilter: (value: any) => void;
rows: TableRow[];
filterValue?: Array<SelectableValue<unknown>>;
setFilter: React.Dispatch<React.SetStateAction<FilterType>>;
onClose: () => void;
field?: Field;
searchFilter: string;
@@ -65,6 +65,7 @@ export const FilterPopup = ({
const filteredOptions = useMemo(() => getFilteredOptions(options, filterValue), [options, filterValue]);
const [values, setValues] = useState<SelectableValue[]>(filteredOptions);
const [matchCase, setMatchCase] = useState(false);
const containerRef = useRef<HTMLDivElement>(null);
const onCancel = useCallback((event?: React.MouseEvent) => onClose(), [onClose]);
@@ -114,6 +115,7 @@ export const FilterPopup = ({
className={styles.filterContainer}
onClick={stopPropagation}
data-testid={selectors.components.Panels.Visualization.TableNG.Filters.Container}
ref={containerRef}
>
<Stack direction="column">
<Stack alignItems="center">
@@ -124,6 +126,7 @@ export const FilterPopup = ({
onChange={setOperator}
value={operator}
tooltip={operator.description}
root={containerRef.current ?? undefined}
/>
</Stack>
@@ -1,8 +1,9 @@
import { Field, formattedValueToString, SelectableValue } from '@grafana/data';
import { TableRow } from '../types';
import { getDisplayName } from '../utils';
export function calculateUniqueFieldValues(rows: any[], field?: Field) {
export function calculateUniqueFieldValues(rows: TableRow[], field?: Field) {
if (!field || rows.length === 0) {
return {};
}
@@ -12,8 +13,7 @@ export function calculateUniqueFieldValues(rows: any[], field?: Field) {
for (let index = 0; index < rows.length; index++) {
const row = rows[index];
const fieldValue = row[getDisplayName(field)];
const displayValue = field.display ? field.display(fieldValue) : fieldValue;
const value = field.display ? formattedValueToString(displayValue) : displayValue;
const value = field.display ? formattedValueToString(field.display(fieldValue)) : String(fieldValue);
set[value || '(Blanks)'] = value;
}