import { useCallback, useState } from 'react';
import useSelectionManager from '../useSelectionManager';
import {
checkCurrentPageSelected,
checkboxState,
compileTitle,
selectOrUnselect,
} from './helpers';
/**
* @typedef {object} useBulkSelectReturn
*
* @property {Function} [markRowSelected] "Transformer" function to be passed to the rowsBuilder
* @property {object} [toolbarProps] Object containing PrimaryToolbar props
* @property {object} [tableProps] Object containing Patternfly (v4) Table props
*
*/
/**
* Provides properties for a Pattternfly (based) Table and Toolbar component to implement bulk selection
*
* @param {object} [options] AsyncTableTools options
* @param {number} [options.total] Number to show as total count
* @param {Function} [options.onSelect] function to call when a selection is made
* @param {Array} [options.preselected] Array of itemIds selected when initialising
* @param {Function} [options.itemIdsInTable] Function to call to retrieve IDs when "Select All" is chosen
* @param {Array} [options.itemIdsOnPage] Array of item ids visible on the page
* @param {string} [options.identifier] Property of the items that should be used as ID to select them
*
* @returns {useBulkSelectReturn} Functions and props to use for setting up bulk selection
*
* @category AsyncTableTools
* @subcategory Hooks
*
*/
const useBulkSelect = ({
total = 0,
onSelect,
preselected,
itemIdsInTable,
itemIdsOnPage,
identifier = 'itemId',
}) => {
const [loading, setLoading] = useState(false);
const enableBulkSelect = !!onSelect;
const {
selection: selectedIds,
set,
select,
deselect,
clear,
} = useSelectionManager(preselected, {}, onSelect);
const selectedIdsTotal = (selectedIds || []).length;
const paginatedTotal = itemIdsOnPage?.length || total;
const allSelected = selectedIdsTotal === total;
const noneSelected = selectedIdsTotal === 0;
const currentPageSelected = checkCurrentPageSelected(
itemIdsOnPage,
selectedIds
);
// TODO this is not totally wrong, but when the tree view is active there is currently no total, which causes the selection to be disabled there.
// The bug may not even be fixed here, but in the tables that use selection and the tree view. They will need to provide an appropriate total still
const isDisabled = total === 0;
const checked = checkboxState(selectedIdsTotal, total);
const title = compileTitle(selectedIdsTotal, loading);
const selectOne = useCallback(
(_, _selected, _key, row) =>
row.selected ? deselect(row[identifier]) : select(row[identifier]),
[select, deselect, identifier]
);
const selectPage = useCallback(
() =>
!currentPageSelected ? select(itemIdsOnPage) : deselect(itemIdsOnPage),
[select, deselect, itemIdsOnPage, currentPageSelected]
);
const selectAll = async () => {
setLoading(true);
if (allSelected) {
clear();
} else {
set(await itemIdsInTable());
}
setLoading(false);
};
const markRowSelected = (row) => ({
...row,
selected: selectedIds.includes(row.itemId),
});
return enableBulkSelect
? {
tableView: { markRowSelected, selectOne, set, select, deselect, clear },
tableProps: {
onSelect: total > 0 ? selectOne : undefined,
canSelectAll: false,
},
toolbarProps: {
bulkSelect: {
toggleProps: { children: [title] },
isDisabled,
items: [
{
title: 'Select none',
onClick: clear,
props: {
isDisabled: noneSelected,
},
},
...(itemIdsOnPage
? [
{
title: `${selectOrUnselect(
currentPageSelected
)} page (${paginatedTotal} items)`,
onClick: selectPage,
},
]
: []),
...(itemIdsInTable
? [
{
title: `${selectOrUnselect(
allSelected
)} all (${total} items)`,
onClick: selectAll,
},
]
: []),
],
checked,
onSelect: !isDisabled ? selectPage : undefined,
},
},
}
: {};
};
export default useBulkSelect;
Source