import { Fragment, useState } from 'react'; import { Table, Thead, Tr, Th, Tbody, Td, ExpandableRowContent } from '@patternfly/react-table'; import { Checkbox } from '@patternfly/react-core'; interface Repository { name: string; branches: string; prs: string; workspaces: string; lastCommit: string; details?: { detail1?: string; detail2?: string; detail3?: string; detailFormat: 0 | 1 | 2 | 3; }; } export const TableExpandable: 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: 'parent 1', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five', // This `details` structure is just for this example. You can drive expanded content from any kind of data. details: { detailFormat: 0, detail1: 'single cell' } }, { name: 'parent 2', branches: 'two', prs: 'b', workspaces: 'four', lastCommit: 'five', details: { detailFormat: 1, detail1: 'Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. Lorem ipsum sit dolor. ' } }, { name: 'parent 3', branches: '2', prs: 'b', workspaces: 'four', lastCommit: 'five', details: { detailFormat: 2, detail1: 'single cell - noPadding' } }, { name: 'parent 4', branches: '2', prs: 'b', workspaces: 'four', lastCommit: 'five', details: { detailFormat: 3, detail1: 'single cell - fullWidth & noPadding' } }, { name: 'parent 5', branches: '2', prs: 'b', workspaces: 'four', lastCommit: 'five', details: { detailFormat: 0, detail1: "spans 'Repositories and 'Branches'", detail2: "spans 'Pull requests' and 'Workspaces', and 'Last commit'" } }, { name: 'parent 6', branches: '2', prs: 'b', workspaces: 'four', lastCommit: 'five', details: { detailFormat: 1, detail1: "fullWidth, spans the collapsible column and 'Repositories'", detail2: "fullWidth, spans 'Branches' and 'Pull requests'", detail3: "fullWidth, spans 'Workspaces' and 'Last commit'" } } ]; const columnNames = { name: 'Repositories', branches: 'Branches', prs: 'Pull requests', workspaces: 'Workspaces', lastCommit: 'Last commit' }; // In this example, expanded rows are tracked by the repo names from each row. This could be any unique identifier. // This is to prevent state from being based on row order index in case we later add sorting. // Note that this behavior is very similar to selection state. const initialExpandedRepoNames = repositories.filter((repo) => !!repo.details).map((repo) => repo.name); // Default to all expanded const [expandedRepoNames, setExpandedRepoNames] = useState(initialExpandedRepoNames); const setRepoExpanded = (repo: Repository, isExpanding = true) => setExpandedRepoNames((prevExpanded) => { const otherExpandedRepoNames = prevExpanded.filter((r) => r !== repo.name); return isExpanding ? [...otherExpandedRepoNames, repo.name] : otherExpandedRepoNames; }); const isRepoExpanded = (repo: Repository) => expandedRepoNames.includes(repo.name); const [isExampleCompact, setIsExampleCompact] = useState(true); return ( setIsExampleCompact(checked)} aria-label="toggle compact variation" id="toggle-compact" name="toggle-compact" /> {repositories.map((repo, rowIndex) => { // Some arbitrary examples of how you could customize the child row based on your needs let childIsFullWidth = false; let childHasNoPadding = false; let detail1Colspan = 1; let detail2Colspan = 1; let detail3Colspan = 1; if (repo.details) { const { detail1, detail2, detail3, detailFormat } = repo.details; const numColumns = 5; childIsFullWidth = [1, 3].includes(detailFormat); childHasNoPadding = [2, 3].includes(detailFormat); if (detail1 && !detail2 && !detail3) { detail1Colspan = !childIsFullWidth ? numColumns : numColumns + 1; // Account for toggle column } else if (detail1 && detail2 && !detail3) { detail1Colspan = 2; detail2Colspan = !childIsFullWidth ? 3 : 4; } else if (detail1 && detail2 && detail3) { detail1Colspan = 2; detail2Colspan = 2; detail3Colspan = !childIsFullWidth ? 1 : 2; } } return ( {repo.details ? ( {!childIsFullWidth ? ) : null} {repo.details.detail2 ? ( ) : null} {repo.details.detail3 ? ( ) : null} ) : null} ); })}
{columnNames.name} {columnNames.branches} {columnNames.prs} {columnNames.workspaces} {columnNames.lastCommit}
setRepoExpanded(repo, !isRepoExpanded(repo)), expandId: 'composable-expandable-example' } : undefined } /> {repo.name} {repo.branches} {repo.prs} {repo.workspaces} {repo.lastCommit}
: null} {repo.details.detail1 ? ( {repo.details.detail1} {repo.details.detail2} {repo.details.detail3}
); };