Table panel: Fix filter not working for special characters and allow filter's case sensitivity control (#40458)

* Fix filter not working for special characters and allow case sansitive filter control

* Memoize regex
This commit is contained in:
Dominik Prokop 2021-10-18 09:19:05 +02:00 committed by GitHub
parent 80a7401cfb
commit 6201b5b1d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 7 deletions

View File

@ -10,18 +10,26 @@ interface Props {
values: SelectableValue[];
options: SelectableValue[];
onChange: (options: SelectableValue[]) => void;
caseSensitive?: boolean;
}
const ITEM_HEIGHT = 28;
const MIN_HEIGHT = ITEM_HEIGHT * 5;
export const FilterList: FC<Props> = ({ options, values, onChange }) => {
export const FilterList: FC<Props> = ({ options, values, caseSensitive, onChange }) => {
const theme = useTheme2();
const styles = getStyles(theme);
const [searchFilter, setSearchFilter] = useState('');
const regex = useMemo(() => new RegExp(searchFilter, caseSensitive ? undefined : 'i'), [searchFilter, caseSensitive]);
const items = useMemo(
() => options.filter((option) => option.label?.toLowerCase().includes(searchFilter.toLowerCase())),
[options, searchFilter]
() =>
options.filter((option) => {
if (option.label === undefined) {
return false;
}
return regex.test(option.label);
}),
[options, regex]
);
const gutter = theme.spacing.gridSize;
const height = useMemo(() => Math.min(items.length * ITEM_HEIGHT, MIN_HEIGHT) + gutter, [gutter, items.length]);

View File

@ -3,8 +3,8 @@ import { Field, GrafanaTheme, SelectableValue } from '@grafana/data';
import { css, cx } from '@emotion/css';
import { TableStyles } from './styles';
import { stylesFactory, useStyles } from '../../themes';
import { Button, ClickOutsideWrapper, HorizontalGroup, Label, VerticalGroup } from '..';
import { stylesFactory, useStyles, useTheme2 } from '../../themes';
import { Button, ClickOutsideWrapper, HorizontalGroup, IconButton, Label, VerticalGroup } from '..';
import { FilterList } from './FilterList';
import { calculateUniqueFieldValues, getFilteredOptions, valuesToOptions } from './utils';
@ -16,10 +16,12 @@ interface Props {
}
export const FilterPopup: FC<Props> = ({ column: { preFilteredRows, filterValue, setFilter }, onClose, field }) => {
const theme = useTheme2();
const uniqueValues = useMemo(() => calculateUniqueFieldValues(preFilteredRows, field), [preFilteredRows, field]);
const options = useMemo(() => valuesToOptions(uniqueValues), [uniqueValues]);
const filteredOptions = useMemo(() => getFilteredOptions(options, filterValue), [options, filterValue]);
const [values, setValues] = useState<SelectableValue[]>(filteredOptions);
const [matchCase, setMatchCase] = useState(false);
const onCancel = useCallback((event?: React.MouseEvent) => onClose(), [onClose]);
@ -49,9 +51,19 @@ export const FilterPopup: FC<Props> = ({ column: { preFilteredRows, filterValue,
<div className={cx(styles.filterContainer)} onClick={stopPropagation}>
<VerticalGroup spacing="lg">
<VerticalGroup spacing="xs">
<Label>Filter by values:</Label>
<HorizontalGroup justify="space-between" align="center">
<Label className={styles.label}>Filter by values:</Label>
<IconButton
name="text-fields"
tooltip="Match case"
style={{ color: matchCase ? theme.colors.text.link : theme.colors.text.disabled }}
onClick={() => {
setMatchCase((s) => !s);
}}
/>
</HorizontalGroup>
<div className={cx(styles.listDivider)} />
<FilterList onChange={setValues} values={values} options={options} />
<FilterList onChange={setValues} values={values} options={options} caseSensitive={matchCase} />
</VerticalGroup>
<HorizontalGroup spacing="lg">
<HorizontalGroup>
@ -96,6 +108,9 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
border-top: ${theme.border.width.sm} solid ${theme.colors.border2};
padding: ${theme.spacing.xs} ${theme.spacing.md};
`,
label: css`
margin-bottom: 0;
`,
}));
const stopPropagation = (event: React.MouseEvent) => {

View File

@ -143,6 +143,7 @@ export const getAvailableIcons = () =>
'sync',
'table',
'tag-alt',
'text-fields',
'times',
'toggle-on',
'trash-alt',