From 014e5ba0c2ed4449fdaaadc43a4b0fefcb0a5bf2 Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Mon, 18 Oct 2021 09:58:39 +0100 Subject: [PATCH] Table panel: Fix filter not working for special characters and allow filter's case sensitivity control (#40458) (#40556) * Fix filter not working for special characters and allow case sansitive filter control * Memoize regex (cherry picked from commit 6201b5b1d9b98a9c48f7565f08cb51468265d837) Co-authored-by: Dominik Prokop --- .../src/components/Table/FilterList.tsx | 14 ++++++++--- .../src/components/Table/FilterPopup.tsx | 23 +++++++++++++++---- packages/grafana-ui/src/types/icon.ts | 1 + 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/packages/grafana-ui/src/components/Table/FilterList.tsx b/packages/grafana-ui/src/components/Table/FilterList.tsx index 0f961cd0922..d14bd9c36d4 100644 --- a/packages/grafana-ui/src/components/Table/FilterList.tsx +++ b/packages/grafana-ui/src/components/Table/FilterList.tsx @@ -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 = ({ options, values, onChange }) => { +export const FilterList: FC = ({ 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]); diff --git a/packages/grafana-ui/src/components/Table/FilterPopup.tsx b/packages/grafana-ui/src/components/Table/FilterPopup.tsx index 5e64eb4c3a8..c5cebb9a1f7 100644 --- a/packages/grafana-ui/src/components/Table/FilterPopup.tsx +++ b/packages/grafana-ui/src/components/Table/FilterPopup.tsx @@ -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 = ({ 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(filteredOptions); + const [matchCase, setMatchCase] = useState(false); const onCancel = useCallback((event?: React.MouseEvent) => onClose(), [onClose]); @@ -49,9 +51,19 @@ export const FilterPopup: FC = ({ column: { preFilteredRows, filterValue,
- + + + { + setMatchCase((s) => !s); + }} + /> +
- + @@ -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) => { diff --git a/packages/grafana-ui/src/types/icon.ts b/packages/grafana-ui/src/types/icon.ts index eb06b512fe9..b356edd6dfe 100644 --- a/packages/grafana-ui/src/types/icon.ts +++ b/packages/grafana-ui/src/types/icon.ts @@ -142,6 +142,7 @@ export const getAvailableIcons = () => 'sync', 'table', 'tag-alt', + 'text-fields', 'times', 'toggle-on', 'trash-alt',