mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Table: Preserve filtered value state (#83631)
* Hoist state * codeincarnate/table-filter-state/ lint --------- Co-authored-by: jev forsberg <jev.forsberg@grafana.com> Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
This commit is contained in:
parent
96127dce62
commit
33cb4f9bf4
@ -1,12 +1,13 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { Field, GrafanaTheme2 } from '@grafana/data';
|
||||
import { Field, GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||
|
||||
import { Popover } from '..';
|
||||
import { useStyles2 } from '../../themes';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
|
||||
import { REGEX_OPERATOR } from './FilterList';
|
||||
import { FilterPopup } from './FilterPopup';
|
||||
import { TableStyles } from './styles';
|
||||
|
||||
@ -23,6 +24,8 @@ export const Filter = ({ column, field, tableStyles }: Props) => {
|
||||
const filterEnabled = useMemo(() => Boolean(column.filterValue), [column.filterValue]);
|
||||
const onShowPopover = useCallback(() => setPopoverVisible(true), [setPopoverVisible]);
|
||||
const onClosePopover = useCallback(() => setPopoverVisible(false), [setPopoverVisible]);
|
||||
const [searchFilter, setSearchFilter] = useState('');
|
||||
const [operator, setOperator] = useState<SelectableValue<string>>(REGEX_OPERATOR);
|
||||
|
||||
if (!field || !field.config.custom?.filterable) {
|
||||
return null;
|
||||
@ -37,7 +40,18 @@ export const Filter = ({ column, field, tableStyles }: Props) => {
|
||||
<Icon name="filter" />
|
||||
{isPopoverVisible && ref.current && (
|
||||
<Popover
|
||||
content={<FilterPopup column={column} tableStyles={tableStyles} field={field} onClose={onClosePopover} />}
|
||||
content={
|
||||
<FilterPopup
|
||||
column={column}
|
||||
tableStyles={tableStyles}
|
||||
field={field}
|
||||
onClose={onClosePopover}
|
||||
searchFilter={searchFilter}
|
||||
setSearchFilter={setSearchFilter}
|
||||
operator={operator}
|
||||
setOperator={setOperator}
|
||||
/>
|
||||
}
|
||||
placement="bottom-start"
|
||||
referenceElement={ref.current}
|
||||
show
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { FixedSizeList as List } from 'react-window';
|
||||
|
||||
import { GrafanaTheme2, formattedValueToString, getValueFormat, SelectableValue } from '@grafana/data';
|
||||
@ -13,6 +13,10 @@ interface Props {
|
||||
onChange: (options: SelectableValue[]) => void;
|
||||
caseSensitive?: boolean;
|
||||
showOperators?: boolean;
|
||||
searchFilter: string;
|
||||
setSearchFilter: (value: string) => void;
|
||||
operator: SelectableValue<string>;
|
||||
setOperator: (item: SelectableValue<string>) => void;
|
||||
}
|
||||
|
||||
const ITEM_HEIGHT = 28;
|
||||
@ -33,7 +37,7 @@ const operatorSelectableValues: { [key: string]: SelectableValue<string> } = {
|
||||
},
|
||||
};
|
||||
const OPERATORS = Object.values(operatorSelectableValues);
|
||||
const REGEX_OPERATOR = operatorSelectableValues['Contains'];
|
||||
export const REGEX_OPERATOR = operatorSelectableValues['Contains'];
|
||||
const XPR_OPERATOR = operatorSelectableValues['Expression'];
|
||||
|
||||
const comparableValue = (value: string): string | number | Date | boolean => {
|
||||
@ -61,9 +65,17 @@ const comparableValue = (value: string): string | number | Date | boolean => {
|
||||
return value;
|
||||
};
|
||||
|
||||
export const FilterList = ({ options, values, caseSensitive, showOperators, onChange }: Props) => {
|
||||
const [operator, setOperator] = useState<SelectableValue<string>>(REGEX_OPERATOR);
|
||||
const [searchFilter, setSearchFilter] = useState('');
|
||||
export const FilterList = ({
|
||||
options,
|
||||
values,
|
||||
caseSensitive,
|
||||
showOperators,
|
||||
onChange,
|
||||
searchFilter,
|
||||
setSearchFilter,
|
||||
operator,
|
||||
setOperator,
|
||||
}: Props) => {
|
||||
const regex = useMemo(() => new RegExp(searchFilter, caseSensitive ? undefined : 'i'), [searchFilter, caseSensitive]);
|
||||
const items = useMemo(
|
||||
() =>
|
||||
|
@ -15,9 +15,21 @@ interface Props {
|
||||
tableStyles: TableStyles;
|
||||
onClose: () => void;
|
||||
field?: Field;
|
||||
searchFilter: string;
|
||||
setSearchFilter: (value: string) => void;
|
||||
operator: SelectableValue<string>;
|
||||
setOperator: (item: SelectableValue<string>) => void;
|
||||
}
|
||||
|
||||
export const FilterPopup = ({ column: { preFilteredRows, filterValue, setFilter }, onClose, field }: Props) => {
|
||||
export const FilterPopup = ({
|
||||
column: { preFilteredRows, filterValue, setFilter },
|
||||
onClose,
|
||||
field,
|
||||
searchFilter,
|
||||
setSearchFilter,
|
||||
operator,
|
||||
setOperator,
|
||||
}: Props) => {
|
||||
const theme = useTheme2();
|
||||
const uniqueValues = useMemo(() => calculateUniqueFieldValues(preFilteredRows, field), [preFilteredRows, field]);
|
||||
const options = useMemo(() => valuesToOptions(uniqueValues), [uniqueValues]);
|
||||
@ -73,6 +85,10 @@ export const FilterPopup = ({ column: { preFilteredRows, filterValue, setFilter
|
||||
options={options}
|
||||
caseSensitive={matchCase}
|
||||
showOperators={true}
|
||||
searchFilter={searchFilter}
|
||||
setSearchFilter={setSearchFilter}
|
||||
operator={operator}
|
||||
setOperator={setOperator}
|
||||
/>
|
||||
</VerticalGroup>
|
||||
<HorizontalGroup spacing="lg">
|
||||
|
Loading…
Reference in New Issue
Block a user