import { useCallback, useState } from 'react'; import { Table, Thead, Tr, Th, Tbody, Td, ThProps } from '@patternfly/react-table'; interface Repository { name: string; branches: string; prs: string; workspaces: string; lastCommit: string; } export const TableFavoritable: React.FunctionComponent = () => { // In real usage, this data would come from some external source like an API via props. const repositories: Repository[] = [ { name: 'one', branches: 'two', prs: 'a', workspaces: 'four', lastCommit: 'five' }, { name: 'a', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five' }, { name: 'p', branches: 'two', prs: 'b', workspaces: 'four', lastCommit: 'five' } ]; const columnNames = { name: 'Repositories', branches: 'Branches', prs: 'Pull requests', workspaces: 'Workspaces', lastCommit: 'Last commit' }; // Index of the currently sorted column // Note: if you intend to make columns reorderable, you may instead want to use a non-numeric key // as the identifier of the sorted column. See the "Compound expandable" example. const [activeSortIndex, setActiveSortIndex] = useState(); // Sort direction of the currently sorted column const [activeSortDirection, setActiveSortDirection] = useState<'asc' | 'desc'>(); // Favorite state is similar to selection state, see Selectable with checkbox. const [favoriteRepoNames, setFavoriteRepoNames] = useState([]); const setRepoFavorited = (repo: Repository, isFavoriting = true) => setFavoriteRepoNames((prevFavorites) => { const otherFavorites = prevFavorites.filter((r) => r !== repo.name); return isFavoriting ? [...otherFavorites, repo.name] : otherFavorites; }); const isRepoFavorited = (repo: Repository) => favoriteRepoNames.includes(repo.name); // State of the header cell to favorite / unfavorite all rows const [headerFavorited, setHeaderFavorited] = useState(false); // Since OnSort specifies sorted columns by index, we need sortable values for our object by column index. // In this example we only deal with booleans here because we only sort on the favorites column. // For more complex sorting, see Sortable. // Note: We also memoize the sortable values with useCallback to prevent rows jumping around when you change // the favorites while sorting on that column. Only updating the sort state will reorder the rows. const getSortableRowValues = useCallback( (repo: Repository): boolean[] => [isRepoFavorited(repo)], [activeSortIndex, activeSortDirection] ); // Note that we perform the sort as part of the component's render logic and not in onSort. // We shouldn't store the list of data in state because we don't want to have to sync that with props. let sortedRepositories = repositories; if (activeSortIndex !== undefined) { sortedRepositories = repositories.sort((a, b) => { const aValue = getSortableRowValues(a)[activeSortIndex]; const bValue = getSortableRowValues(b)[activeSortIndex]; if (aValue === bValue) { return 0; } if (activeSortDirection === 'asc') { return aValue > bValue ? 1 : -1; } else { return bValue > aValue ? 1 : -1; } }); } const getSortParams = (columnIndex: number): ThProps['sort'] => ({ isFavorites: columnIndex === 0, // Not just statically true in case we add sorting on other columns later sortBy: { index: activeSortIndex, direction: activeSortDirection }, onSort: (_event, index, direction) => { setActiveSortIndex(index); setActiveSortDirection(direction); }, 'aria-label': 'Sort favorites', columnIndex, favoriteButtonProps: { favorited: headerFavorited, onClick: (_event) => { repositories.forEach((repo) => setRepoFavorited(repo, !headerFavorited)); setHeaderFavorited(!headerFavorited); }, 'aria-label': headerFavorited ? 'Unfavorite all' : 'Favorite all' } }); return ( {sortedRepositories.map((repo, rowIndex) => ( ))}
{columnNames.name} {columnNames.branches} {columnNames.prs} {columnNames.workspaces} {columnNames.lastCommit}
{ setRepoFavorited(repo, isFavoriting); if ( isFavoriting && repositories.filter((r) => r !== repo).every((r) => favoriteRepoNames.includes(r.name)) ) { setHeaderFavorited(true); } if (!isFavoriting && favoriteRepoNames.length === 1 && favoriteRepoNames.includes(repo.name)) { setHeaderFavorited(false); } }, rowIndex }} /> {repo.name} {repo.branches} {repo.prs} {repo.workspaces} {repo.lastCommit}
); };