diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 73ce4ef95da..15dbecf1ed4 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -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 diff --git a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx index 12e3eb08354..a2e23e78575 100644 --- a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx +++ b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx @@ -20,13 +20,14 @@ export interface Props extends HTMLAttributes { narrow?: boolean; variant?: ToolbarButtonVariant; tooltip?: string; + root?: HTMLElement; } /** * @deprecated Use Combobox or Dropdown instead */ const ButtonSelectComponent = (props: Props) => { - 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 = (props: Props) => { ); return ( - + {value?.label || (value?.value != null ? String(value?.value) : null)} diff --git a/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx b/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx index eff7cdc9454..77cdcc92519 100644 --- a/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx +++ b/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx @@ -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 && ( - + {/* this is handling bubbled events from the inner overlay diff --git a/packages/grafana-ui/src/components/Table/TableNG/Filter/Filter.tsx b/packages/grafana-ui/src/components/Table/TableNG/Filter/Filter.tsx index 2f219a4dd06..3c00ba45699 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/Filter/Filter.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/Filter/Filter.tsx @@ -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>; field?: Field; crossFilterOrder: string[]; crossFilterRows: { [key: string]: TableRow[] }; diff --git a/packages/grafana-ui/src/components/Table/TableNG/Filter/FilterPopup.tsx b/packages/grafana-ui/src/components/Table/TableNG/Filter/FilterPopup.tsx index 5e856d26a05..de258a44815 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/Filter/FilterPopup.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/Filter/FilterPopup.tsx @@ -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>; + setFilter: React.Dispatch>; 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(filteredOptions); const [matchCase, setMatchCase] = useState(false); + const containerRef = useRef(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} > @@ -124,6 +126,7 @@ export const FilterPopup = ({ onChange={setOperator} value={operator} tooltip={operator.description} + root={containerRef.current ?? undefined} /> diff --git a/packages/grafana-ui/src/components/Table/TableNG/Filter/utils.ts b/packages/grafana-ui/src/components/Table/TableNG/Filter/utils.ts index 862ba9856c6..587add826c5 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/Filter/utils.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/Filter/utils.ts @@ -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; }