diff --git a/ui/src/table.tsx b/ui/src/table.tsx index 66e741613b..32b4b99761 100644 --- a/ui/src/table.tsx +++ b/ui/src/table.tsx @@ -189,7 +189,7 @@ type ContextualMenuProps = { col: WaveColumn listProps: Fluent.IContextualMenuListProps selectedFilters: Dict | null - setFiltersInBulk: (colKey: S, filters: S[]) => void + setFiltersInBulk: (colKey: S, filters: S[]) => void } type FooterProps = { @@ -291,6 +291,7 @@ const ContextualMenu = ({ onFilterChange, col, listProps, selectedFilters, setFiltersInBulk }: ContextualMenuProps) => { const isFilterChecked = (data: S, key: S) => !!selectedFilters && selectedFilters[data]?.includes(key), + [selectedFiltersCount, setSelectedFiltersCount] = React.useState(0), // Step 1 [menuFilters, setMenuFilters] = React.useState(col.cellType?.tag ? Array.from(listProps.items.reduce((_filters, { key, text, data }) => { key.split(',').forEach(key => _filters.set(key, { key, text, data, checked: isFilterChecked(data, key) })) @@ -301,18 +302,28 @@ const selectAll = () => { setMenuFilters(menuFilters.map(i => ({ ...i, checked: true }))) setFiltersInBulk(col.key, menuFilters.map(f => f.key)) + setSelectedFiltersCount(menuFilters.length) }, deselectAll = () => { setMenuFilters(menuFilters.map(i => ({ ...i, checked: false }))) setFiltersInBulk(col.key, []) + setSelectedFiltersCount(0) }, getOnFilterChangeHandler = (data: S, key: S) => (_ev?: React.FormEvent, checked?: B) => { - setMenuFilters(filters => filters.map(f => f.key === key ? ({ ...f, checked }) : f)) + const onChangeFilterMap = menuFilters.map(f => (f.key === key ? { ...f, checked } : f)) + setMenuFilters(onChangeFilterMap) onFilterChange(data, key, checked) + setFiltersInBulk(col.key, onChangeFilterMap.filter(f => f.checked).map(f => f.key)) + setSelectedFiltersCount( + onChangeFilterMap.reduce((count, filter) => (filter.checked ? count + 1 : count), 0) + ) } return (
+ + {`(${selectedFiltersCount} selected)`} + Show only Select All | Deselect All @@ -334,7 +345,7 @@ const }, DataTable = React.forwardRef(({ model: m, onFilterChange, items, filteredItems, selection, selectedFilters, isMultiple, isSingle, groups, expandedRefs, onSortChange, setFiltersInBulk }: DataTable, ref) => { const - [colContextMenuList, setColContextMenuList] = React.useState(null), + [colContextMenuList, setColContextMenuList] = React.useState(null), onRenderMenuList = React.useCallback((col: WaveColumn) => (listProps?: Fluent.IContextualMenuListProps) => { return listProps ? { const minWidth = c.min_width @@ -386,9 +398,15 @@ const ? +c.max_width.substring(0, c.max_width.length - 2) : +c.max_width : undefined + let label = c.label + if (c.filterable) { + const dataKey = c.name // Assuming the column name represents the data key + const appliedFilters = selectedFilters?.[dataKey]?.length || 0 + label += (appliedFilters > 0 && appliedFilters <= 9) ? ` (${appliedFilters})` : appliedFilters > 9 ? '(9+)': '' + } return { key: c.name, - name: c.label, + name: label, fieldName: c.name, minWidth, maxWidth, @@ -406,37 +424,38 @@ const isMultiline: c.cell_overflow === 'wrap', filters: c.filterable ? c.filters : undefined, } - }, [onColumnClick]), + }, [onColumnClick, selectedFilters]), [columns, setColumns] = React.useState(m.columns.map(tableToWaveColumn)), primaryColumnKey = m.columns.find(c => c.link)?.name || (m.columns[0].link === false ? undefined : m.columns[0].name), onRenderDetailsHeader = React.useCallback((props?: Fluent.IDetailsHeaderProps) => { if (!props) return - return ( - group.isCollapsed)} - styles={{ - ...props.styles, - root: { - padding: 0, - height: 48, - lineHeight: '48px', - background: cssVar('$neutralLight'), - borderBottom: 'none', - }, - cellSizerEnd: { - marginLeft: -8, - }, - cellIsGroupExpander: { - // HACK: fixed size of expand/collapse button in column header - height: 48 - } - }} - /> +
+ group.isCollapsed)} + styles={{ + ...props.styles, + root: { + padding: 0, + height: 48, + lineHeight: '48px', + background: cssVar('$neutralLight'), + borderBottom: 'none', + }, + cellSizerEnd: { + marginLeft: -8, + }, + cellIsGroupExpander: { + // HACK: fixed size of expand/collapse button in column header + height: 48, + }, + }} + /> +
- ) + ) }, [groups]), onRenderGroupHeader = React.useCallback((props?: Fluent.IDetailsGroupDividerProps) => { if (!props) return @@ -578,9 +597,6 @@ const onRenderItemColumn={onRenderItemColumn} onRenderDetailsHeader={onRenderDetailsHeader} checkboxVisibility={checkboxVisibilityMap[m.checkbox_visibility || 'on-hover']} - // Prevent selection from being cleared when 'items' are updated. - // https://github.com/microsoft/fluentui/blob/4c1cd4bbba73bbca4411db9d01ffb486b1a90303/packages/react/src/components/DetailsList/DetailsList.base.tsx#L1032. - setKey='wave-table-items' /> {colContextMenuList && } @@ -931,11 +947,6 @@ export const const selectedItemKeys = selection.getSelection().map(item => item.key as S) wave.args[m.name] = selectedItemKeys if (!skipNextEventEmit.current && m.events?.includes('select')) wave.emit(m.name, 'select', selectedItemKeys) - }, - onItemsChanged: () => { - // HACK: Skip emitting 'select' event on 'items' update. - skipNextEventEmit.current = true - setTimeout(() => skipNextEventEmit.current = false) } }), [m.name, m.events]), computeHeight = () => { @@ -975,17 +986,19 @@ export const }, [m.pagination, m.events, m.name, filter, search, currentSort, initGroups]) React.useEffect(() => { - skipNextEventEmit.current = true wave.args[m.name] = [] if (isSingle && m.value) { + skipNextEventEmit.current = true selection.setKeySelected(m.value, true, false) + skipNextEventEmit.current = false wave.args[m.name] = [m.value] } else if (isMultiple && m.values) { + skipNextEventEmit.current = true m.values.forEach(v => selection.setKeySelected(v, true, false)) + skipNextEventEmit.current = false wave.args[m.name] = m.values } - skipNextEventEmit.current = false // eslint-disable-next-line react-hooks/exhaustive-deps }, [])