@patternfly/react-table 4.44.9 → 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 +35 -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/dist/umd/react-table.css +5 -3
- package/dist/umd/react-table.min.css +5 -3
- 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
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tr, Th, Tbody, Td, ExpandableRowContent } from '@patternfly/react-table';
|
|
3
|
+
import { Checkbox } from '@patternfly/react-core';
|
|
4
|
+
|
|
5
|
+
interface Repository {
|
|
6
|
+
name: string;
|
|
7
|
+
branches: string;
|
|
8
|
+
prs: string;
|
|
9
|
+
workspaces: string;
|
|
10
|
+
lastCommit: string;
|
|
11
|
+
details?: {
|
|
12
|
+
detail1?: string;
|
|
13
|
+
detail2?: string;
|
|
14
|
+
detail3?: string;
|
|
15
|
+
detailFormat: 0 | 1 | 2 | 3;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ComposableTableExpandable: React.FunctionComponent = () => {
|
|
20
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
21
|
+
const repositories: Repository[] = [
|
|
22
|
+
{ name: 'one', branches: 'two', prs: 'a', workspaces: 'four', lastCommit: 'five' },
|
|
23
|
+
{
|
|
24
|
+
name: 'parent 1',
|
|
25
|
+
branches: 'two',
|
|
26
|
+
prs: 'k',
|
|
27
|
+
workspaces: 'four',
|
|
28
|
+
lastCommit: 'five',
|
|
29
|
+
// This `details` structure is just for this example. You can drive expanded content from any kind of data.
|
|
30
|
+
details: { detailFormat: 0, detail1: 'single cell' }
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'parent 2',
|
|
34
|
+
branches: 'two',
|
|
35
|
+
prs: 'b',
|
|
36
|
+
workspaces: 'four',
|
|
37
|
+
lastCommit: 'five',
|
|
38
|
+
details: { detailFormat: 1, detail1: 'single cell - fullWidth' }
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'parent 3',
|
|
42
|
+
branches: '2',
|
|
43
|
+
prs: 'b',
|
|
44
|
+
workspaces: 'four',
|
|
45
|
+
lastCommit: 'five',
|
|
46
|
+
details: { detailFormat: 2, detail1: 'single cell - noPadding' }
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'parent 4',
|
|
50
|
+
branches: '2',
|
|
51
|
+
prs: 'b',
|
|
52
|
+
workspaces: 'four',
|
|
53
|
+
lastCommit: 'five',
|
|
54
|
+
details: { detailFormat: 3, detail1: 'single cell - fullWidth & noPadding' }
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'parent 5',
|
|
58
|
+
branches: '2',
|
|
59
|
+
prs: 'b',
|
|
60
|
+
workspaces: 'four',
|
|
61
|
+
lastCommit: 'five',
|
|
62
|
+
details: {
|
|
63
|
+
detailFormat: 0,
|
|
64
|
+
detail1: "spans 'Repositories and 'Branches'",
|
|
65
|
+
detail2: "spans 'Pull requests' and 'Workspaces', and 'Last commit'"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'parent 6',
|
|
70
|
+
branches: '2',
|
|
71
|
+
prs: 'b',
|
|
72
|
+
workspaces: 'four',
|
|
73
|
+
lastCommit: 'five',
|
|
74
|
+
details: {
|
|
75
|
+
detailFormat: 1,
|
|
76
|
+
detail1: "fullWidth, spans the collapsible column and 'Repositories'",
|
|
77
|
+
detail2: "fullWidth, spans 'Branches' and 'Pull requests'",
|
|
78
|
+
detail3: "fullWidth, spans 'Workspaces' and 'Last commit'"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
const columnNames = {
|
|
84
|
+
name: 'Repositories',
|
|
85
|
+
branches: 'Branches',
|
|
86
|
+
prs: 'Pull requests',
|
|
87
|
+
workspaces: 'Workspaces',
|
|
88
|
+
lastCommit: 'Last commit'
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// In this example, expanded rows are tracked by the repo names from each row. This could be any unique identifier.
|
|
92
|
+
// This is to prevent state from being based on row order index in case we later add sorting.
|
|
93
|
+
// Note that this behavior is very similar to selection state.
|
|
94
|
+
const initialExpandedRepoNames = repositories.filter(repo => !!repo.details).map(repo => repo.name); // Default to all expanded
|
|
95
|
+
const [expandedRepoNames, setExpandedRepoNames] = React.useState<string[]>(initialExpandedRepoNames);
|
|
96
|
+
const setRepoExpanded = (repo: Repository, isExpanding = true) =>
|
|
97
|
+
setExpandedRepoNames(prevExpanded => {
|
|
98
|
+
const otherExpandedRepoNames = prevExpanded.filter(r => r !== repo.name);
|
|
99
|
+
return isExpanding ? [...otherExpandedRepoNames, repo.name] : otherExpandedRepoNames;
|
|
100
|
+
});
|
|
101
|
+
const isRepoExpanded = (repo: Repository) => expandedRepoNames.includes(repo.name);
|
|
102
|
+
|
|
103
|
+
const [isExampleCompact, setIsExampleCompact] = React.useState(true);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<React.Fragment>
|
|
107
|
+
<Checkbox
|
|
108
|
+
label="Compact"
|
|
109
|
+
isChecked={isExampleCompact}
|
|
110
|
+
onChange={checked => setIsExampleCompact(checked)}
|
|
111
|
+
aria-label="toggle compact variation"
|
|
112
|
+
id="toggle-compact"
|
|
113
|
+
name="toggle-compact"
|
|
114
|
+
/>
|
|
115
|
+
<TableComposable aria-label="Expandable table" variant={isExampleCompact ? 'compact' : undefined}>
|
|
116
|
+
<Thead>
|
|
117
|
+
<Tr>
|
|
118
|
+
<Th />
|
|
119
|
+
<Th>{columnNames.name}</Th>
|
|
120
|
+
<Th>{columnNames.branches}</Th>
|
|
121
|
+
<Th>{columnNames.prs}</Th>
|
|
122
|
+
<Th>{columnNames.workspaces}</Th>
|
|
123
|
+
<Th>{columnNames.lastCommit}</Th>
|
|
124
|
+
</Tr>
|
|
125
|
+
</Thead>
|
|
126
|
+
{repositories.map((repo, rowIndex) => {
|
|
127
|
+
// Some arbitrary examples of how you could customize the child row based on your needs
|
|
128
|
+
let childIsFullWidth = false;
|
|
129
|
+
let childHasNoPadding = false;
|
|
130
|
+
let detail1Colspan = 1;
|
|
131
|
+
let detail2Colspan = 1;
|
|
132
|
+
let detail3Colspan = 1;
|
|
133
|
+
if (repo.details) {
|
|
134
|
+
const { detail1, detail2, detail3, detailFormat } = repo.details;
|
|
135
|
+
const numColumns = 5;
|
|
136
|
+
childIsFullWidth = [1, 3].includes(detailFormat);
|
|
137
|
+
childHasNoPadding = [2, 3].includes(detailFormat);
|
|
138
|
+
if (detail1 && !detail2 && !detail3) {
|
|
139
|
+
detail1Colspan = childIsFullWidth ? numColumns : numColumns + 1; // Account for toggle column
|
|
140
|
+
} else if (detail1 && detail2 && !detail3) {
|
|
141
|
+
detail1Colspan = 2;
|
|
142
|
+
detail2Colspan = childIsFullWidth ? 3 : 4;
|
|
143
|
+
} else if (detail1 && detail2 && detail3) {
|
|
144
|
+
detail1Colspan = 2;
|
|
145
|
+
detail2Colspan = 2;
|
|
146
|
+
detail3Colspan = childIsFullWidth ? 1 : 2;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return (
|
|
150
|
+
<Tbody key={repo.name} isExpanded={isRepoExpanded(repo)}>
|
|
151
|
+
<Tr>
|
|
152
|
+
<Td
|
|
153
|
+
expand={
|
|
154
|
+
repo.details
|
|
155
|
+
? {
|
|
156
|
+
rowIndex,
|
|
157
|
+
isExpanded: isRepoExpanded(repo),
|
|
158
|
+
onToggle: () => setRepoExpanded(repo, !isRepoExpanded(repo))
|
|
159
|
+
}
|
|
160
|
+
: undefined
|
|
161
|
+
}
|
|
162
|
+
/>
|
|
163
|
+
<Td dataLabel={columnNames.name}>{repo.name}</Td>
|
|
164
|
+
<Td dataLabel={columnNames.branches}>{repo.branches}</Td>
|
|
165
|
+
<Td dataLabel={columnNames.prs}>{repo.prs}</Td>
|
|
166
|
+
<Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
|
|
167
|
+
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
|
|
168
|
+
</Tr>
|
|
169
|
+
{repo.details ? (
|
|
170
|
+
<Tr isExpanded={isRepoExpanded(repo)}>
|
|
171
|
+
{!childIsFullWidth ? <Td /> : null}
|
|
172
|
+
{repo.details.detail1 ? (
|
|
173
|
+
<Td dataLabel="Repo detail 1" noPadding={childHasNoPadding} colSpan={detail1Colspan}>
|
|
174
|
+
<ExpandableRowContent>{repo.details.detail1}</ExpandableRowContent>
|
|
175
|
+
</Td>
|
|
176
|
+
) : null}
|
|
177
|
+
{repo.details.detail2 ? (
|
|
178
|
+
<Td dataLabel="Repo detail 2" noPadding={childHasNoPadding} colSpan={detail2Colspan}>
|
|
179
|
+
<ExpandableRowContent>{repo.details.detail2}</ExpandableRowContent>
|
|
180
|
+
</Td>
|
|
181
|
+
) : null}
|
|
182
|
+
{repo.details.detail3 ? (
|
|
183
|
+
<Td dataLabel="Repo detail 3" noPadding={childHasNoPadding} colSpan={detail3Colspan}>
|
|
184
|
+
<ExpandableRowContent>{repo.details.detail3}</ExpandableRowContent>
|
|
185
|
+
</Td>
|
|
186
|
+
) : null}
|
|
187
|
+
</Tr>
|
|
188
|
+
) : null}
|
|
189
|
+
</Tbody>
|
|
190
|
+
);
|
|
191
|
+
})}
|
|
192
|
+
</TableComposable>
|
|
193
|
+
</React.Fragment>
|
|
194
|
+
);
|
|
195
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tr, Th, Tbody, Td, ThProps } from '@patternfly/react-table';
|
|
3
|
+
|
|
4
|
+
interface Repository {
|
|
5
|
+
name: string;
|
|
6
|
+
branches: string;
|
|
7
|
+
prs: string;
|
|
8
|
+
workspaces: string;
|
|
9
|
+
lastCommit: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const ComposableTableFavoritable: React.FunctionComponent = () => {
|
|
13
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
14
|
+
const repositories: Repository[] = [
|
|
15
|
+
{ name: 'one', branches: 'two', prs: 'a', workspaces: 'four', lastCommit: 'five' },
|
|
16
|
+
{ name: 'a', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five' },
|
|
17
|
+
{ name: 'p', branches: 'two', prs: 'b', workspaces: 'four', lastCommit: 'five' }
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const columnNames = {
|
|
21
|
+
name: 'Repositories',
|
|
22
|
+
branches: 'Branches',
|
|
23
|
+
prs: 'Pull requests',
|
|
24
|
+
workspaces: 'Workspaces',
|
|
25
|
+
lastCommit: 'Last commit'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Index of the currently sorted column
|
|
29
|
+
// Note: if you intend to make columns reorderable, you may instead want to use a non-numeric key
|
|
30
|
+
// as the identifier of the sorted column. See the "Compound expandable" example.
|
|
31
|
+
const [activeSortIndex, setActiveSortIndex] = React.useState<number | null>(null);
|
|
32
|
+
|
|
33
|
+
// Sort direction of the currently sorted column
|
|
34
|
+
const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | null>(null);
|
|
35
|
+
|
|
36
|
+
// Favorite state is similar to selection state, see Composable: Selectable with checkbox.
|
|
37
|
+
const [favoriteRepoNames, setFavoriteRepoNames] = React.useState<string[]>([]);
|
|
38
|
+
const setRepoFavorited = (repo: Repository, isFavoriting = true) =>
|
|
39
|
+
setFavoriteRepoNames(prevFavorites => {
|
|
40
|
+
const otherFavorites = prevFavorites.filter(r => r !== repo.name);
|
|
41
|
+
return isFavoriting ? [...otherFavorites, repo.name] : otherFavorites;
|
|
42
|
+
});
|
|
43
|
+
const isRepoFavorited = (repo: Repository) => favoriteRepoNames.includes(repo.name);
|
|
44
|
+
|
|
45
|
+
// Since OnSort specifies sorted columns by index, we need sortable values for our object by column index.
|
|
46
|
+
// In this example we only deal with booleans here because we only sort on the favorites column.
|
|
47
|
+
// For more complex sorting, see Composable: Sortable.
|
|
48
|
+
// Note: We also memoize the sortable values with useCallback to prevent rows jumping around when you change
|
|
49
|
+
// the favorites while sorting on that column. Only updating the sort state will reorder the rows.
|
|
50
|
+
const getSortableRowValues = React.useCallback((repo: Repository): boolean[] => [isRepoFavorited(repo)], [
|
|
51
|
+
activeSortIndex,
|
|
52
|
+
activeSortDirection
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
// Note that we perform the sort as part of the component's render logic and not in onSort.
|
|
56
|
+
// We shouldn't store the list of data in state because we don't want to have to sync that with props.
|
|
57
|
+
let sortedRepositories = repositories;
|
|
58
|
+
if (activeSortIndex !== null) {
|
|
59
|
+
sortedRepositories = repositories.sort((a, b) => {
|
|
60
|
+
const aValue = getSortableRowValues(a)[activeSortIndex];
|
|
61
|
+
const bValue = getSortableRowValues(b)[activeSortIndex];
|
|
62
|
+
if (aValue === bValue) {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
if (activeSortDirection === 'asc') {
|
|
66
|
+
return aValue > bValue ? 1 : -1;
|
|
67
|
+
} else {
|
|
68
|
+
return bValue > aValue ? 1 : -1;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const getSortParams = (columnIndex: number): ThProps['sort'] => ({
|
|
74
|
+
isFavorites: columnIndex === 0, // Not just statically true in case we add sorting on other columns later
|
|
75
|
+
sortBy: {
|
|
76
|
+
index: activeSortIndex,
|
|
77
|
+
direction: activeSortDirection
|
|
78
|
+
},
|
|
79
|
+
onSort: (_event, index, direction) => {
|
|
80
|
+
setActiveSortIndex(index);
|
|
81
|
+
setActiveSortDirection(direction);
|
|
82
|
+
},
|
|
83
|
+
columnIndex
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<TableComposable aria-label="Favoritable table" variant="compact">
|
|
88
|
+
<Thead>
|
|
89
|
+
<Tr>
|
|
90
|
+
<Th sort={getSortParams(0)} />
|
|
91
|
+
<Th>{columnNames.name}</Th>
|
|
92
|
+
<Th>{columnNames.branches}</Th>
|
|
93
|
+
<Th>{columnNames.prs}</Th>
|
|
94
|
+
<Th>{columnNames.workspaces}</Th>
|
|
95
|
+
<Th>{columnNames.lastCommit}</Th>
|
|
96
|
+
</Tr>
|
|
97
|
+
</Thead>
|
|
98
|
+
<Tbody>
|
|
99
|
+
{sortedRepositories.map((repo, rowIndex) => (
|
|
100
|
+
<Tr key={rowIndex}>
|
|
101
|
+
<Td
|
|
102
|
+
favorites={{
|
|
103
|
+
isFavorited: isRepoFavorited(repo),
|
|
104
|
+
onFavorite: (_event, isFavoriting) => setRepoFavorited(repo, isFavoriting),
|
|
105
|
+
rowIndex
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
<Td dataLabel={columnNames.name}>{repo.name}</Td>
|
|
109
|
+
<Td dataLabel={columnNames.branches}>{repo.branches}</Td>
|
|
110
|
+
<Td dataLabel={columnNames.prs}>{repo.prs}</Td>
|
|
111
|
+
<Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
|
|
112
|
+
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
|
|
113
|
+
</Tr>
|
|
114
|
+
))}
|
|
115
|
+
</Tbody>
|
|
116
|
+
</TableComposable>
|
|
117
|
+
);
|
|
118
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
3
|
+
|
|
4
|
+
interface Repository {
|
|
5
|
+
name: string;
|
|
6
|
+
branches: string | null;
|
|
7
|
+
prs: string | null;
|
|
8
|
+
workspaces: string;
|
|
9
|
+
lastCommit: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const ComposableTableHoverable: React.FunctionComponent = () => {
|
|
13
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
14
|
+
const repositories: Repository[] = [
|
|
15
|
+
{ name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
|
|
16
|
+
{ name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
|
|
17
|
+
{ name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' }
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const columnNames = {
|
|
21
|
+
name: 'Repositories',
|
|
22
|
+
branches: 'Branches',
|
|
23
|
+
prs: 'Pull requests',
|
|
24
|
+
workspaces: 'Workspaces',
|
|
25
|
+
lastCommit: 'Last commit'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// In this example, selected rows are tracked by the repo names from each row. This could be any unique identifier.
|
|
29
|
+
// This is to prevent state from being based on row order index in case we later add sorting.
|
|
30
|
+
const [selectedRepoNames, setSelectedRepoNames] = React.useState<string[]>([]);
|
|
31
|
+
const setRepoSelected = (repo: Repository, isSelecting = true) =>
|
|
32
|
+
setSelectedRepoNames(prevSelected => {
|
|
33
|
+
const otherSelectedRepoNames = prevSelected.filter(r => r !== repo.name);
|
|
34
|
+
return isSelecting ? [...otherSelectedRepoNames, repo.name] : otherSelectedRepoNames;
|
|
35
|
+
});
|
|
36
|
+
const isRepoSelected = (repo: Repository) => selectedRepoNames.includes(repo.name);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<TableComposable aria-label="Hoverable table">
|
|
40
|
+
<Thead>
|
|
41
|
+
<Tr>
|
|
42
|
+
<Th>{columnNames.name}</Th>
|
|
43
|
+
<Th>{columnNames.branches}</Th>
|
|
44
|
+
<Th>{columnNames.prs}</Th>
|
|
45
|
+
<Th>{columnNames.workspaces}</Th>
|
|
46
|
+
<Th>{columnNames.lastCommit}</Th>
|
|
47
|
+
</Tr>
|
|
48
|
+
</Thead>
|
|
49
|
+
<Tbody>
|
|
50
|
+
{repositories.map(repo => (
|
|
51
|
+
<Tr
|
|
52
|
+
key={repo.name}
|
|
53
|
+
onRowClick={() => setRepoSelected(repo, !isRepoSelected(repo))}
|
|
54
|
+
isHoverable
|
|
55
|
+
isRowSelected={isRepoSelected(repo)}
|
|
56
|
+
>
|
|
57
|
+
<Td dataLabel={columnNames.name}>{repo.name}</Td>
|
|
58
|
+
<Td dataLabel={columnNames.branches}>{repo.branches}</Td>
|
|
59
|
+
<Td dataLabel={columnNames.prs}>{repo.prs}</Td>
|
|
60
|
+
<Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
|
|
61
|
+
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
|
|
62
|
+
</Tr>
|
|
63
|
+
))}
|
|
64
|
+
</Tbody>
|
|
65
|
+
</TableComposable>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
3
|
+
|
|
4
|
+
interface Repository {
|
|
5
|
+
name: string;
|
|
6
|
+
branches: string | null;
|
|
7
|
+
prs: string | null;
|
|
8
|
+
workspaces: string;
|
|
9
|
+
lastCommit: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const ComposableTableMisc: React.FunctionComponent = () => {
|
|
13
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
14
|
+
const repositories: Repository[] = [
|
|
15
|
+
{ name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
|
|
16
|
+
{ name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
|
|
17
|
+
{ name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' }
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const columnNames = {
|
|
21
|
+
name: 'Repositories',
|
|
22
|
+
branches: 'Branches',
|
|
23
|
+
prs: 'Pull requests',
|
|
24
|
+
workspaces: 'Workspaces',
|
|
25
|
+
lastCommit: 'Last commit'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<TableComposable aria-label="Misc table">
|
|
30
|
+
<Thead noWrap>
|
|
31
|
+
<Tr>
|
|
32
|
+
<Th
|
|
33
|
+
info={{
|
|
34
|
+
tooltip: 'More information about repositories',
|
|
35
|
+
className: 'repositories-info-tip',
|
|
36
|
+
tooltipProps: {
|
|
37
|
+
isContentLeftAligned: true
|
|
38
|
+
}
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
{columnNames.name}
|
|
42
|
+
</Th>
|
|
43
|
+
<Th>{columnNames.branches}</Th>
|
|
44
|
+
<Th
|
|
45
|
+
info={{
|
|
46
|
+
popover: (
|
|
47
|
+
<div>
|
|
48
|
+
More <strong>information</strong> on pull requests
|
|
49
|
+
</div>
|
|
50
|
+
),
|
|
51
|
+
ariaLabel: 'More information on pull requests',
|
|
52
|
+
popoverProps: {
|
|
53
|
+
headerContent: columnNames.prs,
|
|
54
|
+
footerContent: <a href="#">Click here for even more info</a>
|
|
55
|
+
}
|
|
56
|
+
}}
|
|
57
|
+
>
|
|
58
|
+
{columnNames.prs}
|
|
59
|
+
</Th>
|
|
60
|
+
<Th>{columnNames.workspaces}</Th>
|
|
61
|
+
<Th textCenter>{columnNames.lastCommit}</Th>
|
|
62
|
+
</Tr>
|
|
63
|
+
</Thead>
|
|
64
|
+
<Tbody>
|
|
65
|
+
{repositories.map((repo, rowIndex) => {
|
|
66
|
+
const isOddRow = (rowIndex + 1) % 2;
|
|
67
|
+
const customStyle = {
|
|
68
|
+
borderLeft: '3px solid var(--pf-global--primary-color--100)'
|
|
69
|
+
};
|
|
70
|
+
// Some arbitrary logic to demonstrate that cell styles can be based on anything
|
|
71
|
+
const nameColSpan = repo.branches === null && repo.prs === null ? 3 : 1;
|
|
72
|
+
const lastCommitTextCenter = rowIndex !== 2;
|
|
73
|
+
return (
|
|
74
|
+
<Tr
|
|
75
|
+
key={repo.name}
|
|
76
|
+
className={isOddRow ? 'odd-row-class' : 'even-row-class'}
|
|
77
|
+
style={isOddRow ? customStyle : {}}
|
|
78
|
+
>
|
|
79
|
+
<Td dataLabel={columnNames.name} colSpan={nameColSpan}>
|
|
80
|
+
{repo.name}
|
|
81
|
+
</Td>
|
|
82
|
+
<Td dataLabel={columnNames.branches}>{repo.branches}</Td>
|
|
83
|
+
<Td dataLabel={columnNames.prs}></Td>
|
|
84
|
+
<Td dataLabel={columnNames.workspaces}></Td>
|
|
85
|
+
<Td dataLabel={columnNames.lastCommit} textCenter={lastCommitTextCenter}></Td>
|
|
86
|
+
</Tr>
|
|
87
|
+
);
|
|
88
|
+
})}
|
|
89
|
+
</Tbody>
|
|
90
|
+
</TableComposable>
|
|
91
|
+
);
|
|
92
|
+
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tr, Th, Tbody, Td, InnerScrollContainer, ThProps } from '@patternfly/react-table';
|
|
3
|
+
import BlueprintIcon from '@patternfly/react-icons/dist/esm/icons/blueprint-icon';
|
|
4
|
+
|
|
5
|
+
interface Fact {
|
|
6
|
+
name: string;
|
|
7
|
+
state: string;
|
|
8
|
+
detail1: string;
|
|
9
|
+
detail2: string;
|
|
10
|
+
detail3: string;
|
|
11
|
+
detail4: string;
|
|
12
|
+
detail5: string;
|
|
13
|
+
detail6: string;
|
|
14
|
+
detail7: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const ComposableTableMultipleStickyColumns: React.FunctionComponent = () => {
|
|
18
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
19
|
+
const facts: Fact[] = Array.from({ length: 9 }, (_, index) => ({
|
|
20
|
+
name: `Fact ${index + 1}`,
|
|
21
|
+
state: `State ${index + 1}`,
|
|
22
|
+
detail1: `Test cell ${index + 1}-3`,
|
|
23
|
+
detail2: `Test cell ${index + 1}-4`,
|
|
24
|
+
detail3: `Test cell ${index + 1}-5`,
|
|
25
|
+
detail4: `Test cell ${index + 1}-6`,
|
|
26
|
+
detail5: `Test cell ${index + 1}-7`,
|
|
27
|
+
detail6: `Test cell ${index + 1}-8`,
|
|
28
|
+
detail7: `Test cell ${index + 1}-9`
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const columnNames = {
|
|
32
|
+
name: 'Fact',
|
|
33
|
+
state: 'State',
|
|
34
|
+
header3: 'Header 3',
|
|
35
|
+
header4: 'Header 4',
|
|
36
|
+
header5: 'Header 5',
|
|
37
|
+
header6: 'Header 6',
|
|
38
|
+
header7: 'Header 7',
|
|
39
|
+
header8: 'Header 8',
|
|
40
|
+
header9: 'Header 9'
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Index of the currently sorted column
|
|
44
|
+
// Note: if you intend to make columns reorderable, you may instead want to use a non-numeric key
|
|
45
|
+
// as the identifier of the sorted column. See the "Compound expandable" example.
|
|
46
|
+
const [activeSortIndex, setActiveSortIndex] = React.useState<number | null>(null);
|
|
47
|
+
|
|
48
|
+
// Sort direction of the currently sorted column
|
|
49
|
+
const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | null>(null);
|
|
50
|
+
|
|
51
|
+
// Since OnSort specifies sorted columns by index, we need sortable values for our object by column index.
|
|
52
|
+
// This example is trivial since our data objects just contain strings, but if the data was more complex
|
|
53
|
+
// this would be a place to return simplified string or number versions of each column to sort by.
|
|
54
|
+
const getSortableRowValues = (fact: Fact): (string | number)[] => {
|
|
55
|
+
const { name, state, detail1, detail2, detail3, detail4, detail5, detail6, detail7 } = fact;
|
|
56
|
+
return [name, state, detail1, detail2, detail3, detail4, detail5, detail6, detail7];
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Note that we perform the sort as part of the component's render logic and not in onSort.
|
|
60
|
+
// We shouldn't store the list of data in state because we don't want to have to sync that with props.
|
|
61
|
+
let sortedFacts = facts;
|
|
62
|
+
if (activeSortIndex !== null) {
|
|
63
|
+
sortedFacts = facts.sort((a, b) => {
|
|
64
|
+
const aValue = getSortableRowValues(a)[activeSortIndex];
|
|
65
|
+
const bValue = getSortableRowValues(b)[activeSortIndex];
|
|
66
|
+
if (aValue === bValue) {
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
if (activeSortDirection === 'asc') {
|
|
70
|
+
return aValue > bValue ? 1 : -1;
|
|
71
|
+
} else {
|
|
72
|
+
return bValue > aValue ? 1 : -1;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const getSortParams = (columnIndex: number): ThProps['sort'] => ({
|
|
78
|
+
sortBy: {
|
|
79
|
+
index: activeSortIndex,
|
|
80
|
+
direction: activeSortDirection
|
|
81
|
+
},
|
|
82
|
+
onSort: (_event, index, direction) => {
|
|
83
|
+
setActiveSortIndex(index);
|
|
84
|
+
setActiveSortDirection(direction);
|
|
85
|
+
},
|
|
86
|
+
columnIndex
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<InnerScrollContainer>
|
|
91
|
+
<TableComposable aria-label="Multiple sticky column table" gridBreakPoint="">
|
|
92
|
+
<Thead>
|
|
93
|
+
<Tr>
|
|
94
|
+
<Th isStickyColumn modifier="truncate" sort={getSortParams(0)}>
|
|
95
|
+
{columnNames.name}
|
|
96
|
+
</Th>
|
|
97
|
+
<Th
|
|
98
|
+
isStickyColumn
|
|
99
|
+
stickyMinWidth="120px"
|
|
100
|
+
stickyLeftOffset="120px"
|
|
101
|
+
hasRightBorder
|
|
102
|
+
modifier="truncate"
|
|
103
|
+
sort={getSortParams(1)}
|
|
104
|
+
>
|
|
105
|
+
{columnNames.state}
|
|
106
|
+
</Th>
|
|
107
|
+
<Th modifier="truncate">{columnNames.header3}</Th>
|
|
108
|
+
<Th modifier="truncate">{columnNames.header4}</Th>
|
|
109
|
+
<Th modifier="truncate">{columnNames.header5}</Th>
|
|
110
|
+
<Th modifier="truncate">{columnNames.header6}</Th>
|
|
111
|
+
<Th modifier="truncate">{columnNames.header7}</Th>
|
|
112
|
+
<Th modifier="truncate">{columnNames.header8}</Th>
|
|
113
|
+
<Th modifier="truncate">{columnNames.header9}</Th>
|
|
114
|
+
</Tr>
|
|
115
|
+
</Thead>
|
|
116
|
+
<Tbody>
|
|
117
|
+
{sortedFacts.map(fact => (
|
|
118
|
+
<Tr key={fact.name}>
|
|
119
|
+
<Th isStickyColumn modifier="truncate">
|
|
120
|
+
{fact.name}
|
|
121
|
+
</Th>
|
|
122
|
+
<Th isStickyColumn stickyMinWidth="120px" stickyLeftOffset="120px" modifier="truncate" hasRightBorder>
|
|
123
|
+
<BlueprintIcon />
|
|
124
|
+
{` ${fact.state}`}
|
|
125
|
+
</Th>
|
|
126
|
+
<Td modifier="nowrap" dataLabel={columnNames.header3}>
|
|
127
|
+
{fact.detail1}
|
|
128
|
+
</Td>
|
|
129
|
+
<Td modifier="nowrap" dataLabel={columnNames.header4}>
|
|
130
|
+
{fact.detail2}
|
|
131
|
+
</Td>
|
|
132
|
+
<Td modifier="nowrap" dataLabel={columnNames.header5}>
|
|
133
|
+
{fact.detail3}
|
|
134
|
+
</Td>
|
|
135
|
+
<Td modifier="nowrap" dataLabel={columnNames.header6}>
|
|
136
|
+
{fact.detail4}
|
|
137
|
+
</Td>
|
|
138
|
+
<Td modifier="nowrap" dataLabel={columnNames.header7}>
|
|
139
|
+
{fact.detail5}
|
|
140
|
+
</Td>
|
|
141
|
+
<Td modifier="nowrap" dataLabel={columnNames.header8}>
|
|
142
|
+
{fact.detail6}
|
|
143
|
+
</Td>
|
|
144
|
+
<Td modifier="nowrap" dataLabel={columnNames.header9}>
|
|
145
|
+
{fact.detail7}
|
|
146
|
+
</Td>
|
|
147
|
+
</Tr>
|
|
148
|
+
))}
|
|
149
|
+
</Tbody>
|
|
150
|
+
</TableComposable>
|
|
151
|
+
</InnerScrollContainer>
|
|
152
|
+
);
|
|
153
|
+
};
|