diff --git a/docs/sources/panels-visualizations/visualizations/table/index.md b/docs/sources/panels-visualizations/visualizations/table/index.md index d78221b79d0..91862f56b01 100644 --- a/docs/sources/panels-visualizations/visualizations/table/index.md +++ b/docs/sources/panels-visualizations/visualizations/table/index.md @@ -191,6 +191,8 @@ To filter column values, click the filter (funnel) icon next to a column title. Click the check box next to the values that you want to display. Enter text in the search field at the top to show those values in the display so that you can select them rather than scroll to find them. +Click the check box above the **Ok** and **Cancel** buttons to add or remove all displayed values to/from the filter. + ### Clear column filters Columns with filters applied have a blue funnel displayed next to the title. diff --git a/packages/grafana-ui/src/components/Table/FilterList.tsx b/packages/grafana-ui/src/components/Table/FilterList.tsx index 2ff6d26bb41..1c56ff7f631 100644 --- a/packages/grafana-ui/src/components/Table/FilterList.tsx +++ b/packages/grafana-ui/src/components/Table/FilterList.tsx @@ -1,4 +1,4 @@ -import { css } from '@emotion/css'; +import { css, cx } from '@emotion/css'; import React, { useCallback, useMemo, useState } from 'react'; import { FixedSizeList as List } from 'react-window'; @@ -30,6 +30,24 @@ export const FilterList = ({ options, values, caseSensitive, onChange }: Props) }), [options, regex] ); + const selectedItems = useMemo(() => items.filter((item) => values.includes(item)), [items, values]); + + const selectCheckValue = useMemo(() => items.length === selectedItems.length, [items, selectedItems]); + const selectCheckIndeterminate = useMemo( + () => selectedItems.length > 0 && items.length > selectedItems.length, + [items, selectedItems] + ); + const selectCheckLabel = useMemo( + () => (selectedItems.length ? `${selectedItems.length} selected` : `Select all`), + [selectedItems] + ); + const selectCheckDescription = useMemo( + () => + items.length !== selectedItems.length + ? 'Add all displayed values to the filter' + : 'Remove all displayed values from the filter', + [items, selectedItems] + ); const styles = useStyles2(getStyles); const theme = useTheme2(); @@ -47,6 +65,16 @@ export const FilterList = ({ options, values, caseSensitive, onChange }: Props) [onChange, values] ); + const onSelectChanged = useCallback(() => { + if (items.length === selectedItems.length) { + const newValues = values.filter((item) => !items.includes(item)); + onChange(newValues); + } else { + const newValues = [...new Set([...values, ...items])]; + onChange(newValues); + } + }, [onChange, values, items, selectedItems]); + return ( @@ -72,6 +100,20 @@ export const FilterList = ({ options, values, caseSensitive, onChange }: Props) }} )} + {items.length && ( + +
+
+ +
+ + )} ); }; @@ -92,4 +134,10 @@ const getStyles = (theme: GrafanaTheme2) => ({ backgroundColor: theme.colors.action.hover, }, }), + selectDivider: css({ + label: 'selectDivider', + width: '100%', + borderTop: `1px solid ${theme.colors.border.medium}`, + padding: theme.spacing(0.5, 2), + }), });