@patternfly/react-table 4.44.12 → 4.44.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/esm/components/Table/Table.d.ts +2 -1
- package/dist/esm/components/Table/Table.d.ts.map +1 -1
- package/dist/esm/components/Table/Table.js.map +1 -1
- package/dist/esm/components/Table/TableTypes.d.ts +2 -1
- package/dist/esm/components/Table/TableTypes.d.ts.map +1 -1
- package/dist/esm/components/Table/TableTypes.js.map +1 -1
- package/dist/esm/components/Table/base/provider.d.ts +2 -2
- package/dist/esm/components/Table/base/types.d.ts +2 -2
- package/dist/esm/components/TableComposable/TableComposable.d.ts +1 -1
- package/dist/esm/components/TableComposable/Td.d.ts +1 -1
- package/dist/js/components/Table/Table.d.ts +2 -1
- package/dist/js/components/Table/Table.d.ts.map +1 -1
- package/dist/js/components/Table/Table.js.map +1 -1
- package/dist/js/components/Table/TableTypes.d.ts +2 -1
- package/dist/js/components/Table/TableTypes.d.ts.map +1 -1
- package/dist/js/components/Table/TableTypes.js.map +1 -1
- package/dist/js/components/Table/base/provider.d.ts +2 -2
- package/dist/js/components/Table/base/types.d.ts +2 -2
- package/dist/js/components/TableComposable/TableComposable.d.ts +1 -1
- package/dist/js/components/TableComposable/Td.d.ts +1 -1
- package/package.json +6 -6
- package/src/components/Table/Table.tsx +2 -1
- package/src/components/Table/TableTypes.tsx +2 -1
- package/src/components/Table/examples/LegacyTableActions.tsx +218 -0
- package/src/components/Table/examples/LegacyTableBasic.tsx +90 -0
- package/src/components/Table/examples/LegacyTableCellWidth.tsx +66 -0
- package/src/components/Table/examples/LegacyTableCompoundExpandable.tsx +175 -0
- package/src/components/Table/examples/LegacyTableControllingText.tsx +51 -0
- package/src/components/Table/examples/LegacyTableEmptyState.tsx +48 -0
- package/src/components/Table/examples/LegacyTableExpandable.tsx +172 -0
- package/src/components/Table/examples/LegacyTableFavoritable.tsx +157 -0
- package/src/components/Table/examples/LegacyTableHoverable.tsx +125 -0
- package/src/components/Table/examples/LegacyTableMisc.tsx +56 -0
- package/src/components/Table/examples/LegacyTableSelectable.tsx +124 -0
- package/src/components/Table/examples/LegacyTableSelectableRadio.tsx +54 -0
- package/src/components/Table/examples/LegacyTableSortable.tsx +120 -0
- package/src/components/Table/examples/LegacyTableSortableCustom.tsx +189 -0
- package/src/components/Table/examples/LegacyTableTextModifiers.tsx +31 -0
- package/src/components/Table/examples/LegacyTableTree.tsx +213 -0
- package/src/components/Table/examples/Table.md +83 -1848
- package/src/components/TableComposable/examples/ComposableTable.md +31 -2805
- package/src/components/TableComposable/examples/ComposableTableActions.tsx +163 -0
- package/src/components/TableComposable/examples/ComposableTableBasic.tsx +89 -0
- package/src/components/TableComposable/examples/ComposableTableCellWidth.tsx +56 -0
- package/src/components/TableComposable/examples/ComposableTableCompoundExpandable.tsx +103 -0
- package/src/components/TableComposable/examples/ComposableTableControllingText.tsx +51 -0
- package/src/components/TableComposable/examples/ComposableTableDraggable.tsx +170 -0
- package/src/components/TableComposable/examples/ComposableTableEmptyState.tsx +45 -0
- package/src/components/TableComposable/examples/ComposableTableExpandable.tsx +195 -0
- package/src/components/TableComposable/examples/ComposableTableFavoritable.tsx +118 -0
- package/src/components/TableComposable/examples/ComposableTableHoverable.tsx +67 -0
- package/src/components/TableComposable/examples/ComposableTableMisc.tsx +92 -0
- package/src/components/TableComposable/examples/ComposableTableMultipleStickyColumns.tsx +153 -0
- package/src/components/TableComposable/examples/ComposableTableNestedExpandable.tsx +127 -0
- package/src/components/TableComposable/examples/ComposableTableNestedHeaders.tsx +202 -0
- package/src/components/TableComposable/examples/ComposableTableSelectable.tsx +125 -0
- package/src/components/TableComposable/examples/ComposableTableSelectableRadio.tsx +68 -0
- package/src/components/TableComposable/examples/ComposableTableSortable.tsx +107 -0
- package/src/components/TableComposable/examples/ComposableTableSortableCustom.tsx +175 -0
- package/src/components/TableComposable/examples/ComposableTableStickyColumn.tsx +144 -0
- package/src/components/TableComposable/examples/ComposableTableStickyColumnsAndHeader.tsx +167 -0
- package/src/components/TableComposable/examples/ComposableTableTextModifiers.tsx +33 -0
- package/src/components/TableComposable/examples/ComposableTableTree.tsx +201 -0
- package/src/demos/Table.md +7 -6
- package/src/components/Table/examples/DemoSortableTable.js +0 -65
- package/src/components/TableComposable/examples/DemoSortableTable.js +0 -65
|
@@ -30,8 +30,6 @@ import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amou
|
|
|
30
30
|
import { css } from '@patternfly/react-styles';
|
|
31
31
|
import styles from '@patternfly/react-styles/css/components/Table/table';
|
|
32
32
|
|
|
33
|
-
import DemoSortableTable from './DemoSortableTable';
|
|
34
|
-
|
|
35
33
|
### Table Columns
|
|
36
34
|
|
|
37
35
|
Array items for columns provided to the `Table`'s `cells` prop, can be simple strings or objects.
|
|
@@ -118,73 +116,7 @@ interface IRowCell {
|
|
|
118
116
|
|
|
119
117
|
### Basic
|
|
120
118
|
|
|
121
|
-
```
|
|
122
|
-
import React from 'react';
|
|
123
|
-
import { Table, TableHeader, TableBody } from '@patternfly/react-table';
|
|
124
|
-
import { ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';
|
|
125
|
-
|
|
126
|
-
class SimpleTable extends React.Component {
|
|
127
|
-
constructor(props) {
|
|
128
|
-
super(props);
|
|
129
|
-
this.state = {
|
|
130
|
-
choice: 'default'
|
|
131
|
-
};
|
|
132
|
-
this.handleItemClick = this.handleItemClick.bind(this);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
handleItemClick(isSelected, event) {
|
|
136
|
-
this.setState({
|
|
137
|
-
choice: event.currentTarget.id
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
render() {
|
|
142
|
-
// need to make a comment to change
|
|
143
|
-
const { choice } = this.state;
|
|
144
|
-
|
|
145
|
-
const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];
|
|
146
|
-
const rows = [
|
|
147
|
-
['Repository one', 'Branch one', 'PR one', 'Workspace one', 'Commit one'],
|
|
148
|
-
['Repository two', 'Branch two', 'PR two', 'Workspace two', 'Commit two'],
|
|
149
|
-
['Repository three', 'Branch three', 'PR three', 'Workspace three', 'Commit three']
|
|
150
|
-
];
|
|
151
|
-
|
|
152
|
-
return (
|
|
153
|
-
<React.Fragment>
|
|
154
|
-
<ToggleGroup aria-label="Default with single selectable">
|
|
155
|
-
<ToggleGroupItem
|
|
156
|
-
text="Default"
|
|
157
|
-
buttonId="default"
|
|
158
|
-
isSelected={choice === 'default'}
|
|
159
|
-
onChange={this.handleItemClick}
|
|
160
|
-
/>
|
|
161
|
-
<ToggleGroupItem
|
|
162
|
-
text="Compact"
|
|
163
|
-
buttonId="compact"
|
|
164
|
-
isSelected={choice === 'compact'}
|
|
165
|
-
onChange={this.handleItemClick}
|
|
166
|
-
/>
|
|
167
|
-
<ToggleGroupItem
|
|
168
|
-
text="Compact without borders"
|
|
169
|
-
buttonId="compactBorderless"
|
|
170
|
-
isSelected={choice === 'compactBorderless'}
|
|
171
|
-
onChange={this.handleItemClick}
|
|
172
|
-
/>
|
|
173
|
-
</ToggleGroup>
|
|
174
|
-
<Table
|
|
175
|
-
aria-label="Simple Table"
|
|
176
|
-
variant={choice !== 'default' ? 'compact' : null}
|
|
177
|
-
borders={choice !== 'compactBorderless'}
|
|
178
|
-
cells={columns}
|
|
179
|
-
rows={rows}
|
|
180
|
-
>
|
|
181
|
-
<TableHeader />
|
|
182
|
-
<TableBody />
|
|
183
|
-
</Table>
|
|
184
|
-
</React.Fragment>
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
119
|
+
```ts file="LegacyTableBasic.tsx"
|
|
188
120
|
```
|
|
189
121
|
|
|
190
122
|
### Custom row wrapper
|
|
@@ -213,60 +145,7 @@ interface RowWrapperProps {
|
|
|
213
145
|
}
|
|
214
146
|
```
|
|
215
147
|
|
|
216
|
-
```
|
|
217
|
-
import React from 'react';
|
|
218
|
-
import { Table, TableHeader, TableBody } from '@patternfly/react-table';
|
|
219
|
-
import { css } from '@patternfly/react-styles';
|
|
220
|
-
|
|
221
|
-
class RowWrapperTable extends React.Component {
|
|
222
|
-
constructor(props) {
|
|
223
|
-
super(props);
|
|
224
|
-
this.state = {
|
|
225
|
-
columns: [{ title: 'Repositories' }, 'Branches', { title: 'Pull requests' }, 'Workspaces'],
|
|
226
|
-
rows: [
|
|
227
|
-
{
|
|
228
|
-
cells: ['Repositories one', 'Branches one', 'Pull requests one', 'Workspaces one']
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
cells: ['Repositories two', 'Branches two', 'Pull requests two', 'Workspaces two']
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
cells: ['Repositories three', 'Branches three', 'Pull requests three', 'Workspaces three']
|
|
235
|
-
}
|
|
236
|
-
]
|
|
237
|
-
};
|
|
238
|
-
this.customRowWrapper = ({ trRef, className, rowProps, row, ...props }) => {
|
|
239
|
-
const isOddRow = (rowProps.rowIndex + 1) % 2;
|
|
240
|
-
const customStyle = {
|
|
241
|
-
borderLeft: '3px solid var(--pf-global--primary-color--100)'
|
|
242
|
-
};
|
|
243
|
-
return (
|
|
244
|
-
<tr
|
|
245
|
-
{...props}
|
|
246
|
-
ref={trRef}
|
|
247
|
-
className={css(className, isOddRow ? 'odd-row-class' : 'even-row-class', 'custom-static-class')}
|
|
248
|
-
style={isOddRow ? customStyle : {}}
|
|
249
|
-
/>
|
|
250
|
-
);
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
render() {
|
|
255
|
-
const { columns, rows } = this.state;
|
|
256
|
-
|
|
257
|
-
return (
|
|
258
|
-
<Table
|
|
259
|
-
caption="Table with custom row wrapper that styles odd rows"
|
|
260
|
-
cells={columns}
|
|
261
|
-
rows={rows}
|
|
262
|
-
rowWrapper={this.customRowWrapper}
|
|
263
|
-
>
|
|
264
|
-
<TableHeader />
|
|
265
|
-
<TableBody />
|
|
266
|
-
</Table>
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
148
|
+
```ts file="LegacyTableMisc.tsx"
|
|
270
149
|
```
|
|
271
150
|
|
|
272
151
|
### Sortable & wrapping column headers
|
|
@@ -279,1388 +158,108 @@ To implement sortable columns:
|
|
|
279
158
|
3. Pass an `onSort` callback to the `Table` component
|
|
280
159
|
`` `onSort` - (event: React.MouseEvent, columnIndex: number, sortByDirection: SortByDirection, extraData: IExtraColumnData) => void; ``
|
|
281
160
|
|
|
282
|
-
Note: If you want to add a tooltip/popover to a sortable header, in the `transforms` array the `info` transform has to precede the `sortable` transform.
|
|
283
|
-
|
|
284
|
-
The built in display for sorting is not fully responsive, as the column headers will be displayed per row when the screen size is small. The example below showcases how sorting may have a custom control display that can be used for small screen sizes.
|
|
285
|
-
|
|
286
|
-
```js
|
|
287
|
-
import React from 'react';
|
|
288
|
-
import {
|
|
289
|
-
Table,
|
|
290
|
-
TableHeader,
|
|
291
|
-
TableBody,
|
|
292
|
-
sortable,
|
|
293
|
-
SortByDirection,
|
|
294
|
-
wrappable,
|
|
295
|
-
cellWidth,
|
|
296
|
-
info
|
|
297
|
-
} from '@patternfly/react-table';
|
|
298
|
-
|
|
299
|
-
class SortableTable extends React.Component {
|
|
300
|
-
constructor(props) {
|
|
301
|
-
super(props);
|
|
302
|
-
this.state = {
|
|
303
|
-
columns: [
|
|
304
|
-
{ title: 'Repositories', transforms: [sortable] },
|
|
305
|
-
{
|
|
306
|
-
title: 'Branches',
|
|
307
|
-
transforms: [
|
|
308
|
-
info({
|
|
309
|
-
tooltip: 'More information about branches'
|
|
310
|
-
}),
|
|
311
|
-
sortable
|
|
312
|
-
]
|
|
313
|
-
},
|
|
314
|
-
{ title: 'Pull requests', transforms: [sortable] },
|
|
315
|
-
{
|
|
316
|
-
title: 'Workspaces - Also this long header will wrap since we have applied the wrappable transform',
|
|
317
|
-
transforms: [sortable, wrappable, cellWidth(20)]
|
|
318
|
-
},
|
|
319
|
-
{
|
|
320
|
-
title: 'Last commit',
|
|
321
|
-
transforms: [
|
|
322
|
-
info({
|
|
323
|
-
tooltip: 'More information about commits'
|
|
324
|
-
})
|
|
325
|
-
]
|
|
326
|
-
}
|
|
327
|
-
],
|
|
328
|
-
rows: [
|
|
329
|
-
['one', 'two', 'a', 'four', 'five'],
|
|
330
|
-
['a', 'two', 'k', 'four', 'five'],
|
|
331
|
-
['p', 'two', 'b', 'four', 'five']
|
|
332
|
-
],
|
|
333
|
-
sortBy: {
|
|
334
|
-
defaultDirection: 'asc' // starting sort direction when first sorting a column. Defaults to 'asc'
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
this.onSort = this.onSort.bind(this);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
onSort(_event, index, direction) {
|
|
341
|
-
const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0));
|
|
342
|
-
this.setState({
|
|
343
|
-
sortBy: {
|
|
344
|
-
index,
|
|
345
|
-
direction
|
|
346
|
-
},
|
|
347
|
-
rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse()
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
render() {
|
|
352
|
-
const { columns, rows, sortBy } = this.state;
|
|
353
|
-
|
|
354
|
-
return (
|
|
355
|
-
<Table aria-label="Sortable Table" sortBy={sortBy} onSort={this.onSort} cells={columns} rows={rows}>
|
|
356
|
-
<TableHeader />
|
|
357
|
-
<TableBody />
|
|
358
|
-
</Table>
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
### Sortable - custom control
|
|
365
|
-
|
|
366
|
-
Sorting a table may also be controlled with a toolbar. This toolbar item may also be hidden at large screen sizes and only displayed when the screen size is small to support responsive tables.
|
|
367
|
-
|
|
368
|
-
```js
|
|
369
|
-
import React from 'react';
|
|
370
|
-
import { Table, TableHeader, TableBody, sortable, SortByDirection, info } from '@patternfly/react-table';
|
|
371
|
-
import {
|
|
372
|
-
Toolbar,
|
|
373
|
-
ToolbarItem,
|
|
374
|
-
ToolbarContent,
|
|
375
|
-
OptionsMenu,
|
|
376
|
-
OptionsMenuItemGroup,
|
|
377
|
-
OptionsMenuItem,
|
|
378
|
-
OptionsMenuSeparator,
|
|
379
|
-
OptionsMenuToggle
|
|
380
|
-
} from '@patternfly/react-core';
|
|
381
|
-
import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon';
|
|
382
|
-
|
|
383
|
-
class SortableTable extends React.Component {
|
|
384
|
-
constructor(props) {
|
|
385
|
-
super(props);
|
|
386
|
-
this.state = {
|
|
387
|
-
columns: [
|
|
388
|
-
{ title: 'Repositories', transforms: [sortable] },
|
|
389
|
-
{
|
|
390
|
-
title: 'Branches',
|
|
391
|
-
transforms: [
|
|
392
|
-
info({
|
|
393
|
-
tooltip: 'More information about branches'
|
|
394
|
-
}),
|
|
395
|
-
sortable
|
|
396
|
-
]
|
|
397
|
-
},
|
|
398
|
-
{ title: 'Pull requests', transforms: [sortable] },
|
|
399
|
-
{
|
|
400
|
-
title: 'Workspaces',
|
|
401
|
-
transforms: [sortable]
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
title: 'Last commit',
|
|
405
|
-
transforms: [
|
|
406
|
-
info({
|
|
407
|
-
tooltip: 'More information about commits'
|
|
408
|
-
}),
|
|
409
|
-
sortable
|
|
410
|
-
]
|
|
411
|
-
}
|
|
412
|
-
],
|
|
413
|
-
rows: [
|
|
414
|
-
['one', 'two', 'a', 'four', 'five'],
|
|
415
|
-
['a', 'five', 'k', 'two', 'three'],
|
|
416
|
-
['p', 'seven', 'b', 'one', 'six']
|
|
417
|
-
],
|
|
418
|
-
sortBy: {},
|
|
419
|
-
isSortDropdownOpen: false
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
this.onSort = this.onSort.bind(this);
|
|
423
|
-
this.onToggle = this.onToggle.bind(this);
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
onSort(_event, index, direction) {
|
|
427
|
-
const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0));
|
|
428
|
-
this.setState({
|
|
429
|
-
sortBy: {
|
|
430
|
-
index,
|
|
431
|
-
direction
|
|
432
|
-
},
|
|
433
|
-
rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse()
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
onToggle(isSortDropdownOpen) {
|
|
438
|
-
this.setState({
|
|
439
|
-
isSortDropdownOpen
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
render() {
|
|
444
|
-
const { columns, rows, sortBy, isSortDropdownOpen } = this.state;
|
|
445
|
-
|
|
446
|
-
return (
|
|
447
|
-
<React.Fragment>
|
|
448
|
-
<Toolbar id="toolbar">
|
|
449
|
-
<ToolbarContent>
|
|
450
|
-
<ToolbarItem>
|
|
451
|
-
<OptionsMenu
|
|
452
|
-
id="options-menu-multiple-options-example"
|
|
453
|
-
menuItems={[
|
|
454
|
-
<OptionsMenuItemGroup key="first group" aria-label="Sort column">
|
|
455
|
-
{columns.map((column, columnIndex) => (
|
|
456
|
-
<OptionsMenuItem
|
|
457
|
-
key={column.title}
|
|
458
|
-
isSelected={sortBy.index === columnIndex}
|
|
459
|
-
onSelect={evt => this.onSort(evt, columnIndex, sortBy.direction ? sortBy.direction : 'asc')}
|
|
460
|
-
>
|
|
461
|
-
{column.title}
|
|
462
|
-
</OptionsMenuItem>
|
|
463
|
-
))}
|
|
464
|
-
</OptionsMenuItemGroup>,
|
|
465
|
-
<OptionsMenuSeparator key="separator" />,
|
|
466
|
-
<OptionsMenuItemGroup key="second group" aria-label="Sort direction">
|
|
467
|
-
<OptionsMenuItem
|
|
468
|
-
onSelect={evt => this.onSort(evt, sortBy.index ? sortBy.index : 0, 'asc')}
|
|
469
|
-
isSelected={sortBy.direction === 'asc'}
|
|
470
|
-
id="ascending"
|
|
471
|
-
key="ascending"
|
|
472
|
-
>
|
|
473
|
-
Ascending
|
|
474
|
-
</OptionsMenuItem>
|
|
475
|
-
<OptionsMenuItem
|
|
476
|
-
onSelect={evt => this.onSort(evt, sortBy.index ? sortBy.index : 0, 'desc')}
|
|
477
|
-
isSelected={sortBy.direction === 'desc'}
|
|
478
|
-
id="descending"
|
|
479
|
-
key="descending"
|
|
480
|
-
>
|
|
481
|
-
Descending
|
|
482
|
-
</OptionsMenuItem>
|
|
483
|
-
</OptionsMenuItemGroup>
|
|
484
|
-
]}
|
|
485
|
-
isOpen={isSortDropdownOpen}
|
|
486
|
-
toggle={
|
|
487
|
-
<OptionsMenuToggle
|
|
488
|
-
hideCaret
|
|
489
|
-
onToggle={() => this.onToggle(!isSortDropdownOpen)}
|
|
490
|
-
toggleTemplate={<SortAmountDownIcon />}
|
|
491
|
-
/>
|
|
492
|
-
}
|
|
493
|
-
isPlain
|
|
494
|
-
isGrouped
|
|
495
|
-
/>
|
|
496
|
-
</ToolbarItem>
|
|
497
|
-
</ToolbarContent>
|
|
498
|
-
</Toolbar>
|
|
499
|
-
<Table aria-label="Sortable Table" sortBy={sortBy} onSort={this.onSort} cells={columns} rows={rows}>
|
|
500
|
-
<TableHeader />
|
|
501
|
-
<TableBody />
|
|
502
|
-
</Table>
|
|
503
|
-
</React.Fragment>
|
|
504
|
-
);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
```
|
|
508
|
-
|
|
509
|
-
### Selectable with checkbox
|
|
510
|
-
|
|
511
|
-
To enable row selection, set the `onSelect` callback prop on the Table.
|
|
512
|
-
|
|
513
|
-
To control whether a row is selected or not, the Table looks for `selected: true | falsy` on the row definition.
|
|
514
|
-
|
|
515
|
-
To disable selection for a row, set `disableSelection: true` on the row definition.
|
|
516
|
-
|
|
517
|
-
To include a 'select all' checkbox in the header row, pass `true` to the`canSelectAll` prop on the Table.
|
|
518
|
-
|
|
519
|
-
Note: this example also demonstrates the use of the `headerCol` transformation being applied to the first
|
|
520
|
-
column via the `cellTransforms` in the column definition. `headerCol` transforms the column so that instead
|
|
521
|
-
of using `td` elements, the cells in that column use `th` elements.
|
|
522
|
-
|
|
523
|
-
```js
|
|
524
|
-
import React from 'react';
|
|
525
|
-
import { Table, TableHeader, TableBody, headerCol } from '@patternfly/react-table';
|
|
526
|
-
import { Checkbox } from '@patternfly/react-core';
|
|
527
|
-
|
|
528
|
-
class SelectableTable extends React.Component {
|
|
529
|
-
constructor(props) {
|
|
530
|
-
super(props);
|
|
531
|
-
this.state = {
|
|
532
|
-
columns: [
|
|
533
|
-
{ title: 'Repositories', cellTransforms: [headerCol()] },
|
|
534
|
-
'Branches',
|
|
535
|
-
{ title: 'Pull requests' },
|
|
536
|
-
'Workspaces',
|
|
537
|
-
'Last commit'
|
|
538
|
-
],
|
|
539
|
-
rows: [
|
|
540
|
-
{
|
|
541
|
-
cells: ['one', 'two', 'a', 'four', 'five']
|
|
542
|
-
},
|
|
543
|
-
{
|
|
544
|
-
cells: ['a', 'two', 'k', 'four', 'five'],
|
|
545
|
-
disableSelection: true
|
|
546
|
-
},
|
|
547
|
-
{
|
|
548
|
-
cells: ['p', 'two', 'b', 'four', 'five']
|
|
549
|
-
}
|
|
550
|
-
],
|
|
551
|
-
canSelectAll: true
|
|
552
|
-
};
|
|
553
|
-
this.onSelect = this.onSelect.bind(this);
|
|
554
|
-
this.toggleSelect = this.toggleSelect.bind(this);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
onSelect(event, isSelected, rowId) {
|
|
558
|
-
let rows;
|
|
559
|
-
if (rowId === -1) {
|
|
560
|
-
rows = this.state.rows.map(oneRow => {
|
|
561
|
-
if (!oneRow.disableSelection) {
|
|
562
|
-
oneRow.selected = isSelected;
|
|
563
|
-
}
|
|
564
|
-
return oneRow;
|
|
565
|
-
});
|
|
566
|
-
} else {
|
|
567
|
-
rows = [...this.state.rows];
|
|
568
|
-
rows[rowId].selected = isSelected;
|
|
569
|
-
}
|
|
570
|
-
this.setState({
|
|
571
|
-
rows
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
toggleSelect(checked) {
|
|
576
|
-
this.setState({
|
|
577
|
-
canSelectAll: checked
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
render() {
|
|
582
|
-
const { columns, rows, canSelectAll } = this.state;
|
|
583
|
-
|
|
584
|
-
return (
|
|
585
|
-
<div>
|
|
586
|
-
<Checkbox
|
|
587
|
-
label="Can select all"
|
|
588
|
-
className="pf-u-mb-lg"
|
|
589
|
-
isChecked={canSelectAll}
|
|
590
|
-
onChange={this.toggleSelect}
|
|
591
|
-
aria-label="toggle select all checkbox"
|
|
592
|
-
id="toggle-select-all"
|
|
593
|
-
name="toggle-select-all"
|
|
594
|
-
/>
|
|
595
|
-
<Table
|
|
596
|
-
onSelect={this.onSelect}
|
|
597
|
-
canSelectAll={canSelectAll}
|
|
598
|
-
aria-label="Selectable Table"
|
|
599
|
-
cells={columns}
|
|
600
|
-
rows={rows}
|
|
601
|
-
>
|
|
602
|
-
<TableHeader />
|
|
603
|
-
<TableBody />
|
|
604
|
-
</Table>
|
|
605
|
-
</div>
|
|
606
|
-
);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
### Selectable radio input
|
|
612
|
-
|
|
613
|
-
To enable row radio selection, set the `onSelect` callback prop on the Table, and set `RowSelectVariant.radio` as the
|
|
614
|
-
`selectVariant` prop on the Table.
|
|
615
|
-
|
|
616
|
-
To disable selection for a row, set `disableSelection: true` on the row definition.
|
|
617
|
-
|
|
618
|
-
```js
|
|
619
|
-
import React from 'react';
|
|
620
|
-
import { Table, TableHeader, TableBody, RowSelectVariant, headerCol } from '@patternfly/react-table';
|
|
621
|
-
|
|
622
|
-
class SelectableTable extends React.Component {
|
|
623
|
-
constructor(props) {
|
|
624
|
-
super(props);
|
|
625
|
-
this.state = {
|
|
626
|
-
columns: [
|
|
627
|
-
{ title: 'Repositories', cellTransforms: [headerCol()] },
|
|
628
|
-
'Branches',
|
|
629
|
-
{ title: 'Pull requests' },
|
|
630
|
-
'Workspaces',
|
|
631
|
-
'Last commit'
|
|
632
|
-
],
|
|
633
|
-
rows: [
|
|
634
|
-
{
|
|
635
|
-
cells: ['one', 'two', 'a', 'four', 'five']
|
|
636
|
-
},
|
|
637
|
-
{
|
|
638
|
-
cells: ['a', 'two', 'k', 'four', 'five'],
|
|
639
|
-
disableSelection: true
|
|
640
|
-
},
|
|
641
|
-
{
|
|
642
|
-
cells: ['p', 'two', 'b', 'four', 'five']
|
|
643
|
-
}
|
|
644
|
-
]
|
|
645
|
-
};
|
|
646
|
-
this.onSelect = this.onSelect.bind(this);
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
onSelect(event, isSelected, rowId) {
|
|
650
|
-
let rows = this.state.rows.map((oneRow, index) => {
|
|
651
|
-
oneRow.selected = rowId === index;
|
|
652
|
-
return oneRow;
|
|
653
|
-
});
|
|
654
|
-
this.setState({
|
|
655
|
-
rows
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
render() {
|
|
660
|
-
const { columns, rows } = this.state;
|
|
661
|
-
|
|
662
|
-
return (
|
|
663
|
-
<Table
|
|
664
|
-
onSelect={this.onSelect}
|
|
665
|
-
selectVariant={RowSelectVariant.radio}
|
|
666
|
-
aria-label="Selectable Table"
|
|
667
|
-
cells={columns}
|
|
668
|
-
rows={rows}
|
|
669
|
-
>
|
|
670
|
-
<TableHeader />
|
|
671
|
-
<TableBody />
|
|
672
|
-
</Table>
|
|
673
|
-
);
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
```
|
|
677
|
-
|
|
678
|
-
### Hoverable rows, selectable rows, and header cell tooltips/popovers
|
|
679
|
-
|
|
680
|
-
This selectable rows feature is intended for use when a table is used to present a list of objects in a Primary-detail view.
|
|
681
|
-
|
|
682
|
-
```js
|
|
683
|
-
import React from 'react';
|
|
684
|
-
import { Table, TableHeader, TableBody, textCenter } from '@patternfly/react-table';
|
|
685
|
-
import styles from '@patternfly/react-styles/css/components/Table/table';
|
|
686
|
-
|
|
687
|
-
class RowClickTable extends React.Component {
|
|
688
|
-
constructor(props) {
|
|
689
|
-
super(props);
|
|
690
|
-
this.state = {
|
|
691
|
-
columns: [
|
|
692
|
-
{
|
|
693
|
-
title: 'Repositories',
|
|
694
|
-
transforms: [
|
|
695
|
-
info({
|
|
696
|
-
tooltip: 'More information about repositories',
|
|
697
|
-
className: 'repositories-info-tip',
|
|
698
|
-
tooltipProps: {
|
|
699
|
-
isContentLeftAligned: true
|
|
700
|
-
}
|
|
701
|
-
})
|
|
702
|
-
]
|
|
703
|
-
},
|
|
704
|
-
'Branches',
|
|
705
|
-
{
|
|
706
|
-
title: 'Pull requests',
|
|
707
|
-
transforms: [
|
|
708
|
-
info({
|
|
709
|
-
popover: (
|
|
710
|
-
<div>
|
|
711
|
-
More <strong>information</strong> on pull requests
|
|
712
|
-
</div>
|
|
713
|
-
),
|
|
714
|
-
ariaLabel: 'More information on pull requests',
|
|
715
|
-
popoverProps: {
|
|
716
|
-
headerContent: 'Pull requests',
|
|
717
|
-
footerContent: <a href="">Click here for even more info</a>
|
|
718
|
-
}
|
|
719
|
-
})
|
|
720
|
-
]
|
|
721
|
-
},
|
|
722
|
-
'Workspaces',
|
|
723
|
-
{
|
|
724
|
-
title: 'Last commit',
|
|
725
|
-
transforms: [textCenter],
|
|
726
|
-
cellTransforms: [textCenter]
|
|
727
|
-
}
|
|
728
|
-
],
|
|
729
|
-
rows: [
|
|
730
|
-
{
|
|
731
|
-
cells: ['Repository one', 'Branch one', 'PR one', 'Workspace one', 'Commit one'],
|
|
732
|
-
isHoverable: true,
|
|
733
|
-
isRowSelected: false
|
|
734
|
-
},
|
|
735
|
-
{
|
|
736
|
-
cells: [
|
|
737
|
-
{
|
|
738
|
-
title: <div>one - 2</div>,
|
|
739
|
-
props: { title: 'hover title', colSpan: 3 }
|
|
740
|
-
},
|
|
741
|
-
'four - 2',
|
|
742
|
-
'five - 2'
|
|
743
|
-
],
|
|
744
|
-
isHoverable: true,
|
|
745
|
-
isRowSelected: false
|
|
746
|
-
},
|
|
747
|
-
{
|
|
748
|
-
cells: [
|
|
749
|
-
'one - 3',
|
|
750
|
-
'two - 3',
|
|
751
|
-
'three - 3',
|
|
752
|
-
'four - 3',
|
|
753
|
-
{
|
|
754
|
-
title: 'five - 3 (not centered)',
|
|
755
|
-
props: { textCenter: false }
|
|
756
|
-
}
|
|
757
|
-
],
|
|
758
|
-
isHoverable: true,
|
|
759
|
-
isRowSelected: false
|
|
760
|
-
}
|
|
761
|
-
]
|
|
762
|
-
};
|
|
763
|
-
|
|
764
|
-
this.rowClickHandler = (event, row, rowProps) => {
|
|
765
|
-
this.setState(prevState => {
|
|
766
|
-
const updatedRows = [...prevState.rows];
|
|
767
|
-
updatedRows[rowProps.rowIndex].isRowSelected = !prevState.rows[rowProps.rowIndex].isRowSelected;
|
|
768
|
-
return {
|
|
769
|
-
rows: updatedRows
|
|
770
|
-
};
|
|
771
|
-
});
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
render() {
|
|
776
|
-
const { columns, rows } = this.state;
|
|
777
|
-
|
|
778
|
-
return (
|
|
779
|
-
<Table caption="Row click handler table" cells={columns} rows={rows}>
|
|
780
|
-
<TableHeader className={styles.modifiers.nowrap} />
|
|
781
|
-
<TableBody onRowClick={this.rowClickHandler} />
|
|
782
|
-
</Table>
|
|
783
|
-
);
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
```
|
|
787
|
-
|
|
788
|
-
### Actions and first cell in body rows as th
|
|
789
|
-
|
|
790
|
-
To use actions you can either specify an array of actions and pass that into the `Table`'s `actions` prop, or for more control you can use the `actionResolver` callback prop to add actions conditionally.
|
|
791
|
-
|
|
792
|
-
```js
|
|
793
|
-
import React from 'react';
|
|
794
|
-
import { Table, TableHeader, TableBody, headerCol } from '@patternfly/react-table';
|
|
795
|
-
import {
|
|
796
|
-
ButtonVariant,
|
|
797
|
-
Checkbox,
|
|
798
|
-
DropdownToggle,
|
|
799
|
-
ToggleGroup,
|
|
800
|
-
ToggleGroupItem,
|
|
801
|
-
Toolbar,
|
|
802
|
-
ToolbarContent,
|
|
803
|
-
ToolbarItem
|
|
804
|
-
} from '@patternfly/react-core';
|
|
805
|
-
|
|
806
|
-
class ActionsTable extends React.Component {
|
|
807
|
-
constructor(props) {
|
|
808
|
-
super(props);
|
|
809
|
-
this.state = {
|
|
810
|
-
propToUse: 'actions',
|
|
811
|
-
useCustomToggle: false,
|
|
812
|
-
useExtraAction: false,
|
|
813
|
-
columns: [
|
|
814
|
-
{ title: 'Repositories', cellTransforms: [headerCol()] },
|
|
815
|
-
'Branches',
|
|
816
|
-
{ title: 'Pull requests' },
|
|
817
|
-
'Workspaces',
|
|
818
|
-
'Last commit'
|
|
819
|
-
],
|
|
820
|
-
rows: [
|
|
821
|
-
{
|
|
822
|
-
cells: ['a', 'two', 1, 'four', 'five']
|
|
823
|
-
},
|
|
824
|
-
{
|
|
825
|
-
cells: ['disable actions', 'two', 3, 'four', 'five'],
|
|
826
|
-
disableActions: true
|
|
827
|
-
},
|
|
828
|
-
{
|
|
829
|
-
cells: ['green actions', 'two', 4, 'four', 'five'],
|
|
830
|
-
type: 'green'
|
|
831
|
-
},
|
|
832
|
-
{
|
|
833
|
-
cells: ['extra action props', 'two', 5, 'four', 'five'],
|
|
834
|
-
actionProps: {
|
|
835
|
-
'data-specific-attr': 'some-value'
|
|
836
|
-
}
|
|
837
|
-
},
|
|
838
|
-
{
|
|
839
|
-
cells: ['blue actions', 'two', 6, 'four', 'five'],
|
|
840
|
-
type: 'blue'
|
|
841
|
-
}
|
|
842
|
-
]
|
|
843
|
-
};
|
|
844
|
-
this.handleItemClick = this.handleItemClick.bind(this);
|
|
845
|
-
this.toggleCustomToggle = this.toggleCustomToggle.bind(this);
|
|
846
|
-
this.toggleExtraAction = this.toggleExtraAction.bind(this);
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
/**
|
|
850
|
-
* Use actions or actionResolver, not both
|
|
851
|
-
*/
|
|
852
|
-
actions() {
|
|
853
|
-
return [
|
|
854
|
-
{
|
|
855
|
-
title: 'Some action',
|
|
856
|
-
onClick: (event, rowId, rowData, extra) => console.log('clicked on Some action, on row: ', rowId)
|
|
857
|
-
},
|
|
858
|
-
{
|
|
859
|
-
title: <a href="https://www.patternfly.org">Link action</a>
|
|
860
|
-
},
|
|
861
|
-
{
|
|
862
|
-
isSeparator: true
|
|
863
|
-
},
|
|
864
|
-
{
|
|
865
|
-
title: 'Third action',
|
|
866
|
-
onClick: (event, rowId, rowData, extra) => console.log('clicked on Third action, on row: ', rowId)
|
|
867
|
-
},
|
|
868
|
-
...(this.state.useExtraAction
|
|
869
|
-
? [
|
|
870
|
-
{
|
|
871
|
-
title: 'Start',
|
|
872
|
-
variant: ButtonVariant.secondary,
|
|
873
|
-
onClick: (event, rowId, rowData, extra) => console.log('clicked on extra action on row: ', rowId),
|
|
874
|
-
isOutsideDropdown: true
|
|
875
|
-
}
|
|
876
|
-
]
|
|
877
|
-
: [])
|
|
878
|
-
];
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
/**
|
|
882
|
-
* Use actions or actionResolver, not both
|
|
883
|
-
*/
|
|
884
|
-
actionResolver(rowData, { rowIndex }) {
|
|
885
|
-
if (rowIndex === 1) {
|
|
886
|
-
return null;
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
const thirdAction = rowData.type
|
|
890
|
-
? [
|
|
891
|
-
{
|
|
892
|
-
isSeparator: true
|
|
893
|
-
},
|
|
894
|
-
{
|
|
895
|
-
title: `${rowData.type} action`,
|
|
896
|
-
onClick: (event, rowId, rowData, extra) =>
|
|
897
|
-
console.log(`clicked on ${rowData.type} action, on row ${rowId} of type ${rowData.type}`)
|
|
898
|
-
}
|
|
899
|
-
]
|
|
900
|
-
: [];
|
|
901
|
-
|
|
902
|
-
return [
|
|
903
|
-
{
|
|
904
|
-
title: 'actionResolver action',
|
|
905
|
-
onClick: (event, rowId, rowData, extra) =>
|
|
906
|
-
console.log(`clicked on Some action, on row ${rowId} of type ${rowData.type}`)
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
title: <div>Another action</div>,
|
|
910
|
-
onClick: (event, rowId, rowData, extra) =>
|
|
911
|
-
console.log(`clicked on Another action, on row ${rowId} of type ${rowData.type}`)
|
|
912
|
-
},
|
|
913
|
-
...thirdAction
|
|
914
|
-
];
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
/**
|
|
918
|
-
* Use actions or actionResolver, not both
|
|
919
|
-
*/
|
|
920
|
-
actionResolverWithActions(rowData, { rowIndex }) {
|
|
921
|
-
if (rowIndex === 1) {
|
|
922
|
-
return null;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
const thirdAction = rowData.type
|
|
926
|
-
? [
|
|
927
|
-
{
|
|
928
|
-
isSeparator: true
|
|
929
|
-
},
|
|
930
|
-
{
|
|
931
|
-
title: `${rowData.type} action`,
|
|
932
|
-
onClick: (event, rowId, rowData, extra) =>
|
|
933
|
-
console.log(`clicked on ${rowData.type} action, on row ${rowId} of type ${rowData.type}`)
|
|
934
|
-
}
|
|
935
|
-
]
|
|
936
|
-
: [];
|
|
937
|
-
|
|
938
|
-
return [
|
|
939
|
-
{
|
|
940
|
-
title: 'Start',
|
|
941
|
-
variant: ButtonVariant.secondary,
|
|
942
|
-
onClick: (event, rowId, rowData, extra) => console.log('clicked on extra action on row: ', rowId),
|
|
943
|
-
isOutsideDropdown: true
|
|
944
|
-
},
|
|
945
|
-
{
|
|
946
|
-
title: 'actionResolver action',
|
|
947
|
-
onClick: (event, rowId, rowData, extra) =>
|
|
948
|
-
console.log(`clicked on Some action, on row ${rowId} of type ${rowData.type}`)
|
|
949
|
-
},
|
|
950
|
-
{
|
|
951
|
-
title: <div>Another action</div>,
|
|
952
|
-
onClick: (event, rowId, rowData, extra) =>
|
|
953
|
-
console.log(`clicked on Another action, on row ${rowId} of type ${rowData.type}`)
|
|
954
|
-
},
|
|
955
|
-
...thirdAction
|
|
956
|
-
];
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
areActionsDisabled(rowData, { rowIndex }) {
|
|
960
|
-
return rowIndex === 3;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
handleItemClick(isSelected, event) {
|
|
964
|
-
const action = event.currentTarget.id;
|
|
965
|
-
this.setState({
|
|
966
|
-
propToUse: action
|
|
967
|
-
});
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
toggleCustomToggle(checked) {
|
|
971
|
-
this.setState({
|
|
972
|
-
useCustomToggle: checked
|
|
973
|
-
});
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
toggleExtraAction(checked) {
|
|
977
|
-
this.setState({
|
|
978
|
-
useExtraAction: checked
|
|
979
|
-
});
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
render() {
|
|
983
|
-
const { columns, rows, propToUse, useCustomToggle, useExtraAction } = this.state;
|
|
984
|
-
|
|
985
|
-
const customActionsToggle = props => (
|
|
986
|
-
<DropdownToggle onToggle={props.onToggle} isDisabled={props.isDisabled}>
|
|
987
|
-
Actions
|
|
988
|
-
</DropdownToggle>
|
|
989
|
-
);
|
|
990
|
-
|
|
991
|
-
return (
|
|
992
|
-
<React.Fragment>
|
|
993
|
-
<Toolbar>
|
|
994
|
-
<ToolbarContent>
|
|
995
|
-
<ToolbarItem>
|
|
996
|
-
<ToggleGroup aria-label="actions or actionResolver">
|
|
997
|
-
<ToggleGroupItem
|
|
998
|
-
text="Use actions prop"
|
|
999
|
-
buttonId="actions"
|
|
1000
|
-
isSelected={propToUse === 'actions'}
|
|
1001
|
-
onChange={this.handleItemClick}
|
|
1002
|
-
/>
|
|
1003
|
-
<ToggleGroupItem
|
|
1004
|
-
text="Use actionResolver prop"
|
|
1005
|
-
buttonId="actionResolver"
|
|
1006
|
-
isSelected={propToUse === 'actionResolver'}
|
|
1007
|
-
onChange={this.handleItemClick}
|
|
1008
|
-
/>
|
|
1009
|
-
</ToggleGroup>
|
|
1010
|
-
</ToolbarItem>
|
|
1011
|
-
<ToolbarItem>
|
|
1012
|
-
<Checkbox
|
|
1013
|
-
label="Use custom actions toggle"
|
|
1014
|
-
isChecked={useCustomToggle}
|
|
1015
|
-
onChange={this.toggleCustomToggle}
|
|
1016
|
-
aria-label="toggle use of custom actions toggle"
|
|
1017
|
-
id="toggle-custom-actions-toggle"
|
|
1018
|
-
name="toggle-custom-actions-toggle"
|
|
1019
|
-
/>
|
|
1020
|
-
</ToolbarItem>
|
|
1021
|
-
<ToolbarItem>
|
|
1022
|
-
<Checkbox
|
|
1023
|
-
label="Add extra actions"
|
|
1024
|
-
isChecked={useExtraAction}
|
|
1025
|
-
onChange={this.toggleExtraAction}
|
|
1026
|
-
aria-label="toggle extra actions"
|
|
1027
|
-
id="toggle-extra-action"
|
|
1028
|
-
name="toggle-extra-action"
|
|
1029
|
-
/>
|
|
1030
|
-
</ToolbarItem>
|
|
1031
|
-
</ToolbarContent>
|
|
1032
|
-
</Toolbar>
|
|
1033
|
-
<Table
|
|
1034
|
-
aria-label="Actions table"
|
|
1035
|
-
cells={columns}
|
|
1036
|
-
rows={rows}
|
|
1037
|
-
actions={propToUse === 'actions' ? this.actions() : null}
|
|
1038
|
-
{...(propToUse === 'actionResolver' && {
|
|
1039
|
-
actionResolver: useExtraAction ? this.actionResolverWithActions : this.actionResolver
|
|
1040
|
-
})}
|
|
1041
|
-
areActionsDisabled={this.areActionsDisabled}
|
|
1042
|
-
dropdownPosition="left"
|
|
1043
|
-
dropdownDirection="bottom"
|
|
1044
|
-
actionsToggle={useCustomToggle ? customActionsToggle : undefined}
|
|
1045
|
-
>
|
|
1046
|
-
<TableHeader />
|
|
1047
|
-
<TableBody />
|
|
1048
|
-
</Table>
|
|
1049
|
-
</React.Fragment>
|
|
1050
|
-
);
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
```
|
|
1054
|
-
|
|
1055
|
-
### Expandable
|
|
1056
|
-
|
|
1057
|
-
To make an exapandable row, define a child row with the `parent` field set to its parent's row index.
|
|
1058
|
-
The parent row can have an `isOpen` field for managing the expanded state of the parent row.
|
|
1059
|
-
|
|
1060
|
-
Also, pass an `onCollapse` event handler via the prop on the Table
|
|
1061
|
-
|
|
1062
|
-
```js
|
|
1063
|
-
import React from 'react';
|
|
1064
|
-
import { Table, TableHeader, TableBody, TableVariant, expandable } from '@patternfly/react-table';
|
|
1065
|
-
import { Checkbox } from '@patternfly/react-core';
|
|
1066
|
-
|
|
1067
|
-
class CompactExpandableTable extends React.Component {
|
|
1068
|
-
constructor(props) {
|
|
1069
|
-
super(props);
|
|
1070
|
-
this.state = {
|
|
1071
|
-
isCompact: true,
|
|
1072
|
-
columns: [
|
|
1073
|
-
{
|
|
1074
|
-
title: 'ID',
|
|
1075
|
-
cellFormatters: [expandable]
|
|
1076
|
-
},
|
|
1077
|
-
'Branches',
|
|
1078
|
-
{ title: 'Pull requests' },
|
|
1079
|
-
{ title: '' /* deliberately empty */, dataLabel: 'Label for mobile view' }
|
|
1080
|
-
],
|
|
1081
|
-
rows: [
|
|
1082
|
-
{
|
|
1083
|
-
cells: ['one', 'two', 'three', 'four']
|
|
1084
|
-
},
|
|
1085
|
-
{
|
|
1086
|
-
isOpen: true,
|
|
1087
|
-
cells: ['parent - 1', 'two', 'three', 'four']
|
|
1088
|
-
},
|
|
1089
|
-
{
|
|
1090
|
-
parent: 1,
|
|
1091
|
-
cells: ['single cell']
|
|
1092
|
-
},
|
|
1093
|
-
{
|
|
1094
|
-
isOpen: true,
|
|
1095
|
-
cells: ['parent - 2', 'two', 'three', 'four']
|
|
1096
|
-
},
|
|
1097
|
-
{
|
|
1098
|
-
parent: 3,
|
|
1099
|
-
fullWidth: true,
|
|
1100
|
-
cells: ['single cell - fullWidth']
|
|
1101
|
-
},
|
|
1102
|
-
{
|
|
1103
|
-
isOpen: true,
|
|
1104
|
-
cells: ['parent - 3', 'two', 'three', 'four']
|
|
1105
|
-
},
|
|
1106
|
-
{
|
|
1107
|
-
parent: 5,
|
|
1108
|
-
noPadding: true,
|
|
1109
|
-
cells: ['single cell - noPadding']
|
|
1110
|
-
},
|
|
1111
|
-
{
|
|
1112
|
-
isOpen: true,
|
|
1113
|
-
cells: ['parent - 4', 'two', 'three', 'four']
|
|
1114
|
-
},
|
|
1115
|
-
{
|
|
1116
|
-
parent: 7,
|
|
1117
|
-
noPadding: true,
|
|
1118
|
-
fullWidth: true,
|
|
1119
|
-
cells: ['single cell - fullWidth & noPadding']
|
|
1120
|
-
},
|
|
1121
|
-
{
|
|
1122
|
-
isOpen: true,
|
|
1123
|
-
cells: ['parent - 5', 'two', 'three', 'four']
|
|
1124
|
-
},
|
|
1125
|
-
{
|
|
1126
|
-
parent: 9,
|
|
1127
|
-
cells: [
|
|
1128
|
-
{
|
|
1129
|
-
title: "spans 'Header cell' and 'Branches'",
|
|
1130
|
-
props: {
|
|
1131
|
-
colSpan: 2
|
|
1132
|
-
}
|
|
1133
|
-
},
|
|
1134
|
-
{
|
|
1135
|
-
title: "spans 'Pull requests' and the empty column",
|
|
1136
|
-
props: {
|
|
1137
|
-
colSpan: 2
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
]
|
|
1141
|
-
},
|
|
1142
|
-
{
|
|
1143
|
-
isOpen: true,
|
|
1144
|
-
cells: ['parent - 6', 'two', 'three', 'four']
|
|
1145
|
-
},
|
|
1146
|
-
{
|
|
1147
|
-
parent: 11,
|
|
1148
|
-
fullWidth: true,
|
|
1149
|
-
cells: [
|
|
1150
|
-
{
|
|
1151
|
-
title: "fullWidth, spans the collapsible column and 'Header cell'",
|
|
1152
|
-
props: {
|
|
1153
|
-
colSpan: 2
|
|
1154
|
-
}
|
|
1155
|
-
},
|
|
1156
|
-
{
|
|
1157
|
-
title: "fullWidth, spans 'Branches' and 'Pull requests'",
|
|
1158
|
-
props: {
|
|
1159
|
-
colSpan: 2
|
|
1160
|
-
}
|
|
1161
|
-
},
|
|
1162
|
-
'fullWidth, spans the empty column'
|
|
1163
|
-
]
|
|
1164
|
-
}
|
|
1165
|
-
]
|
|
1166
|
-
};
|
|
1167
|
-
this.onCollapse = this.onCollapse.bind(this);
|
|
1168
|
-
this.toggleCompact = this.toggleCompact.bind(this);
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
onCollapse(event, rowKey, isOpen) {
|
|
1172
|
-
const { rows } = this.state;
|
|
1173
|
-
/**
|
|
1174
|
-
* Please do not use rowKey as row index for more complex tables.
|
|
1175
|
-
* Rather use some kind of identifier like ID passed with each row.
|
|
1176
|
-
*/
|
|
1177
|
-
rows[rowKey].isOpen = isOpen;
|
|
1178
|
-
this.setState({
|
|
1179
|
-
rows
|
|
1180
|
-
});
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
toggleCompact(checked) {
|
|
1184
|
-
this.setState({
|
|
1185
|
-
isCompact: checked
|
|
1186
|
-
});
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
render() {
|
|
1190
|
-
const { columns, rows, isCompact } = this.state;
|
|
1191
|
-
|
|
1192
|
-
return (
|
|
1193
|
-
<React.Fragment>
|
|
1194
|
-
<Checkbox
|
|
1195
|
-
label="Compact"
|
|
1196
|
-
isChecked={isCompact}
|
|
1197
|
-
onChange={this.toggleCompact}
|
|
1198
|
-
aria-label="toggle compact variation"
|
|
1199
|
-
id="toggle-compact"
|
|
1200
|
-
name="toggle-compact"
|
|
1201
|
-
/>
|
|
1202
|
-
<Table
|
|
1203
|
-
aria-label="Expandable table"
|
|
1204
|
-
variant={isCompact ? TableVariant.compact : null}
|
|
1205
|
-
onCollapse={this.onCollapse}
|
|
1206
|
-
rows={rows}
|
|
1207
|
-
cells={columns}
|
|
1208
|
-
>
|
|
1209
|
-
<TableHeader />
|
|
1210
|
-
<TableBody />
|
|
1211
|
-
</Table>
|
|
1212
|
-
</React.Fragment>
|
|
1213
|
-
);
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
```
|
|
1217
|
-
|
|
1218
|
-
### Compound expandable
|
|
1219
|
-
|
|
1220
|
-
To build a compound expandable table:
|
|
1221
|
-
|
|
1222
|
-
1. Pass the `compoundExpand` transformation via the `cellTransforms` field in the column definition for each column that will have an expanded section.
|
|
1223
|
-
2. For each expandable parent row, the cells in the expandable columns should:
|
|
1224
|
-
1. have a managed `isOpen` prop passed to the cell definition
|
|
1225
|
-
2. have an `ariaControls` value which matches the `id` of it’s child row
|
|
1226
|
-
3. For each expandable child row, the row definition needs:
|
|
1227
|
-
1. A `parent` field set to its parent’s row index
|
|
1228
|
-
2. A `compoundParent` field set to the cell index which will control the expanding/collapsing of this row
|
|
1229
|
-
4. An `onExpand` event handler prop should be passed to the Table.
|
|
1230
|
-
|
|
1231
|
-
```js
|
|
1232
|
-
import React from 'react';
|
|
1233
|
-
import { Table, TableHeader, TableBody, compoundExpand } from '@patternfly/react-table';
|
|
1234
|
-
|
|
1235
|
-
import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
|
|
1236
|
-
import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon';
|
|
1237
|
-
import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
|
|
1238
|
-
|
|
1239
|
-
// https://github.com/patternfly/patternfly-react/blob/main/packages/react-table/src/components/Table/composable-table-examples/DemoSortableTable.js
|
|
1240
|
-
import DemoSortableTable from './DemoSortableTable';
|
|
1241
|
-
|
|
1242
|
-
class CompoundExpandableTable extends React.Component {
|
|
1243
|
-
constructor(props) {
|
|
1244
|
-
super(props);
|
|
1245
|
-
this.state = {
|
|
1246
|
-
columns: [
|
|
1247
|
-
'Repositories',
|
|
1248
|
-
{
|
|
1249
|
-
title: 'Branches',
|
|
1250
|
-
cellTransforms: [compoundExpand]
|
|
1251
|
-
},
|
|
1252
|
-
{
|
|
1253
|
-
title: 'Pull requests',
|
|
1254
|
-
cellTransforms: [compoundExpand]
|
|
1255
|
-
},
|
|
1256
|
-
{
|
|
1257
|
-
title: 'Workspaces',
|
|
1258
|
-
cellTransforms: [compoundExpand]
|
|
1259
|
-
},
|
|
1260
|
-
'Last Commit',
|
|
1261
|
-
{
|
|
1262
|
-
title: '',
|
|
1263
|
-
dataLabel: 'Action'
|
|
1264
|
-
}
|
|
1265
|
-
],
|
|
1266
|
-
rows: [
|
|
1267
|
-
{
|
|
1268
|
-
isOpen: true,
|
|
1269
|
-
cells: [
|
|
1270
|
-
{ title: <a href="#">siemur/test-space</a>, props: { component: 'th' } },
|
|
1271
|
-
{
|
|
1272
|
-
title: (
|
|
1273
|
-
<React.Fragment>
|
|
1274
|
-
<CodeBranchIcon key="icon" /> 10
|
|
1275
|
-
</React.Fragment>
|
|
1276
|
-
),
|
|
1277
|
-
props: { isOpen: true, ariaControls: 'compound-expansion-table-1' }
|
|
1278
|
-
},
|
|
1279
|
-
{
|
|
1280
|
-
title: (
|
|
1281
|
-
<React.Fragment>
|
|
1282
|
-
<CodeIcon key="icon" /> 4
|
|
1283
|
-
</React.Fragment>
|
|
1284
|
-
),
|
|
1285
|
-
props: { isOpen: false, ariaControls: 'compound-expansion-table-2' }
|
|
1286
|
-
},
|
|
1287
|
-
{
|
|
1288
|
-
title: (
|
|
1289
|
-
<React.Fragment>
|
|
1290
|
-
<CubeIcon key="icon" /> 4
|
|
1291
|
-
</React.Fragment>
|
|
1292
|
-
),
|
|
1293
|
-
props: { isOpen: false, ariaControls: 'compound-expansion-table-3' }
|
|
1294
|
-
},
|
|
1295
|
-
'20 minutes',
|
|
1296
|
-
{ title: <a href="#">Open in Github</a> }
|
|
1297
|
-
]
|
|
1298
|
-
},
|
|
1299
|
-
{
|
|
1300
|
-
parent: 0,
|
|
1301
|
-
compoundParent: 1,
|
|
1302
|
-
cells: [
|
|
1303
|
-
{
|
|
1304
|
-
title: (
|
|
1305
|
-
<DemoSortableTable
|
|
1306
|
-
firstColumnRows={['parent-0', 'compound-1', 'three', 'four', 'five']}
|
|
1307
|
-
id="compound-expansion-table-1"
|
|
1308
|
-
/>
|
|
1309
|
-
),
|
|
1310
|
-
props: { colSpan: 6, className: 'pf-m-no-padding' }
|
|
1311
|
-
}
|
|
1312
|
-
]
|
|
1313
|
-
},
|
|
1314
|
-
{
|
|
1315
|
-
parent: 0,
|
|
1316
|
-
compoundParent: 2,
|
|
1317
|
-
cells: [
|
|
1318
|
-
{
|
|
1319
|
-
title: (
|
|
1320
|
-
<DemoSortableTable
|
|
1321
|
-
firstColumnRows={['parent-0', 'compound-2', 'three', 'four', 'five']}
|
|
1322
|
-
id="compound-expansion-table-2"
|
|
1323
|
-
/>
|
|
1324
|
-
),
|
|
1325
|
-
props: { colSpan: 6, className: 'pf-m-no-padding' }
|
|
1326
|
-
}
|
|
1327
|
-
]
|
|
1328
|
-
},
|
|
1329
|
-
{
|
|
1330
|
-
parent: 0,
|
|
1331
|
-
compoundParent: 3,
|
|
1332
|
-
cells: [
|
|
1333
|
-
{
|
|
1334
|
-
title: (
|
|
1335
|
-
<DemoSortableTable
|
|
1336
|
-
firstColumnRows={['parent-0', 'compound-3', 'three', 'four', 'five']}
|
|
1337
|
-
id="compound-expansion-table-3"
|
|
1338
|
-
/>
|
|
1339
|
-
),
|
|
1340
|
-
props: { colSpan: 6, className: 'pf-m-no-padding' }
|
|
1341
|
-
}
|
|
1342
|
-
]
|
|
1343
|
-
},
|
|
1344
|
-
{
|
|
1345
|
-
isOpen: false,
|
|
1346
|
-
cells: [
|
|
1347
|
-
{ title: <a href="#">siemur/test-space</a>, props: { component: 'th' } },
|
|
1348
|
-
{
|
|
1349
|
-
title: (
|
|
1350
|
-
<React.Fragment>
|
|
1351
|
-
<CodeBranchIcon key="icon" /> 3
|
|
1352
|
-
</React.Fragment>
|
|
1353
|
-
),
|
|
1354
|
-
props: { isOpen: false, ariaControls: 'compound-expansion-table-4' }
|
|
1355
|
-
},
|
|
1356
|
-
{
|
|
1357
|
-
title: (
|
|
1358
|
-
<React.Fragment>
|
|
1359
|
-
<CodeIcon key="icon" /> 4
|
|
1360
|
-
</React.Fragment>
|
|
1361
|
-
),
|
|
1362
|
-
props: { isOpen: false, ariaControls: 'compound-expansion-table-5' }
|
|
1363
|
-
},
|
|
1364
|
-
{
|
|
1365
|
-
title: (
|
|
1366
|
-
<React.Fragment>
|
|
1367
|
-
<CubeIcon key="icon" /> 2
|
|
1368
|
-
</React.Fragment>
|
|
1369
|
-
),
|
|
1370
|
-
props: { isOpen: false, ariaControls: 'compound-expansion-table-6' }
|
|
1371
|
-
},
|
|
1372
|
-
'20 minutes',
|
|
1373
|
-
{ title: <a href="#">Open in Github</a> }
|
|
1374
|
-
]
|
|
1375
|
-
},
|
|
1376
|
-
{
|
|
1377
|
-
parent: 4,
|
|
1378
|
-
compoundParent: 1,
|
|
1379
|
-
cells: [
|
|
1380
|
-
{
|
|
1381
|
-
title: (
|
|
1382
|
-
<DemoSortableTable
|
|
1383
|
-
firstColumnRows={['parent-4', 'compound-1', 'three', 'four', 'five']}
|
|
1384
|
-
id="compound-expansion-table-4"
|
|
1385
|
-
/>
|
|
1386
|
-
),
|
|
1387
|
-
props: { colSpan: 6, className: 'pf-m-no-padding' }
|
|
1388
|
-
}
|
|
1389
|
-
]
|
|
1390
|
-
},
|
|
1391
|
-
{
|
|
1392
|
-
parent: 4,
|
|
1393
|
-
compoundParent: 2,
|
|
1394
|
-
cells: [
|
|
1395
|
-
{
|
|
1396
|
-
title: (
|
|
1397
|
-
<DemoSortableTable
|
|
1398
|
-
firstColumnRows={['parent-4', 'compound-2', 'three', 'four', 'five']}
|
|
1399
|
-
id="compound-expansion-table-5"
|
|
1400
|
-
/>
|
|
1401
|
-
),
|
|
1402
|
-
props: { colSpan: 6, className: 'pf-m-no-padding' }
|
|
1403
|
-
}
|
|
1404
|
-
]
|
|
1405
|
-
},
|
|
1406
|
-
{
|
|
1407
|
-
parent: 4,
|
|
1408
|
-
compoundParent: 3,
|
|
1409
|
-
cells: [
|
|
1410
|
-
{
|
|
1411
|
-
title: (
|
|
1412
|
-
<DemoSortableTable
|
|
1413
|
-
firstColumnRows={['parent-4', 'compound-3', 'three', 'four', 'five']}
|
|
1414
|
-
id="compound-expansion-table-6"
|
|
1415
|
-
/>
|
|
1416
|
-
),
|
|
1417
|
-
props: { colSpan: 6, className: 'pf-m-no-padding' }
|
|
1418
|
-
}
|
|
1419
|
-
]
|
|
1420
|
-
}
|
|
1421
|
-
]
|
|
1422
|
-
};
|
|
1423
|
-
this.onExpand = this.onExpand.bind(this);
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
onExpand(event, rowIndex, colIndex, isOpen, rowData, extraData) {
|
|
1427
|
-
const { rows } = this.state;
|
|
1428
|
-
if (!isOpen) {
|
|
1429
|
-
// set all other expanded cells false in this row if we are expanding
|
|
1430
|
-
rows[rowIndex].cells.forEach(cell => {
|
|
1431
|
-
if (cell.props) cell.props.isOpen = false;
|
|
1432
|
-
});
|
|
1433
|
-
rows[rowIndex].cells[colIndex].props.isOpen = true;
|
|
1434
|
-
rows[rowIndex].isOpen = true;
|
|
1435
|
-
} else {
|
|
1436
|
-
rows[rowIndex].cells[colIndex].props.isOpen = false;
|
|
1437
|
-
rows[rowIndex].isOpen = rows[rowIndex].cells.some(cell => cell.props && cell.props.isOpen);
|
|
1438
|
-
}
|
|
1439
|
-
this.setState({
|
|
1440
|
-
rows
|
|
1441
|
-
});
|
|
1442
|
-
}
|
|
161
|
+
Note: If you want to add a tooltip/popover to a sortable header, in the `transforms` array the `info` transform has to precede the `sortable` transform.
|
|
1443
162
|
|
|
1444
|
-
|
|
1445
|
-
const { columns, rows } = this.state;
|
|
163
|
+
The built in display for sorting is not fully responsive, as the column headers will be displayed per row when the screen size is small. The example below showcases how sorting may have a custom control display that can be used for small screen sizes.
|
|
1446
164
|
|
|
1447
|
-
|
|
1448
|
-
<Table aria-label="Compound expandable table" onExpand={this.onExpand} rows={rows} cells={columns}>
|
|
1449
|
-
<TableHeader />
|
|
1450
|
-
<TableBody />
|
|
1451
|
-
</Table>
|
|
1452
|
-
);
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
165
|
+
```ts file="LegacyTableSortable.tsx"
|
|
1455
166
|
```
|
|
1456
167
|
|
|
1457
|
-
###
|
|
168
|
+
### Sortable - custom control
|
|
1458
169
|
|
|
1459
|
-
|
|
1460
|
-
import React from 'react';
|
|
1461
|
-
import { Table, TableHeader, TableBody, cellWidth, classNames, Visibility } from '@patternfly/react-table';
|
|
170
|
+
Sorting a table may also be controlled with a toolbar. This toolbar item may also be hidden at large screen sizes and only displayed when the screen size is small to support responsive tables.
|
|
1462
171
|
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
super(props);
|
|
1466
|
-
this.state = {
|
|
1467
|
-
columns: [
|
|
1468
|
-
{ title: 'Header cell', transforms: [cellWidth(10)] },
|
|
1469
|
-
{
|
|
1470
|
-
title: 'Branches (visible only on md)',
|
|
1471
|
-
columnTransforms: [
|
|
1472
|
-
classNames(Visibility.hidden, Visibility.visibleOnMd, Visibility.hiddenOnLg, Visibility.visibleOn2Xl)
|
|
1473
|
-
]
|
|
1474
|
-
},
|
|
1475
|
-
{
|
|
1476
|
-
title: 'Pull requests (hidden only on md)',
|
|
1477
|
-
columnTransforms: [classNames(Visibility.hiddenOnMd, Visibility.visibleOnLg)]
|
|
1478
|
-
},
|
|
1479
|
-
{
|
|
1480
|
-
title: 'Workspaces (hidden on xs)',
|
|
1481
|
-
columnTransforms: [classNames(Visibility.hidden, Visibility.visibleOnSm)]
|
|
1482
|
-
},
|
|
1483
|
-
{
|
|
1484
|
-
title: 'Last commit',
|
|
1485
|
-
transforms: [cellWidth(30)]
|
|
1486
|
-
}
|
|
1487
|
-
],
|
|
1488
|
-
rows: [
|
|
1489
|
-
[
|
|
1490
|
-
'one - 1',
|
|
1491
|
-
'two - 1 (visible only on md)',
|
|
1492
|
-
'three - 1 (hidden only on md)',
|
|
1493
|
-
'four - 1 (hidden on xs)',
|
|
1494
|
-
'five - 1'
|
|
1495
|
-
],
|
|
1496
|
-
[
|
|
1497
|
-
'one - 2',
|
|
1498
|
-
'two - 2 (visible only on md)',
|
|
1499
|
-
'three - 2 (hidden only on md)',
|
|
1500
|
-
'four - 2 (hidden on xs)',
|
|
1501
|
-
'five - 2'
|
|
1502
|
-
]
|
|
1503
|
-
]
|
|
1504
|
-
};
|
|
1505
|
-
}
|
|
172
|
+
```ts file="LegacyTableSortableCustom.tsx"
|
|
173
|
+
```
|
|
1506
174
|
|
|
1507
|
-
|
|
1508
|
-
const { columns, rows } = this.state;
|
|
175
|
+
### Selectable with checkbox
|
|
1509
176
|
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
177
|
+
To enable row selection, set the `onSelect` callback prop on the Table.
|
|
178
|
+
|
|
179
|
+
To control whether a row is selected or not, the Table looks for `selected: true | falsy` on the row definition.
|
|
180
|
+
|
|
181
|
+
To disable selection for a row, set `disableSelection: true` on the row definition.
|
|
182
|
+
|
|
183
|
+
To include a 'select all' checkbox in the header row, pass `true` to the`canSelectAll` prop on the Table.
|
|
184
|
+
|
|
185
|
+
Note: this example also demonstrates the use of the `headerCol` transformation being applied to the first
|
|
186
|
+
column via the `cellTransforms` in the column definition. `headerCol` transforms the column so that instead
|
|
187
|
+
of using `td` elements, the cells in that column use `th` elements.
|
|
188
|
+
|
|
189
|
+
**Note:** This example has a `shift + select` feature where holding shift while
|
|
190
|
+
checking checkboxes will check intermediate rows' checkboxes.
|
|
191
|
+
|
|
192
|
+
```ts file="LegacyTableSelectable.tsx"
|
|
1518
193
|
```
|
|
1519
194
|
|
|
1520
|
-
###
|
|
195
|
+
### Selectable radio input
|
|
1521
196
|
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
import {
|
|
1525
|
-
Table,
|
|
1526
|
-
TableHeader,
|
|
1527
|
-
TableBody,
|
|
1528
|
-
wrappable,
|
|
1529
|
-
truncate,
|
|
1530
|
-
nowrap,
|
|
1531
|
-
breakWord,
|
|
1532
|
-
cellWidth,
|
|
1533
|
-
fitContent
|
|
1534
|
-
} from '@patternfly/react-table';
|
|
197
|
+
To enable row radio selection, set the `onSelect` callback prop on the Table, and set
|
|
198
|
+
`RowSelectVariant.radio` or `"radio"` as the `selectVariant` prop on the Table.
|
|
1535
199
|
|
|
1536
|
-
|
|
1537
|
-
constructor(props) {
|
|
1538
|
-
super(props);
|
|
1539
|
-
this.state = {
|
|
1540
|
-
columns: [
|
|
1541
|
-
{ title: 'Truncate (width 20%)', transforms: [cellWidth(20)], cellTransforms: [truncate] },
|
|
1542
|
-
{ title: 'Break word', cellTransforms: [breakWord] },
|
|
1543
|
-
{ title: 'Wrapping table header text. This th text will wrap instead of truncate.', transforms: [wrappable] },
|
|
1544
|
-
{ title: 'Fit content', transforms: [fitContent] },
|
|
1545
|
-
{ title: '', cellTransforms: [nowrap] }
|
|
1546
|
-
],
|
|
1547
|
-
rows: [
|
|
1548
|
-
[
|
|
1549
|
-
'This text will truncate instead of wrap.',
|
|
1550
|
-
{ title: <a href="#">http://thisisaverylongurlthatneedstobreakusethebreakwordmodifier.org</a> },
|
|
1551
|
-
{
|
|
1552
|
-
title: (
|
|
1553
|
-
<p>
|
|
1554
|
-
By default,
|
|
1555
|
-
<code>thead</code> cells will truncate and
|
|
1556
|
-
<code>tbody</code> cells will wrap. Use
|
|
1557
|
-
<code>.pf-m-wrap</code> on a<code>th</code> to change its behavior.
|
|
1558
|
-
</p>
|
|
1559
|
-
)
|
|
1560
|
-
},
|
|
1561
|
-
"This cell's content will adjust itself to the parent th width. This modifier only affects table layouts.",
|
|
1562
|
-
{ title: <a href="#">No wrap</a> }
|
|
1563
|
-
]
|
|
1564
|
-
]
|
|
1565
|
-
};
|
|
1566
|
-
}
|
|
200
|
+
To disable selection for a row, set `disableSelection: true` on the row definition.
|
|
1567
201
|
|
|
1568
|
-
|
|
1569
|
-
|
|
202
|
+
```ts file="LegacyTableSelectableRadio.tsx"
|
|
203
|
+
```
|
|
1570
204
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
);
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
205
|
+
### Hoverable rows, selectable rows, and header cell tooltips/popovers
|
|
206
|
+
|
|
207
|
+
This selectable rows feature is intended for use when a table is used to present a list of objects in a Primary-detail view.
|
|
208
|
+
|
|
209
|
+
```ts file="LegacyTableHoverable.tsx"
|
|
1579
210
|
```
|
|
1580
211
|
|
|
1581
|
-
###
|
|
212
|
+
### Actions and first cell in body rows as th
|
|
1582
213
|
|
|
1583
|
-
|
|
1584
|
-
import React from 'react';
|
|
1585
|
-
import { Table, TableHeader, TableBody, TableText, cellWidth } from '@patternfly/react-table';
|
|
214
|
+
To use actions you can either specify an array of actions and pass that into the `Table`'s `actions` prop, or for more control you can use the `actionResolver` callback prop to add actions conditionally.
|
|
1586
215
|
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
super(props);
|
|
1590
|
-
this.state = {
|
|
1591
|
-
columns: [
|
|
1592
|
-
{ title: 'Truncating text', transforms: [cellWidth(30)] },
|
|
1593
|
-
{ title: 'Wrapping table header text. This th text will wrap instead of truncate.' }
|
|
1594
|
-
],
|
|
1595
|
-
rows: [
|
|
1596
|
-
[
|
|
1597
|
-
{ title: <TableText wrapModifier="truncate">This text will truncate instead of wrap.</TableText> },
|
|
1598
|
-
{
|
|
1599
|
-
title: (
|
|
1600
|
-
<TableText wrapModifier="nowrap">
|
|
1601
|
-
<a href="#">This is a link that needs to be on one line and fully readable.</a>
|
|
1602
|
-
</TableText>
|
|
1603
|
-
)
|
|
1604
|
-
}
|
|
1605
|
-
]
|
|
1606
|
-
]
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
216
|
+
```ts file="LegacyTableActions.tsx"
|
|
217
|
+
```
|
|
1609
218
|
|
|
1610
|
-
|
|
1611
|
-
const { columns, rows } = this.state;
|
|
219
|
+
### Expandable
|
|
1612
220
|
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
221
|
+
To make an exapandable row, define a child row with the `parent` field set to its parent's row index.
|
|
222
|
+
The parent row can have an `isOpen` field for managing the expanded state of the parent row.
|
|
223
|
+
|
|
224
|
+
Also, pass an `onCollapse` event handler via the prop on the Table
|
|
225
|
+
|
|
226
|
+
```ts file="LegacyTableExpandable.tsx"
|
|
1621
227
|
```
|
|
1622
228
|
|
|
1623
|
-
###
|
|
229
|
+
### Compound expandable
|
|
1624
230
|
|
|
1625
|
-
|
|
1626
|
-
import React from 'react';
|
|
1627
|
-
import { Table, TableHeader, TableBody } from '@patternfly/react-table';
|
|
1628
|
-
import { Button, EmptyState, EmptyStateBody, Bullseye, Title, EmptyStateIcon } from '@patternfly/react-core';
|
|
1629
|
-
import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
|
|
231
|
+
To build a compound expandable table:
|
|
1630
232
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
</React.Fragment>
|
|
1662
|
-
);
|
|
1663
|
-
};
|
|
233
|
+
1. Pass the `compoundExpand` transformation via the `cellTransforms` field in the column definition for each column that will have an expanded section.
|
|
234
|
+
2. For each expandable parent row, the cells in the expandable columns should:
|
|
235
|
+
1. have a managed `isOpen` prop passed to the cell definition
|
|
236
|
+
2. have an `ariaControls` value which matches the `id` of it’s child row
|
|
237
|
+
3. For each expandable child row, the row definition needs:
|
|
238
|
+
1. A `parent` field set to its parent’s row index
|
|
239
|
+
2. A `compoundParent` field set to the cell index which will control the expanding/collapsing of this row
|
|
240
|
+
4. An `onExpand` event handler prop should be passed to the Table.
|
|
241
|
+
|
|
242
|
+
```ts file="LegacyTableCompoundExpandable.tsx"
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### With width and breakpoint visibility modifiers
|
|
246
|
+
|
|
247
|
+
```ts file="LegacyTableCellWidth.tsx"
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Controlling text
|
|
251
|
+
|
|
252
|
+
```ts file="LegacyTableControllingText.tsx"
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Modifiers with table text
|
|
256
|
+
|
|
257
|
+
```ts file="LegacyTableTextModifiers.tsx"
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Empty state
|
|
261
|
+
|
|
262
|
+
```ts file="LegacyTableEmptyState.tsx"
|
|
1664
263
|
```
|
|
1665
264
|
|
|
1666
265
|
### Editable rows
|
|
@@ -2152,7 +751,7 @@ class EditableRowsTable extends React.Component {
|
|
|
2152
751
|
}
|
|
2153
752
|
```
|
|
2154
753
|
|
|
2155
|
-
### Favoritable
|
|
754
|
+
### Favoritable (implemented with sortable and selectable)
|
|
2156
755
|
|
|
2157
756
|
To enable favoriting of a row, set the `onFavorite` callback prop on the Table.
|
|
2158
757
|
|
|
@@ -2162,154 +761,7 @@ When you also pass a sort callback through the `onSort` prop, favorites sorting
|
|
|
2162
761
|
|
|
2163
762
|
If you want to exclude favorites from sorting, set `canSortFavorites={false}` on the Table.
|
|
2164
763
|
|
|
2165
|
-
```
|
|
2166
|
-
import React from 'react';
|
|
2167
|
-
import { Table, TableHeader, TableBody, sortable, SortByDirection } from '@patternfly/react-table';
|
|
2168
|
-
import { Checkbox } from '@patternfly/react-core';
|
|
2169
|
-
|
|
2170
|
-
class FavoritesTable extends React.Component {
|
|
2171
|
-
constructor(props) {
|
|
2172
|
-
super(props);
|
|
2173
|
-
this.state = {
|
|
2174
|
-
columns: [
|
|
2175
|
-
{ title: 'Repositories', transforms: [sortable] },
|
|
2176
|
-
'Branches',
|
|
2177
|
-
'Pull requests',
|
|
2178
|
-
'Workspaces',
|
|
2179
|
-
'Last commit'
|
|
2180
|
-
],
|
|
2181
|
-
rows: [
|
|
2182
|
-
{
|
|
2183
|
-
favorited: true,
|
|
2184
|
-
// The favorites button has defaults that can be overriden
|
|
2185
|
-
favoritesProps: {
|
|
2186
|
-
'aria-label': 'Favorited', // Defaults to 'Starred' / 'Not starred'
|
|
2187
|
-
id: 'favorites-button-a', // Defaults to `favorites-button-${rowIndex}`
|
|
2188
|
-
'aria-labelledby': 'favorites-button-a repository-1' // Defaults to `favorites-button-${rowIndex}`
|
|
2189
|
-
},
|
|
2190
|
-
cells: ['c', 'two', 'a', 'four', 'five']
|
|
2191
|
-
},
|
|
2192
|
-
{
|
|
2193
|
-
cells: ['a', 'two', 'k', 'four', 'five'],
|
|
2194
|
-
disableSelection: true
|
|
2195
|
-
},
|
|
2196
|
-
{
|
|
2197
|
-
favorited: true,
|
|
2198
|
-
cells: ['b', 'two', 'b', 'four', 'five']
|
|
2199
|
-
}
|
|
2200
|
-
],
|
|
2201
|
-
sortBy: {},
|
|
2202
|
-
canSortFavorites: true
|
|
2203
|
-
};
|
|
2204
|
-
this.onSelect = this.onSelect.bind(this);
|
|
2205
|
-
this.onFavorite = this.onFavorite.bind(this);
|
|
2206
|
-
this.onSort = this.onSort.bind(this);
|
|
2207
|
-
this.toggleFavsSort = this.toggleFavsSort.bind(this);
|
|
2208
|
-
}
|
|
2209
|
-
|
|
2210
|
-
onSelect(event, isSelected, rowId) {
|
|
2211
|
-
let rows;
|
|
2212
|
-
if (rowId === -1) {
|
|
2213
|
-
// header row
|
|
2214
|
-
rows = this.state.rows.map(oneRow => {
|
|
2215
|
-
oneRow.selected = isSelected;
|
|
2216
|
-
return oneRow;
|
|
2217
|
-
});
|
|
2218
|
-
} else {
|
|
2219
|
-
// body row
|
|
2220
|
-
rows = [...this.state.rows];
|
|
2221
|
-
rows[rowId].selected = isSelected;
|
|
2222
|
-
}
|
|
2223
|
-
this.setState({
|
|
2224
|
-
rows
|
|
2225
|
-
});
|
|
2226
|
-
}
|
|
2227
|
-
|
|
2228
|
-
onFavorite(event, isFavorited, rowId) {
|
|
2229
|
-
this.setState({
|
|
2230
|
-
rows: this.state.rows.map((row, index) => {
|
|
2231
|
-
if (index === rowId) {
|
|
2232
|
-
row.favorited = isFavorited;
|
|
2233
|
-
row.favoritesProps = {
|
|
2234
|
-
...row.favoritesProps,
|
|
2235
|
-
// Example of how to override the default aria-label of Starred / Not starred
|
|
2236
|
-
'aria-label': isFavorited ? 'Favorited' : 'Not favorited'
|
|
2237
|
-
};
|
|
2238
|
-
}
|
|
2239
|
-
return row;
|
|
2240
|
-
})
|
|
2241
|
-
});
|
|
2242
|
-
}
|
|
2243
|
-
|
|
2244
|
-
onSort(_event, index, direction) {
|
|
2245
|
-
// index 0 === select column
|
|
2246
|
-
// index 1 === favorites column
|
|
2247
|
-
// index 2 === first user defined column
|
|
2248
|
-
let sortedRows;
|
|
2249
|
-
if (index === 1) {
|
|
2250
|
-
// favorites column
|
|
2251
|
-
sortedRows = this.state.rows.sort((a, b) => {
|
|
2252
|
-
if (a.favorited && !b.favorited) {
|
|
2253
|
-
return -1;
|
|
2254
|
-
} else if (!a.favorited && b.favorited) {
|
|
2255
|
-
return 1;
|
|
2256
|
-
}
|
|
2257
|
-
return 0;
|
|
2258
|
-
});
|
|
2259
|
-
} else {
|
|
2260
|
-
const userIndex = index - 2; // subtract for select and favorites column
|
|
2261
|
-
sortedRows = this.state.rows.sort((a, b) =>
|
|
2262
|
-
a.cells[userIndex] < b.cells[userIndex] ? -1 : a.cells[userIndex] > b.cells[userIndex] ? 1 : 0
|
|
2263
|
-
);
|
|
2264
|
-
}
|
|
2265
|
-
this.setState({
|
|
2266
|
-
sortBy: {
|
|
2267
|
-
index,
|
|
2268
|
-
direction
|
|
2269
|
-
},
|
|
2270
|
-
rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse()
|
|
2271
|
-
});
|
|
2272
|
-
}
|
|
2273
|
-
|
|
2274
|
-
toggleFavsSort(checked) {
|
|
2275
|
-
this.setState({
|
|
2276
|
-
canSortFavorites: checked
|
|
2277
|
-
});
|
|
2278
|
-
}
|
|
2279
|
-
|
|
2280
|
-
render() {
|
|
2281
|
-
const { columns, rows, sortBy, canSortFavorites } = this.state;
|
|
2282
|
-
|
|
2283
|
-
return (
|
|
2284
|
-
<div>
|
|
2285
|
-
<Checkbox
|
|
2286
|
-
label="Can sort favorites"
|
|
2287
|
-
isChecked={canSortFavorites}
|
|
2288
|
-
onChange={this.toggleFavsSort}
|
|
2289
|
-
aria-label="toggle select all checkbox"
|
|
2290
|
-
id="toggle-select-all"
|
|
2291
|
-
name="toggle-select-all"
|
|
2292
|
-
/>
|
|
2293
|
-
<Table
|
|
2294
|
-
// using this prop enables the favorites column
|
|
2295
|
-
onFavorite={this.onFavorite}
|
|
2296
|
-
// if the onSort prop is detected, favorites can be sorted
|
|
2297
|
-
// if you want to exclude favorites from sorting you can use this prop with a value of `false`
|
|
2298
|
-
canSortFavorites={canSortFavorites}
|
|
2299
|
-
onSelect={this.onSelect}
|
|
2300
|
-
onSort={this.onSort}
|
|
2301
|
-
sortBy={sortBy}
|
|
2302
|
-
aria-label="Favoritable Table"
|
|
2303
|
-
cells={columns}
|
|
2304
|
-
rows={rows}
|
|
2305
|
-
>
|
|
2306
|
-
<TableHeader />
|
|
2307
|
-
<TableBody />
|
|
2308
|
-
</Table>
|
|
2309
|
-
</div>
|
|
2310
|
-
);
|
|
2311
|
-
}
|
|
2312
|
-
}
|
|
764
|
+
```ts file="LegacyTableFavoritable.tsx"
|
|
2313
765
|
```
|
|
2314
766
|
|
|
2315
767
|
### Tree table
|
|
@@ -2338,222 +790,5 @@ Note: If this table is going to be tested using axe-core, the tests will flag th
|
|
|
2338
790
|
aria-posinset, and aria-setsize as violations. This is an intentional choice at this time so that
|
|
2339
791
|
the voice over technologies will recognize the flat table structure as a tree.
|
|
2340
792
|
|
|
2341
|
-
```
|
|
2342
|
-
import React from 'react';
|
|
2343
|
-
import { Table, TableHeader, TableBody, headerCol, treeRow } from '@patternfly/react-table';
|
|
2344
|
-
import LeafIcon from '@patternfly/react-icons/dist/esm/icons/leaf-icon';
|
|
2345
|
-
import FolderIcon from '@patternfly/react-icons/dist/esm/icons/folder-icon';
|
|
2346
|
-
import FolderOpenIcon from '@patternfly/react-icons/dist/esm/icons/folder-open-icon';
|
|
2347
|
-
|
|
2348
|
-
class TreeTable extends React.Component {
|
|
2349
|
-
constructor(props) {
|
|
2350
|
-
super(props);
|
|
2351
|
-
this.state = {
|
|
2352
|
-
data: [
|
|
2353
|
-
{
|
|
2354
|
-
repositories: 'Repositories one',
|
|
2355
|
-
branches: 'Branch one',
|
|
2356
|
-
pullRequests: 'Pull request one',
|
|
2357
|
-
workspaces: 'Workplace one',
|
|
2358
|
-
children: [
|
|
2359
|
-
{
|
|
2360
|
-
repositories: 'Repositories two',
|
|
2361
|
-
branches: 'Branch two',
|
|
2362
|
-
pullRequests: 'Pull request two',
|
|
2363
|
-
workspaces: 'Workplace two',
|
|
2364
|
-
children: [
|
|
2365
|
-
{
|
|
2366
|
-
repositories: 'Repositories three',
|
|
2367
|
-
branches: 'Branch three',
|
|
2368
|
-
pullRequests: 'Pull request three',
|
|
2369
|
-
workspaces: 'Workplace three'
|
|
2370
|
-
},
|
|
2371
|
-
{
|
|
2372
|
-
repositories: 'Repositories four',
|
|
2373
|
-
branches: 'Branch four',
|
|
2374
|
-
pullRequests: 'Pull request four',
|
|
2375
|
-
workspaces: 'Workplace four'
|
|
2376
|
-
}
|
|
2377
|
-
]
|
|
2378
|
-
},
|
|
2379
|
-
{
|
|
2380
|
-
repositories: 'Repositories five',
|
|
2381
|
-
branches: 'Branch five',
|
|
2382
|
-
pullRequests: 'Pull request five',
|
|
2383
|
-
workspaces: 'Workplace five'
|
|
2384
|
-
},
|
|
2385
|
-
{
|
|
2386
|
-
repositories: 'Repositories six',
|
|
2387
|
-
branches: 'Branch six',
|
|
2388
|
-
pullRequests: 'Pull request six',
|
|
2389
|
-
workspaces: 'Workplace six'
|
|
2390
|
-
}
|
|
2391
|
-
]
|
|
2392
|
-
},
|
|
2393
|
-
{
|
|
2394
|
-
repositories: 'Repositories seven',
|
|
2395
|
-
branches: 'Branch seven',
|
|
2396
|
-
pullRequests: 'Pull request seven',
|
|
2397
|
-
workspaces: 'Workplace seven',
|
|
2398
|
-
children: [
|
|
2399
|
-
{
|
|
2400
|
-
repositories: 'Repositories eight',
|
|
2401
|
-
branches: 'Branch eight',
|
|
2402
|
-
pullRequests: 'Pull request eight',
|
|
2403
|
-
workspaces: 'Workplace eight'
|
|
2404
|
-
}
|
|
2405
|
-
]
|
|
2406
|
-
},
|
|
2407
|
-
{
|
|
2408
|
-
repositories: 'Repositories nine',
|
|
2409
|
-
branches: 'Branch nine',
|
|
2410
|
-
pullRequests: 'Pull request nine',
|
|
2411
|
-
workspaces: 'Workplace nine'
|
|
2412
|
-
}
|
|
2413
|
-
],
|
|
2414
|
-
expandedRows: ['Repositories one', 'Repositories six'],
|
|
2415
|
-
expandedDetailsRows: [],
|
|
2416
|
-
checkedRows: []
|
|
2417
|
-
};
|
|
2418
|
-
|
|
2419
|
-
/**
|
|
2420
|
-
Recursive function which flattens the data into an array flattened IRow objects
|
|
2421
|
-
to be passed to the `rows` prop of the Table
|
|
2422
|
-
params:
|
|
2423
|
-
- rowData - array of data
|
|
2424
|
-
- level - number representing how deeply nested the current row is
|
|
2425
|
-
- posinset - position of the row relative to this row's siblings
|
|
2426
|
-
- isHidden - defaults to false, true if this row's parent is expanded
|
|
2427
|
-
*/
|
|
2428
|
-
this.buildRows = ([x, ...xs], level, posinset, isHidden = false) => {
|
|
2429
|
-
if (x) {
|
|
2430
|
-
const isExpanded = this.state.expandedRows.includes(x.repositories);
|
|
2431
|
-
const isDetailsExpanded = this.state.expandedDetailsRows.includes(x.repositories);
|
|
2432
|
-
const isChecked = this.mapChecked(x);
|
|
2433
|
-
let icon = <LeafIcon />;
|
|
2434
|
-
if (x.children) {
|
|
2435
|
-
icon = isExpanded ? <FolderOpenIcon aria-hidden /> : <FolderIcon aria-hidden />;
|
|
2436
|
-
}
|
|
2437
|
-
|
|
2438
|
-
return [
|
|
2439
|
-
{
|
|
2440
|
-
cells: [x.repositories, x.branches, x.pullRequests, x.workspaces],
|
|
2441
|
-
props: {
|
|
2442
|
-
isExpanded,
|
|
2443
|
-
isDetailsExpanded,
|
|
2444
|
-
isHidden,
|
|
2445
|
-
'aria-level': level,
|
|
2446
|
-
'aria-posinset': posinset,
|
|
2447
|
-
'aria-setsize': x.children ? x.children.length : 0,
|
|
2448
|
-
isChecked,
|
|
2449
|
-
icon
|
|
2450
|
-
}
|
|
2451
|
-
},
|
|
2452
|
-
...(x.children && x.children.length ? this.buildRows(x.children, level + 1, 1, !isExpanded || isHidden) : []),
|
|
2453
|
-
...this.buildRows(xs, level, posinset + 1, isHidden)
|
|
2454
|
-
];
|
|
2455
|
-
}
|
|
2456
|
-
return [];
|
|
2457
|
-
};
|
|
2458
|
-
|
|
2459
|
-
this.onToggleRowDetails = (event, rowIndex, title) => {
|
|
2460
|
-
this.setState(prevState => {
|
|
2461
|
-
const { expandedDetailsRows } = prevState;
|
|
2462
|
-
const openedIndex = expandedDetailsRows.indexOf(title);
|
|
2463
|
-
const newExpandedDetailsRows =
|
|
2464
|
-
openedIndex === -1 ? [...expandedDetailsRows, title] : expandedDetailsRows.filter(o => o !== title);
|
|
2465
|
-
return {
|
|
2466
|
-
expandedDetailsRows: newExpandedDetailsRows
|
|
2467
|
-
};
|
|
2468
|
-
});
|
|
2469
|
-
};
|
|
2470
|
-
|
|
2471
|
-
this.onCollapse = (event, rowIndex, title) => {
|
|
2472
|
-
this.setState(prevState => {
|
|
2473
|
-
const { expandedRows } = prevState;
|
|
2474
|
-
const openedIndex = expandedRows.indexOf(title);
|
|
2475
|
-
const newExpandedRows = openedIndex === -1 ? [...expandedRows, title] : expandedRows.filter(o => o !== title);
|
|
2476
|
-
return {
|
|
2477
|
-
expandedRows: newExpandedRows
|
|
2478
|
-
};
|
|
2479
|
-
});
|
|
2480
|
-
};
|
|
2481
|
-
|
|
2482
|
-
this.onCheck = (event, checked, rowIndex, checkedTitle) => {
|
|
2483
|
-
this.setState(prevState => {
|
|
2484
|
-
let flattenedData = this.getFlattenedTitles(prevState.data, checkedTitle);
|
|
2485
|
-
const prevChecked = prevState.checkedRows;
|
|
2486
|
-
return {
|
|
2487
|
-
checkedRows: checked
|
|
2488
|
-
? prevChecked.concat(flattenedData.filter(title => !prevChecked.includes(title)))
|
|
2489
|
-
: prevChecked.filter(title => !flattenedData.includes(title))
|
|
2490
|
-
};
|
|
2491
|
-
});
|
|
2492
|
-
};
|
|
2493
|
-
|
|
2494
|
-
// // helper methods for determining the checkbox's checked state for each row ///
|
|
2495
|
-
|
|
2496
|
-
/** Recursive function which flattens the data into an array of row titles
|
|
2497
|
-
* whose checkboxes' checked states are being updated.
|
|
2498
|
-
* Titles are only added to the array if they are the root checked title node,
|
|
2499
|
-
* or if they are a descendent of the root checked title node */
|
|
2500
|
-
this.getFlattenedTitles = (data, checkedTitle, parentChecked) => {
|
|
2501
|
-
let flattenedData = [];
|
|
2502
|
-
data.forEach(item => {
|
|
2503
|
-
if (item.repositories === checkedTitle || parentChecked) {
|
|
2504
|
-
flattenedData.push(item.repositories);
|
|
2505
|
-
}
|
|
2506
|
-
if (item.children) {
|
|
2507
|
-
flattenedData = flattenedData.concat(
|
|
2508
|
-
this.getFlattenedTitles(item.children, checkedTitle, item.repositories === checkedTitle || parentChecked)
|
|
2509
|
-
);
|
|
2510
|
-
}
|
|
2511
|
-
return flattenedData;
|
|
2512
|
-
});
|
|
2513
|
-
return flattenedData;
|
|
2514
|
-
};
|
|
2515
|
-
|
|
2516
|
-
this.areAllDescendantsChecked = row =>
|
|
2517
|
-
row.children
|
|
2518
|
-
? row.children.every(child => this.areAllDescendantsChecked(child))
|
|
2519
|
-
: this.state.checkedRows.indexOf(row.repositories) !== -1;
|
|
2520
|
-
|
|
2521
|
-
this.areSomeDescendantsChecked = row =>
|
|
2522
|
-
row.children
|
|
2523
|
-
? row.children.some(child => this.areSomeDescendantsChecked(child))
|
|
2524
|
-
: this.state.checkedRows.indexOf(row.repositories) !== -1;
|
|
2525
|
-
|
|
2526
|
-
this.mapChecked = row => {
|
|
2527
|
-
if (this.areAllDescendantsChecked(row)) {
|
|
2528
|
-
return true;
|
|
2529
|
-
}
|
|
2530
|
-
if (this.areSomeDescendantsChecked(row)) {
|
|
2531
|
-
return null;
|
|
2532
|
-
}
|
|
2533
|
-
return false;
|
|
2534
|
-
};
|
|
2535
|
-
}
|
|
2536
|
-
|
|
2537
|
-
render() {
|
|
2538
|
-
return (
|
|
2539
|
-
<Table
|
|
2540
|
-
isTreeTable
|
|
2541
|
-
aria-label="Tree table"
|
|
2542
|
-
cells={[
|
|
2543
|
-
{
|
|
2544
|
-
title: 'Repositories',
|
|
2545
|
-
cellTransforms: [treeRow(this.onCollapse, this.onCheck, this.onToggleRowDetails)]
|
|
2546
|
-
},
|
|
2547
|
-
'Branches',
|
|
2548
|
-
{ title: 'Pull requests' },
|
|
2549
|
-
'Workspaces'
|
|
2550
|
-
]}
|
|
2551
|
-
rows={this.buildRows(this.state.data, 1, 1)}
|
|
2552
|
-
>
|
|
2553
|
-
<TableHeader />
|
|
2554
|
-
<TableBody />
|
|
2555
|
-
</Table>
|
|
2556
|
-
);
|
|
2557
|
-
}
|
|
2558
|
-
}
|
|
793
|
+
```ts isBeta file="LegacyTableTree.tsx"
|
|
2559
794
|
```
|