Skip to content

Commit 2283b01

Browse files
authored
feat(table): add compound expandable fullscreen demo (#7366)
* add support for switching orientation at various breakpoints * update paths * add compound expandable demo * rename demo, add bottom pagination, wip toolbar * PR feedback from mcoker, wrap with card, use flex layout
1 parent ce1bb47 commit 2283b01

File tree

2 files changed

+267
-0
lines changed

2 files changed

+267
-0
lines changed

packages/react-table/src/demos/Table.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import BarsIcon from '@patternfly/react-icons/dist/esm/icons/bars-icon';
2424
import AttentionBellIcon from '@patternfly/react-icons/dist/esm/icons/attention-bell-icon';
2525
import DashboardWrapper from '@patternfly/react-core/src/demos/examples/DashboardWrapper';
2626

27+
import DashboardWrapper from '@patternfly/react-core/src/demos/examples/DashboardWrapper';
28+
2729
### Bulk select
2830

2931
```js isFullscreen
@@ -283,6 +285,11 @@ class BulkSelectTableDemo extends React.Component {
283285
```js isFullscreen file="table-demos/Compact.jsx"
284286
```
285287

288+
### Compound expansion
289+
290+
```js isFullscreen file="table-demos/CompoundExpansion.jsx"
291+
```
292+
286293
### Column management
287294

288295
```js
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
import React from 'react';
2+
import {
3+
ActionsColumn,
4+
TableComposable,
5+
Thead,
6+
Tr,
7+
Th,
8+
Tbody,
9+
Td,
10+
ExpandableRowContent
11+
} from '@patternfly/react-table';
12+
import {
13+
Button,
14+
Card,
15+
Flex,
16+
FlexItem,
17+
Toolbar,
18+
ToolbarContent,
19+
ToolbarGroup,
20+
ToolbarItem,
21+
Pagination,
22+
Select,
23+
SelectVariant,
24+
SelectOption,
25+
PageSection
26+
} from '@patternfly/react-core';
27+
import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
28+
import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon';
29+
import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
30+
import DashboardWrapper from '@patternfly/react-core/src/demos/examples/DashboardWrapper';
31+
import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon';
32+
33+
export const CompoundExpandable = () => {
34+
// In real usage, this data would come from some external source like an API via props.
35+
const [isSelectOpen, setIsSelectOpen] = React.useState(false);
36+
37+
const NestedItemsTable = () => {
38+
// In real usage, this data would come from some external source like an API via props.
39+
const items = [
40+
{ description: 'Item 1', date: 'May 9, 2018', status: 'Active' },
41+
{ description: 'Item 2', date: 'May 9, 2018', status: 'Warning' },
42+
{ description: 'Item 3', date: 'May 9, 2018', status: 'Active' },
43+
{ description: 'Item 4', date: 'May 9, 2018', status: 'Active' },
44+
{ description: 'Item 5', date: 'May 9, 2018', status: 'Active' }
45+
];
46+
47+
const columnNames = {
48+
description: 'Description',
49+
date: 'Date',
50+
status: 'Status'
51+
};
52+
53+
return (
54+
<TableComposable borders={false} aria-label="Nested table" variant="compact">
55+
<Thead>
56+
<Tr>
57+
<Th>{columnNames.description}</Th>
58+
<Th>{columnNames.date}</Th>
59+
<Th>{columnNames.status}</Th>
60+
<Th />
61+
</Tr>
62+
</Thead>
63+
<Tbody>
64+
{items.map(item => (
65+
<Tr key={item.name}>
66+
<Td dataLabel={columnNames.description}>{item.description}</Td>
67+
<Td dataLabel={columnNames.date}>{item.date}</Td>
68+
<Td dataLabel={columnNames.status}>{item.status}</Td>
69+
<Td isActionCell>
70+
<ActionsColumn items={defaultActions()} />
71+
</Td>
72+
</Tr>
73+
))}
74+
</Tbody>
75+
</TableComposable>
76+
);
77+
};
78+
79+
const renderPagination = (variant, isCompact) => (
80+
<Pagination
81+
isCompact={isCompact}
82+
itemCount={36}
83+
page={1}
84+
perPage={10}
85+
variant={variant}
86+
titles={{
87+
paginationTitle: `${variant} pagination`
88+
}}
89+
/>
90+
);
91+
92+
const tableToolbar = (
93+
<Toolbar id="compact-toolbar" usePageInsets>
94+
<ToolbarContent>
95+
<ToolbarItem>
96+
<Select
97+
id="select-example"
98+
variant={SelectVariant.single}
99+
aria-label="Select Input"
100+
placeholderText={
101+
<>
102+
<FilterIcon /> Status
103+
</>
104+
}
105+
isOpen={isSelectOpen}
106+
onToggle={() => setIsSelectOpen(!isSelectOpen)}
107+
onSelect={() => setIsSelectOpen(!isSelectOpen)}
108+
>
109+
{[
110+
<SelectOption key={0} value="Debug" />,
111+
<SelectOption key={1} value="Info" />,
112+
<SelectOption key={2} value="Warn" />,
113+
<SelectOption key={3} value="Error" />
114+
]}
115+
</Select>
116+
</ToolbarItem>
117+
<ToolbarGroup>
118+
<ToolbarItem>
119+
<Button variant="primary">Action</Button>
120+
</ToolbarItem>
121+
</ToolbarGroup>
122+
<ToolbarItem variant="pagination">{renderPagination('top', true)}</ToolbarItem>
123+
</ToolbarContent>
124+
</Toolbar>
125+
);
126+
127+
const defaultActions = () => [
128+
{
129+
title: 'Settings',
130+
// eslint-disable-next-line no-console
131+
onClick: () => console.log(`clicked on Settings`)
132+
},
133+
{
134+
title: 'Help',
135+
// eslint-disable-next-line no-console
136+
onClick: () => console.log(`clicked on Help`)
137+
}
138+
];
139+
140+
const repositories = [
141+
{
142+
name: 'siemur/test-space',
143+
branches: 10,
144+
prs: 4,
145+
workspaces: 4,
146+
lastCommit: '20 minutes'
147+
},
148+
{ name: 'siemur/test-space-2', branches: 3, prs: 4, workspaces: 4, lastCommit: '20 minutes' }
149+
];
150+
151+
const columnNames = {
152+
name: 'Repositories',
153+
branches: 'Branches',
154+
prs: 'Pull requests',
155+
workspaces: 'Workspaces',
156+
lastCommit: 'Last commit'
157+
};
158+
159+
// In this example, expanded cells are tracked by the repo and property names from each row. This could be any pair of unique identifiers.
160+
// This is to prevent state from being based on row and column order index in case we later add sorting and rearranging columns.
161+
// Note that this behavior is very similar to selection state.
162+
const [expandedCells, setExpandedCells] = React.useState({
163+
'siemur/test-space': 'branches' // Default to the first cell of the first row being expanded
164+
});
165+
const setCellExpanded = (repo, columnKey, isExpanding = true) => {
166+
const newExpandedCells = { ...expandedCells };
167+
if (isExpanding) {
168+
newExpandedCells[repo.name] = columnKey;
169+
} else {
170+
delete newExpandedCells[repo.name];
171+
}
172+
setExpandedCells(newExpandedCells);
173+
};
174+
const compoundExpandParams = (repo, columnKey) => ({
175+
isExpanded: expandedCells[repo.name] === columnKey,
176+
onToggle: () => setCellExpanded(repo, columnKey, expandedCells[repo.name] !== columnKey)
177+
});
178+
179+
return (
180+
<DashboardWrapper hasPageTemplateTitle>
181+
<PageSection padding={{ default: 'noPadding', xl: 'padding' }}>
182+
<Card>
183+
{tableToolbar}
184+
<TableComposable aria-label="Compound expandable table">
185+
<Thead>
186+
<Tr>
187+
<Th>{columnNames.name}</Th>
188+
<Th>{columnNames.branches}</Th>
189+
<Th>{columnNames.prs}</Th>
190+
<Th>{columnNames.workspaces}</Th>
191+
<Th>{columnNames.lastCommit}</Th>
192+
<Th />
193+
</Tr>
194+
</Thead>
195+
{repositories.map(repo => {
196+
const expandedCellKey = expandedCells[repo.name];
197+
const isRowExpanded = !!expandedCellKey;
198+
return (
199+
<Tbody key={repo.name} isExpanded={isRowExpanded}>
200+
<Tr>
201+
<Td dataLabel={columnNames.name} component="th">
202+
<a href="#">{repo.name}</a>
203+
</Td>
204+
<Td dataLabel={columnNames.branches} compoundExpand={compoundExpandParams(repo, 'branches')}>
205+
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
206+
<FlexItem>
207+
<CodeBranchIcon key="icon" />
208+
</FlexItem>
209+
<FlexItem>{repo.branches}</FlexItem>
210+
</Flex>
211+
</Td>
212+
<Td dataLabel={columnNames.prs} compoundExpand={compoundExpandParams(repo, 'prs')}>
213+
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
214+
<FlexItem>
215+
<CodeIcon key="icon" />
216+
</FlexItem>
217+
<FlexItem>{repo.prs}</FlexItem>
218+
</Flex>{' '}
219+
</Td>
220+
<Td dataLabel={columnNames.workspaces} compoundExpand={compoundExpandParams(repo, 'workspaces')}>
221+
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
222+
<FlexItem>
223+
<CubeIcon key="icon" />
224+
</FlexItem>
225+
<FlexItem>{repo.workspaces}</FlexItem>
226+
</Flex>
227+
</Td>
228+
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
229+
<Td>
230+
<a href="#">Open in GitHub</a>
231+
</Td>
232+
<Td isActionCell>
233+
<ActionsColumn items={defaultActions()} />
234+
</Td>
235+
</Tr>
236+
{isRowExpanded ? (
237+
<Tr isExpanded={isRowExpanded}>
238+
<Td dataLabel={columnNames[expandedCellKey]} noPadding colSpan={7}>
239+
{expandedCellKey === 'branches' && repo.name === 'siemur/test-space' ? (
240+
<NestedItemsTable />
241+
) : (
242+
<ExpandableRowContent>
243+
<div className="pf-u-m-md">
244+
Expanded content for {repo.name}: {expandedCellKey} goes here!
245+
</div>
246+
</ExpandableRowContent>
247+
)}
248+
</Td>
249+
</Tr>
250+
) : null}
251+
</Tbody>
252+
);
253+
})}
254+
</TableComposable>
255+
{renderPagination('bottom', false)}
256+
</Card>
257+
</PageSection>
258+
</DashboardWrapper>
259+
);
260+
};

0 commit comments

Comments
 (0)