@patternfly/react-table 6.0.0-alpha.2 → 6.0.0-alpha.4
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 +56 -0
- package/components/package.json +1 -1
- package/deprecated/package.json +1 -1
- package/dist/dynamic/components/Table/package.json +1 -1
- package/dist/dynamic/components/Table/utils/decorators/package.json +1 -1
- package/dist/dynamic/components/Table/utils/package.json +1 -1
- package/dist/dynamic/deprecated/components/Table/base/package.json +1 -1
- package/dist/dynamic/deprecated/components/Table/package.json +1 -1
- package/dist/dynamic/deprecated/components/package.json +1 -1
- package/dist/esm/components/Table/Caption.js +1 -1
- package/dist/esm/components/Table/Caption.js.map +1 -1
- package/dist/esm/components/Table/CollapseColumn.js +1 -1
- package/dist/esm/components/Table/CollapseColumn.js.map +1 -1
- package/dist/esm/components/Table/DraggableRowWrapper.js +2 -2
- package/dist/esm/components/Table/DraggableRowWrapper.js.map +1 -1
- package/dist/esm/components/Table/EditColumn.js +1 -1
- package/dist/esm/components/Table/EditColumn.js.map +1 -1
- package/dist/esm/components/Table/EditableSelectInputCell.js +2 -2
- package/dist/esm/components/Table/EditableSelectInputCell.js.map +1 -1
- package/dist/esm/components/Table/EditableTextCell.js +2 -2
- package/dist/esm/components/Table/EditableTextCell.js.map +1 -1
- package/dist/esm/components/Table/ExpandableRowContent.js +1 -1
- package/dist/esm/components/Table/ExpandableRowContent.js.map +1 -1
- package/dist/esm/components/Table/HeaderCellInfoWrapper.js +1 -1
- package/dist/esm/components/Table/HeaderCellInfoWrapper.js.map +1 -1
- package/dist/esm/components/Table/InnerScrollContainer.js +1 -1
- package/dist/esm/components/Table/InnerScrollContainer.js.map +1 -1
- package/dist/esm/components/Table/OuterScrollContainer.js +1 -1
- package/dist/esm/components/Table/OuterScrollContainer.js.map +1 -1
- package/dist/esm/components/Table/SortColumn.js +1 -1
- package/dist/esm/components/Table/SortColumn.js.map +1 -1
- package/dist/esm/components/Table/Table.js +3 -3
- package/dist/esm/components/Table/Table.js.map +1 -1
- package/dist/esm/components/Table/TableText.js +1 -1
- package/dist/esm/components/Table/TableText.js.map +1 -1
- package/dist/esm/components/Table/Tbody.js +1 -1
- package/dist/esm/components/Table/Tbody.js.map +1 -1
- package/dist/esm/components/Table/Td.js +3 -3
- package/dist/esm/components/Table/Td.js.map +1 -1
- package/dist/esm/components/Table/Th.js +2 -2
- package/dist/esm/components/Table/Th.js.map +1 -1
- package/dist/esm/components/Table/Thead.js +1 -1
- package/dist/esm/components/Table/Thead.js.map +1 -1
- package/dist/esm/components/Table/Tr.js +2 -2
- package/dist/esm/components/Table/Tr.js.map +1 -1
- package/dist/esm/components/Table/TreeRowWrapper.js +2 -2
- package/dist/esm/components/Table/TreeRowWrapper.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/cellActions.js +1 -1
- package/dist/esm/components/Table/utils/decorators/cellActions.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/cellWidth.js +1 -1
- package/dist/esm/components/Table/utils/decorators/cellWidth.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/classNames.js +1 -1
- package/dist/esm/components/Table/utils/decorators/classNames.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/collapsible.js +1 -1
- package/dist/esm/components/Table/utils/decorators/collapsible.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/compoundExpand.js +1 -1
- package/dist/esm/components/Table/utils/decorators/compoundExpand.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/editable.js +1 -1
- package/dist/esm/components/Table/utils/decorators/editable.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/favoritable.js +1 -1
- package/dist/esm/components/Table/utils/decorators/favoritable.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/info.js +1 -1
- package/dist/esm/components/Table/utils/decorators/info.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/selectable.js +2 -2
- package/dist/esm/components/Table/utils/decorators/selectable.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/sortable.js +1 -1
- package/dist/esm/components/Table/utils/decorators/sortable.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/treeRow.js +2 -2
- package/dist/esm/components/Table/utils/decorators/treeRow.js.map +1 -1
- package/dist/esm/components/Table/utils/decorators/wrappable.js +1 -1
- package/dist/esm/components/Table/utils/decorators/wrappable.js.map +1 -1
- package/dist/esm/demos/index.d.ts +2 -0
- package/dist/esm/demos/index.d.ts.map +1 -0
- package/dist/esm/demos/index.js +2 -0
- package/dist/esm/demos/index.js.map +1 -0
- package/dist/esm/demos/sampleData.d.ts +13 -0
- package/dist/esm/demos/sampleData.d.ts.map +1 -0
- package/dist/esm/demos/sampleData.js +764 -0
- package/dist/esm/demos/sampleData.js.map +1 -0
- package/dist/esm/deprecated/components/Table/Table.js +1 -1
- package/dist/esm/deprecated/components/Table/Table.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/js/demos/index.d.ts +2 -0
- package/dist/js/demos/index.d.ts.map +1 -0
- package/dist/js/demos/index.js +5 -0
- package/dist/js/demos/index.js.map +1 -0
- package/dist/js/demos/sampleData.d.ts +13 -0
- package/dist/js/demos/sampleData.d.ts.map +1 -0
- package/dist/js/demos/sampleData.js +767 -0
- package/dist/js/demos/sampleData.js.map +1 -0
- package/dist/js/index.d.ts +1 -0
- package/dist/js/index.d.ts.map +1 -1
- package/dist/js/index.js +1 -0
- package/dist/js/index.js.map +1 -1
- package/dist/umd/react-table.min.js +3 -3
- package/package.json +6 -6
- package/src/components/Table/examples/TableStickyColumnsAndHeader.tsx +5 -4
- package/src/components/Table/utils/transformers.test.tsx +1 -0
- package/src/demos/Table.md +159 -0
- package/src/demos/examples/TableAutomaticPagination.tsx +101 -0
- package/src/{docs/demos/table-demos/BulkSelect.jsx → demos/examples/TableBulkSelect.tsx} +41 -20
- package/src/demos/examples/TableColumnManagement.tsx +486 -0
- package/src/demos/examples/TableColumnManagementWithDraggable.tsx +641 -0
- package/src/{docs/demos/table-demos/Compact.jsx → demos/examples/TableCompact.tsx} +32 -16
- package/src/{docs/demos/table-demos/CompoundExpansion.jsx → demos/examples/TableCompoundExpansion.tsx} +25 -12
- package/src/demos/examples/TableEmptyStateDefault.tsx +60 -0
- package/src/demos/examples/TableEmptyStateError.tsx +53 -0
- package/src/demos/examples/TableEmptyStateLoading.tsx +43 -0
- package/src/{docs/demos/table-demos/ExpandCollapseAll.jsx → demos/examples/TableExpandCollapseAll.tsx} +17 -10
- package/src/demos/examples/TableFilterable.tsx +394 -0
- package/src/{docs/demos/table-demos/SortableResponsive.jsx → demos/examples/TableSortableResponsive.tsx} +29 -27
- package/src/{docs/demos/table-demos/StaticBottomPagination.jsx → demos/examples/TableStaticBottomPagination.tsx} +22 -9
- package/src/{docs/demos/table-demos/StickyFirstColumn.jsx → demos/examples/TableStickyFirstColumn.tsx} +31 -9
- package/src/{docs/demos/table-demos/StickyHeader.jsx → demos/examples/TableStickyHeader.tsx} +3 -3
- package/src/demos/index.ts +1 -0
- package/src/{docs/demos/table-demos/sampleData.js → demos/sampleData.tsx} +88 -77
- package/src/deprecated/components/Table/__tests__/Table.test.tsx +4 -9
- package/src/index.ts +1 -0
- package/src/docs/demos/Table.md +0 -1620
- package/src/docs/demos/table-demos/ColumnManagement.jsx +0 -471
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Badge,
|
|
4
|
+
Button,
|
|
5
|
+
Bullseye,
|
|
6
|
+
EmptyState,
|
|
7
|
+
EmptyStateActions,
|
|
8
|
+
EmptyStateBody,
|
|
9
|
+
EmptyStateIcon,
|
|
10
|
+
EmptyStateHeader,
|
|
11
|
+
EmptyStateFooter,
|
|
12
|
+
Label,
|
|
13
|
+
MenuToggle,
|
|
14
|
+
MenuToggleElement,
|
|
15
|
+
Toolbar,
|
|
16
|
+
ToolbarItem,
|
|
17
|
+
ToolbarContent,
|
|
18
|
+
ToolbarFilter,
|
|
19
|
+
ToolbarToggleGroup,
|
|
20
|
+
ToolbarGroup,
|
|
21
|
+
Select,
|
|
22
|
+
SelectOption,
|
|
23
|
+
SearchInput,
|
|
24
|
+
ToolbarChipGroup
|
|
25
|
+
} from '@patternfly/react-core';
|
|
26
|
+
import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
|
|
27
|
+
import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon';
|
|
28
|
+
import { Table, TableText, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
29
|
+
import { rows, columns } from '@patternfly/react-table/dist/esm/demos/sampleData';
|
|
30
|
+
|
|
31
|
+
export const TableFilterable: React.FunctionComponent = () => {
|
|
32
|
+
const [filters, setFilters] = React.useState<Record<string, string[]>>({ location: [], name: [], status: [] });
|
|
33
|
+
const [currentCategory, setCurrentCategory] = React.useState('Status');
|
|
34
|
+
const [isFilterDropdownOpen, setIsFilterDropdownOpen] = React.useState(false);
|
|
35
|
+
const [isCategoryDropdownOpen, setIsCategoryDropdownOpen] = React.useState(false);
|
|
36
|
+
const [inputValue, setInputValue] = React.useState('');
|
|
37
|
+
|
|
38
|
+
const rowData = rows.slice(0, 10);
|
|
39
|
+
|
|
40
|
+
const onDelete = (type: string | ToolbarChipGroup, id: string) => {
|
|
41
|
+
if (type === 'Location') {
|
|
42
|
+
setFilters({
|
|
43
|
+
...filters,
|
|
44
|
+
location: filters.location.filter((fil: string) => fil !== id)
|
|
45
|
+
});
|
|
46
|
+
} else if (type === 'Name') {
|
|
47
|
+
setFilters({
|
|
48
|
+
...filters,
|
|
49
|
+
name: filters.name.filter((fil: string) => fil !== id)
|
|
50
|
+
});
|
|
51
|
+
} else if (type === 'Status') {
|
|
52
|
+
setFilters({
|
|
53
|
+
...filters,
|
|
54
|
+
status: filters.status.filter((fil: string) => fil !== id)
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
setFilters({ location: [], name: [], status: [] });
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const onCategoryToggle = () => {
|
|
62
|
+
setIsCategoryDropdownOpen(!isCategoryDropdownOpen);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const onCategorySelect = (event: React.MouseEvent<Element, MouseEvent>, value: string) => {
|
|
66
|
+
setCurrentCategory(value);
|
|
67
|
+
setIsCategoryDropdownOpen(false);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const onFilterToggle = () => {
|
|
71
|
+
setIsFilterDropdownOpen(!isFilterDropdownOpen);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const onFilterSelect = () => {
|
|
75
|
+
setIsFilterDropdownOpen(!isFilterDropdownOpen);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const onInputChange = (newValue: string) => {
|
|
79
|
+
setInputValue(newValue);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const onStatusSelect = (event: React.MouseEvent<Element, MouseEvent>, selection: string) => {
|
|
83
|
+
const checked = (event.target as HTMLInputElement).checked;
|
|
84
|
+
setFilters({
|
|
85
|
+
...filters,
|
|
86
|
+
status: checked ? [...filters.status, selection] : filters.status.filter((value) => value !== selection)
|
|
87
|
+
});
|
|
88
|
+
setIsFilterDropdownOpen(false);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const onNameInput = (event: React.KeyboardEvent) => {
|
|
92
|
+
if (event.key && event.key !== 'Enter') {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const prevFilters = filters.name;
|
|
97
|
+
setFilters({ ...filters, name: prevFilters.includes(inputValue) ? prevFilters : [...prevFilters, inputValue] });
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const onLocationSelect = (event: React.MouseEvent<Element, MouseEvent>, selection: string) => {
|
|
101
|
+
setFilters({ ...filters, location: [selection] });
|
|
102
|
+
|
|
103
|
+
setIsFilterDropdownOpen(false);
|
|
104
|
+
onFilterSelect();
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const buildCategoryDropdown = () => {
|
|
108
|
+
const categoryMenuItems = [
|
|
109
|
+
<SelectOption key="cat1" value="Location">
|
|
110
|
+
Location
|
|
111
|
+
</SelectOption>,
|
|
112
|
+
<SelectOption key="cat2" value="Name">
|
|
113
|
+
Name
|
|
114
|
+
</SelectOption>,
|
|
115
|
+
<SelectOption key="cat3" value="Status">
|
|
116
|
+
Status
|
|
117
|
+
</SelectOption>
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<ToolbarItem>
|
|
122
|
+
<Select
|
|
123
|
+
onSelect={onCategorySelect}
|
|
124
|
+
selected={currentCategory}
|
|
125
|
+
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
|
|
126
|
+
<MenuToggle
|
|
127
|
+
ref={toggleRef}
|
|
128
|
+
onClick={onCategoryToggle}
|
|
129
|
+
isExpanded={isCategoryDropdownOpen}
|
|
130
|
+
icon={<FilterIcon />}
|
|
131
|
+
style={
|
|
132
|
+
{
|
|
133
|
+
width: '100%',
|
|
134
|
+
verticalAlign: 'text-bottom'
|
|
135
|
+
} as React.CSSProperties
|
|
136
|
+
}
|
|
137
|
+
>
|
|
138
|
+
{currentCategory}
|
|
139
|
+
</MenuToggle>
|
|
140
|
+
)}
|
|
141
|
+
isOpen={isCategoryDropdownOpen}
|
|
142
|
+
>
|
|
143
|
+
{categoryMenuItems}
|
|
144
|
+
</Select>
|
|
145
|
+
</ToolbarItem>
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const buildFilterDropdown = () => {
|
|
150
|
+
const locationMenuItems = [
|
|
151
|
+
<SelectOption key="raleigh" value="Raleigh">
|
|
152
|
+
Raleigh
|
|
153
|
+
</SelectOption>,
|
|
154
|
+
<SelectOption key="san francisco" value="San Francisco">
|
|
155
|
+
San Francisco
|
|
156
|
+
</SelectOption>,
|
|
157
|
+
<SelectOption key="boston" value="Boston">
|
|
158
|
+
Boston
|
|
159
|
+
</SelectOption>,
|
|
160
|
+
<SelectOption key="atlanta" value="Atlanta">
|
|
161
|
+
Atlanta
|
|
162
|
+
</SelectOption>
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
const statusMenuItems = [
|
|
166
|
+
<SelectOption hasCheckbox key="statusRunning" value="Running" isSelected={filters.status.includes('Running')}>
|
|
167
|
+
Running
|
|
168
|
+
</SelectOption>,
|
|
169
|
+
<SelectOption hasCheckbox key="statusStopped" value="Stopped" isSelected={filters.status.includes('Stopped')}>
|
|
170
|
+
Stopped
|
|
171
|
+
</SelectOption>,
|
|
172
|
+
<SelectOption hasCheckbox key="statusDown" value="Down" isSelected={filters.status.includes('Down')}>
|
|
173
|
+
Down
|
|
174
|
+
</SelectOption>,
|
|
175
|
+
<SelectOption hasCheckbox key="statusDegraded" value="Degraded" isSelected={filters.status.includes('Degraded')}>
|
|
176
|
+
Degraded
|
|
177
|
+
</SelectOption>,
|
|
178
|
+
<SelectOption
|
|
179
|
+
hasCheckbox
|
|
180
|
+
key="statusMaint"
|
|
181
|
+
value="Needs maintenance"
|
|
182
|
+
isSelected={filters.status.includes('Needs maintenance')}
|
|
183
|
+
>
|
|
184
|
+
Needs maintenance
|
|
185
|
+
</SelectOption>
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<React.Fragment>
|
|
190
|
+
<ToolbarFilter
|
|
191
|
+
chips={filters.location}
|
|
192
|
+
deleteChip={(category, chip) => onDelete(category, chip as string)}
|
|
193
|
+
categoryName="Location"
|
|
194
|
+
showToolbarItem={currentCategory === 'Location'}
|
|
195
|
+
>
|
|
196
|
+
<Select
|
|
197
|
+
aria-label="Location"
|
|
198
|
+
onSelect={onLocationSelect}
|
|
199
|
+
selected={filters.location[0]}
|
|
200
|
+
isOpen={isFilterDropdownOpen}
|
|
201
|
+
popperProps={{ minWidth: '100px' }}
|
|
202
|
+
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
|
|
203
|
+
<MenuToggle
|
|
204
|
+
ref={toggleRef}
|
|
205
|
+
onClick={onFilterToggle}
|
|
206
|
+
isExpanded={isFilterDropdownOpen}
|
|
207
|
+
style={
|
|
208
|
+
{
|
|
209
|
+
width: '100%',
|
|
210
|
+
verticalAlign: 'text-bottom'
|
|
211
|
+
} as React.CSSProperties
|
|
212
|
+
}
|
|
213
|
+
>
|
|
214
|
+
{filters.location[0] || `Any`}
|
|
215
|
+
</MenuToggle>
|
|
216
|
+
)}
|
|
217
|
+
>
|
|
218
|
+
{locationMenuItems}
|
|
219
|
+
</Select>
|
|
220
|
+
</ToolbarFilter>
|
|
221
|
+
<ToolbarFilter
|
|
222
|
+
chips={filters.name}
|
|
223
|
+
deleteChip={(category, chip) => onDelete(category, chip as string)}
|
|
224
|
+
categoryName="Name"
|
|
225
|
+
showToolbarItem={currentCategory === 'Name'}
|
|
226
|
+
>
|
|
227
|
+
<SearchInput
|
|
228
|
+
aria-label="name filter"
|
|
229
|
+
placeholder="Filter by name..."
|
|
230
|
+
onChange={(_event, value) => onInputChange(value)}
|
|
231
|
+
value={inputValue}
|
|
232
|
+
onClear={() => {
|
|
233
|
+
onInputChange('');
|
|
234
|
+
}}
|
|
235
|
+
onSearch={onNameInput}
|
|
236
|
+
/>
|
|
237
|
+
</ToolbarFilter>
|
|
238
|
+
<ToolbarFilter
|
|
239
|
+
chips={filters.status}
|
|
240
|
+
deleteChip={(category, chip) => onDelete(category, chip as string)}
|
|
241
|
+
categoryName="Status"
|
|
242
|
+
showToolbarItem={currentCategory === 'Status'}
|
|
243
|
+
>
|
|
244
|
+
<Select
|
|
245
|
+
aria-label="Status"
|
|
246
|
+
isOpen={isFilterDropdownOpen}
|
|
247
|
+
popperProps={{ minWidth: '100px' }}
|
|
248
|
+
onSelect={onStatusSelect}
|
|
249
|
+
selected={filters.status}
|
|
250
|
+
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
|
|
251
|
+
<MenuToggle
|
|
252
|
+
ref={toggleRef}
|
|
253
|
+
onClick={onFilterToggle}
|
|
254
|
+
isExpanded={isFilterDropdownOpen}
|
|
255
|
+
style={
|
|
256
|
+
{
|
|
257
|
+
width: '100%',
|
|
258
|
+
verticalAlign: 'text-bottom'
|
|
259
|
+
} as React.CSSProperties
|
|
260
|
+
}
|
|
261
|
+
>
|
|
262
|
+
Filter by status
|
|
263
|
+
{filters.status.length > 0 && <Badge isRead>{filters.status.length}</Badge>}
|
|
264
|
+
</MenuToggle>
|
|
265
|
+
)}
|
|
266
|
+
>
|
|
267
|
+
{statusMenuItems}
|
|
268
|
+
</Select>
|
|
269
|
+
</ToolbarFilter>
|
|
270
|
+
</React.Fragment>
|
|
271
|
+
);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const renderToolbar = () => (
|
|
275
|
+
<Toolbar
|
|
276
|
+
id="toolbar-with-chip-groups"
|
|
277
|
+
clearAllFilters={() => setFilters({ location: [], name: [], status: [] })}
|
|
278
|
+
collapseListedFiltersBreakpoint="xl"
|
|
279
|
+
>
|
|
280
|
+
<ToolbarContent>
|
|
281
|
+
<ToolbarToggleGroup toggleIcon={<FilterIcon />} breakpoint="xl">
|
|
282
|
+
<ToolbarGroup
|
|
283
|
+
variant="filter-group"
|
|
284
|
+
style={
|
|
285
|
+
{
|
|
286
|
+
lineHeight: '22px',
|
|
287
|
+
alignItems: 'center'
|
|
288
|
+
} as React.CSSProperties
|
|
289
|
+
}
|
|
290
|
+
>
|
|
291
|
+
{buildCategoryDropdown()}
|
|
292
|
+
{buildFilterDropdown()}
|
|
293
|
+
</ToolbarGroup>
|
|
294
|
+
</ToolbarToggleGroup>
|
|
295
|
+
</ToolbarContent>
|
|
296
|
+
</Toolbar>
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
const filteredRows =
|
|
300
|
+
filters.name.length > 0 || filters.location.length > 0 || filters.status.length > 0
|
|
301
|
+
? rowData.filter(
|
|
302
|
+
(row) =>
|
|
303
|
+
(filters.name.length === 0 ||
|
|
304
|
+
filters.name.some((name) => row.name.toLowerCase().includes(name.toLowerCase()))) &&
|
|
305
|
+
(filters.location.length === 0 || filters.location.includes(row.location)) &&
|
|
306
|
+
(filters.status.length === 0 || filters.status.includes(row.status))
|
|
307
|
+
)
|
|
308
|
+
: rowData;
|
|
309
|
+
|
|
310
|
+
const emptyState = (
|
|
311
|
+
<EmptyState>
|
|
312
|
+
<EmptyStateHeader
|
|
313
|
+
titleText="Clear all filters and try again."
|
|
314
|
+
headingLevel="h5"
|
|
315
|
+
icon={<EmptyStateIcon icon={SearchIcon} />}
|
|
316
|
+
/>
|
|
317
|
+
<EmptyStateBody>No results match the filter criteria. Clear all filters and try again.</EmptyStateBody>
|
|
318
|
+
<EmptyStateFooter>
|
|
319
|
+
<EmptyStateActions>
|
|
320
|
+
<Button
|
|
321
|
+
variant="link"
|
|
322
|
+
onClick={() => {
|
|
323
|
+
setFilters({ location: [], name: [], status: [] });
|
|
324
|
+
}}
|
|
325
|
+
>
|
|
326
|
+
Clear all filters
|
|
327
|
+
</Button>
|
|
328
|
+
</EmptyStateActions>
|
|
329
|
+
</EmptyStateFooter>
|
|
330
|
+
</EmptyState>
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
const renderLabel = (labelText: string) => {
|
|
334
|
+
switch (labelText) {
|
|
335
|
+
case 'Running':
|
|
336
|
+
return <Label color="green">{labelText}</Label>;
|
|
337
|
+
case 'Stopped':
|
|
338
|
+
return <Label color="orange">{labelText}</Label>;
|
|
339
|
+
case 'Needs maintenance':
|
|
340
|
+
return <Label color="blue">{labelText}</Label>;
|
|
341
|
+
case 'Down':
|
|
342
|
+
return <Label color="red">{labelText}</Label>;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
return (
|
|
347
|
+
<React.Fragment>
|
|
348
|
+
{renderToolbar()}
|
|
349
|
+
<Table aria-label="Filterable Table Demo">
|
|
350
|
+
<Thead>
|
|
351
|
+
<Tr>
|
|
352
|
+
<Th key={0}>{columns[0]}</Th>
|
|
353
|
+
<Th key={1}>{columns[1]}</Th>
|
|
354
|
+
<Th key={2}>{columns[2]}</Th>
|
|
355
|
+
<Th key={3}>{columns[3]}</Th>
|
|
356
|
+
<Th key={4}>{columns[4]}</Th>
|
|
357
|
+
<Th key={5}>{columns[5]}</Th>
|
|
358
|
+
<Th key={6}>{columns[6]}</Th>
|
|
359
|
+
<Th key={7} width={10}>
|
|
360
|
+
{columns[7]}
|
|
361
|
+
</Th>
|
|
362
|
+
</Tr>
|
|
363
|
+
</Thead>
|
|
364
|
+
<Tbody>
|
|
365
|
+
{filteredRows.slice(0, 10).map((row, rowIndex) => (
|
|
366
|
+
<Tr key={rowIndex}>
|
|
367
|
+
<>
|
|
368
|
+
<Td dataLabel={columns[0]}>{row.name}</Td>
|
|
369
|
+
<Td dataLabel={columns[1]}>{row.threads}</Td>
|
|
370
|
+
<Td dataLabel={columns[2]}>{row.applications}</Td>
|
|
371
|
+
<Td dataLabel={columns[3]}>{row.workspaces}</Td>
|
|
372
|
+
<Td dataLabel={columns[4]}>{renderLabel(row.status)}</Td>
|
|
373
|
+
<Td dataLabel={columns[5]}>{row.location}</Td>
|
|
374
|
+
<Td dataLabel={columns[6]}>{row.lastModified}</Td>
|
|
375
|
+
<Td dataLabel={columns[7]} modifier="truncate">
|
|
376
|
+
<TableText>
|
|
377
|
+
<a href="#">{row.url}</a>
|
|
378
|
+
</TableText>
|
|
379
|
+
</Td>
|
|
380
|
+
</>
|
|
381
|
+
</Tr>
|
|
382
|
+
))}
|
|
383
|
+
{filteredRows.length === 0 && (
|
|
384
|
+
<Tr>
|
|
385
|
+
<Td colSpan={8}>
|
|
386
|
+
<Bullseye>{emptyState}</Bullseye>
|
|
387
|
+
</Td>
|
|
388
|
+
</Tr>
|
|
389
|
+
)}
|
|
390
|
+
</Tbody>
|
|
391
|
+
</Table>
|
|
392
|
+
</React.Fragment>
|
|
393
|
+
);
|
|
394
|
+
};
|
|
@@ -7,18 +7,10 @@ import {
|
|
|
7
7
|
DropdownList,
|
|
8
8
|
Flex,
|
|
9
9
|
FlexItem,
|
|
10
|
-
Label,
|
|
11
10
|
MenuToggle,
|
|
12
11
|
MenuToggleElement,
|
|
13
|
-
OverflowMenu,
|
|
14
|
-
OverflowMenuContent,
|
|
15
|
-
OverflowMenuControl,
|
|
16
|
-
OverflowMenuDropdownItem,
|
|
17
|
-
OverflowMenuGroup,
|
|
18
|
-
OverflowMenuItem,
|
|
19
12
|
PageSection,
|
|
20
13
|
Pagination,
|
|
21
|
-
Select,
|
|
22
14
|
SelectOption,
|
|
23
15
|
SelectList,
|
|
24
16
|
SelectGroup,
|
|
@@ -27,7 +19,16 @@ import {
|
|
|
27
19
|
Toolbar,
|
|
28
20
|
ToolbarContent,
|
|
29
21
|
ToolbarGroup,
|
|
30
|
-
ToolbarItem
|
|
22
|
+
ToolbarItem,
|
|
23
|
+
OverflowMenuDropdownItem,
|
|
24
|
+
PaginationVariant,
|
|
25
|
+
Label,
|
|
26
|
+
Select,
|
|
27
|
+
OverflowMenu,
|
|
28
|
+
OverflowMenuContent,
|
|
29
|
+
OverflowMenuControl,
|
|
30
|
+
OverflowMenuGroup,
|
|
31
|
+
OverflowMenuItem
|
|
31
32
|
} from '@patternfly/react-core';
|
|
32
33
|
import { Table, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
33
34
|
import CloneIcon from '@patternfly/react-icons/dist/esm/icons/clone-icon';
|
|
@@ -37,15 +38,17 @@ import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon';
|
|
|
37
38
|
import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
|
|
38
39
|
import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon';
|
|
39
40
|
import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
|
|
40
|
-
import { DashboardWrapper } from '@patternfly/react-core/
|
|
41
|
+
import { DashboardWrapper } from '@patternfly/react-core/dist/esm/demos/DashboardWrapper';
|
|
41
42
|
import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
|
|
42
|
-
import { rows, columns } from '@patternfly/react-table/
|
|
43
|
+
import { rows, columns, SampleDataRow } from '@patternfly/react-table/dist/esm/demos/sampleData';
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
type Direction = 'asc' | 'desc' | undefined;
|
|
46
|
+
|
|
47
|
+
export const TableSortableResponsive: React.FunctionComponent = () => {
|
|
45
48
|
const [isKebabDropdownOpen, setIsKebabDropdownOpen] = React.useState(false);
|
|
46
49
|
|
|
47
|
-
const sortRows = (
|
|
48
|
-
|
|
50
|
+
const sortRows = (rows: SampleDataRow[], sortIndex: number, sortDirection: Direction) =>
|
|
51
|
+
[...rows].sort((a, b) => {
|
|
49
52
|
let returnValue = 0;
|
|
50
53
|
if (sortIndex === 0 || sortIndex === 7) {
|
|
51
54
|
returnValue = 1;
|
|
@@ -61,7 +64,6 @@ export const ComposableTableSortable = () => {
|
|
|
61
64
|
}
|
|
62
65
|
return returnValue;
|
|
63
66
|
});
|
|
64
|
-
};
|
|
65
67
|
|
|
66
68
|
const [sortedData, setSortedData] = React.useState([...sortRows(rows, 0, 'asc')]);
|
|
67
69
|
const [sortedRows, setSortedRows] = React.useState([...sortedData]);
|
|
@@ -71,11 +73,11 @@ export const ComposableTableSortable = () => {
|
|
|
71
73
|
// index of the currently active column
|
|
72
74
|
const [activeSortIndex, setActiveSortIndex] = React.useState(0);
|
|
73
75
|
// sort direction of the currently active column
|
|
74
|
-
const [activeSortDirection, setActiveSortDirection] = React.useState('asc');
|
|
76
|
+
const [activeSortDirection, setActiveSortDirection] = React.useState<Direction>('asc');
|
|
75
77
|
// sort dropdown expansion
|
|
76
78
|
const [isSortDropdownOpen, setIsSortDropdownOpen] = React.useState(false);
|
|
77
79
|
|
|
78
|
-
const onSort = (
|
|
80
|
+
const onSort = (_event: any, index: number, direction: Direction) => {
|
|
79
81
|
setActiveSortIndex(index);
|
|
80
82
|
setActiveSortDirection(direction);
|
|
81
83
|
|
|
@@ -88,17 +90,17 @@ export const ComposableTableSortable = () => {
|
|
|
88
90
|
setSortedRows(sortedData.slice((page - 1) * perPage, page * perPage - 1));
|
|
89
91
|
}, [sortedData, page, perPage]);
|
|
90
92
|
|
|
91
|
-
const handleSetPage = (_evt, newPage) => {
|
|
93
|
+
const handleSetPage = (_evt: React.MouseEvent | React.KeyboardEvent | MouseEvent, newPage: number) => {
|
|
92
94
|
setPage(newPage);
|
|
93
95
|
};
|
|
94
96
|
|
|
95
|
-
const handlePerPageSelect = (_evt, newPerPage) => {
|
|
97
|
+
const handlePerPageSelect = (_evt: React.MouseEvent | React.KeyboardEvent | MouseEvent, newPerPage: number) => {
|
|
96
98
|
setPerPage(newPerPage);
|
|
97
99
|
};
|
|
98
100
|
|
|
99
|
-
const renderPagination = (variant) => (
|
|
101
|
+
const renderPagination = (variant: 'top' | 'bottom' | PaginationVariant, isCompact: boolean) => (
|
|
100
102
|
<Pagination
|
|
101
|
-
isCompact
|
|
103
|
+
isCompact={isCompact}
|
|
102
104
|
itemCount={rows.length}
|
|
103
105
|
page={page}
|
|
104
106
|
perPage={perPage}
|
|
@@ -117,7 +119,7 @@ export const ComposableTableSortable = () => {
|
|
|
117
119
|
/>
|
|
118
120
|
);
|
|
119
121
|
|
|
120
|
-
const renderLabel = (labelText) => {
|
|
122
|
+
const renderLabel = (labelText: string) => {
|
|
121
123
|
switch (labelText) {
|
|
122
124
|
case 'Running':
|
|
123
125
|
return <Label color="green">{labelText}</Label>;
|
|
@@ -137,12 +139,12 @@ export const ComposableTableSortable = () => {
|
|
|
137
139
|
<Select
|
|
138
140
|
isOpen={isSortDropdownOpen}
|
|
139
141
|
selected={[activeSortDirection, activeSortIndex]}
|
|
140
|
-
onOpenChange={(isOpen) => setIsSortDropdownOpen(isOpen)}
|
|
141
|
-
onSelect={(event, value) => {
|
|
142
|
+
onOpenChange={(isOpen: boolean) => setIsSortDropdownOpen(isOpen)}
|
|
143
|
+
onSelect={(event: React.MouseEvent<Element, MouseEvent>, value: string | number) => {
|
|
142
144
|
if (value === 'asc' || value === 'desc') {
|
|
143
145
|
onSort(event, activeSortIndex, value);
|
|
144
146
|
} else {
|
|
145
|
-
onSort(event, value
|
|
147
|
+
onSort(event, value as number, activeSortDirection ?? 'asc');
|
|
146
148
|
}
|
|
147
149
|
}}
|
|
148
150
|
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
|
|
@@ -192,8 +194,8 @@ export const ComposableTableSortable = () => {
|
|
|
192
194
|
<OverflowMenuControl hasAdditionalOptions>
|
|
193
195
|
<Dropdown
|
|
194
196
|
onSelect={() => setIsKebabDropdownOpen(!isKebabDropdownOpen)}
|
|
195
|
-
onOpenChange={(isKebabDropdownOpen) => setIsKebabDropdownOpen(isKebabDropdownOpen)}
|
|
196
|
-
toggle={(toggleRef) => (
|
|
197
|
+
onOpenChange={(isKebabDropdownOpen: boolean) => setIsKebabDropdownOpen(isKebabDropdownOpen)}
|
|
198
|
+
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
|
|
197
199
|
<MenuToggle
|
|
198
200
|
ref={toggleRef}
|
|
199
201
|
aria-label="overflow menu"
|
|
@@ -13,29 +13,42 @@ import {
|
|
|
13
13
|
MenuToggleElement,
|
|
14
14
|
Label,
|
|
15
15
|
Select,
|
|
16
|
-
SelectOption
|
|
16
|
+
SelectOption,
|
|
17
|
+
PaginationVariant
|
|
17
18
|
} from '@patternfly/react-core';
|
|
18
19
|
import { Table, TableText, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
19
20
|
import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon';
|
|
20
|
-
import { DashboardWrapper } from '@patternfly/react-core/
|
|
21
|
-
import { rows, columns } from '@patternfly/react-table/
|
|
21
|
+
import { DashboardWrapper } from '@patternfly/react-core/dist/esm/demos/DashboardWrapper';
|
|
22
|
+
import { rows, columns } from '@patternfly/react-table/dist/esm/demos/sampleData';
|
|
22
23
|
|
|
23
|
-
export const
|
|
24
|
+
export const TableStaticBottomPagination: React.FunctionComponent = () => {
|
|
24
25
|
const [isSelectOpen, setIsSelectOpen] = React.useState(false);
|
|
25
26
|
const [page, setPage] = React.useState(1);
|
|
26
27
|
const [perPage, setPerPage] = React.useState(10);
|
|
27
28
|
const [paginatedRows, setPaginatedRows] = React.useState(rows.slice(0, 10));
|
|
28
|
-
const handleSetPage = (
|
|
29
|
+
const handleSetPage = (
|
|
30
|
+
_evt: React.MouseEvent | React.KeyboardEvent | MouseEvent,
|
|
31
|
+
newPage: number,
|
|
32
|
+
_perPage: number,
|
|
33
|
+
startIdx: number,
|
|
34
|
+
endIdx: number
|
|
35
|
+
) => {
|
|
29
36
|
setPaginatedRows(rows.slice(startIdx, endIdx));
|
|
30
37
|
setPage(newPage);
|
|
31
38
|
};
|
|
32
|
-
handlePerPageSelect = (
|
|
39
|
+
const handlePerPageSelect = (
|
|
40
|
+
_evt: React.MouseEvent | React.KeyboardEvent | MouseEvent,
|
|
41
|
+
newPerPage: number,
|
|
42
|
+
newPage: number,
|
|
43
|
+
startIdx: number,
|
|
44
|
+
endIdx: number
|
|
45
|
+
) => {
|
|
33
46
|
setPaginatedRows(rows.slice(startIdx, endIdx));
|
|
34
47
|
setPage(newPage);
|
|
35
48
|
setPerPage(newPerPage);
|
|
36
49
|
};
|
|
37
50
|
|
|
38
|
-
const renderPagination = (variant, isCompact) => (
|
|
51
|
+
const renderPagination = (variant: PaginationVariant | 'bottom' | 'top', isCompact: boolean) => (
|
|
39
52
|
<Pagination
|
|
40
53
|
isCompact={isCompact}
|
|
41
54
|
itemCount={rows.length}
|
|
@@ -51,7 +64,7 @@ export const StaticBottomPagination = () => {
|
|
|
51
64
|
/>
|
|
52
65
|
);
|
|
53
66
|
|
|
54
|
-
const renderLabel = (labelText) => {
|
|
67
|
+
const renderLabel = (labelText: string) => {
|
|
55
68
|
switch (labelText) {
|
|
56
69
|
case 'Running':
|
|
57
70
|
return (
|
|
@@ -93,7 +106,7 @@ export const StaticBottomPagination = () => {
|
|
|
93
106
|
</MenuToggle>
|
|
94
107
|
)}
|
|
95
108
|
isOpen={isSelectOpen}
|
|
96
|
-
onOpenChange={(isOpen) => setIsSelectOpen(isOpen)}
|
|
109
|
+
onOpenChange={(isOpen: boolean) => setIsSelectOpen(isOpen)}
|
|
97
110
|
onSelect={() => setIsSelectOpen(!isSelectOpen)}
|
|
98
111
|
>
|
|
99
112
|
{[
|
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Table, Thead, Tr, Th, Tbody, Td, InnerScrollContainer } from '@patternfly/react-table';
|
|
3
3
|
import { Card, PageSection } from '@patternfly/react-core';
|
|
4
|
-
import { DashboardWrapper } from '@patternfly/react-core/
|
|
4
|
+
import { DashboardWrapper } from '@patternfly/react-core/dist/esm/demos/DashboardWrapper';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
type Direction = 'asc' | 'desc' | undefined;
|
|
7
|
+
|
|
8
|
+
interface Fact {
|
|
9
|
+
name: string;
|
|
10
|
+
state: string;
|
|
11
|
+
detail1: string;
|
|
12
|
+
detail2: string;
|
|
13
|
+
detail3: string;
|
|
14
|
+
detail4: string;
|
|
15
|
+
detail5: string;
|
|
16
|
+
detail6: string;
|
|
17
|
+
detail7: string;
|
|
18
|
+
detail8: string;
|
|
19
|
+
detail9: string;
|
|
20
|
+
detail10: string;
|
|
21
|
+
detail11: string;
|
|
22
|
+
detail12: string;
|
|
23
|
+
detail13: string;
|
|
24
|
+
detail14: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const TableStickyFirstColumn = () => {
|
|
7
28
|
const facts = Array.from(
|
|
8
29
|
{
|
|
9
30
|
length: 9
|
|
@@ -45,9 +66,10 @@ export const StickyFirstColumn = () => {
|
|
|
45
66
|
header15: 'Header 15',
|
|
46
67
|
header16: 'Header 16'
|
|
47
68
|
};
|
|
48
|
-
|
|
49
|
-
const [
|
|
50
|
-
const
|
|
69
|
+
|
|
70
|
+
const [activeSortIndex, setActiveSortIndex] = React.useState(-1);
|
|
71
|
+
const [activeSortDirection, setActiveSortDirection] = React.useState<Direction>('asc');
|
|
72
|
+
const getSortableRowValues = (fact: Fact) => {
|
|
51
73
|
const {
|
|
52
74
|
name,
|
|
53
75
|
state,
|
|
@@ -86,7 +108,7 @@ export const StickyFirstColumn = () => {
|
|
|
86
108
|
];
|
|
87
109
|
};
|
|
88
110
|
let sortedFacts = facts;
|
|
89
|
-
if (activeSortIndex
|
|
111
|
+
if (activeSortIndex > -1) {
|
|
90
112
|
sortedFacts = facts.sort((a, b) => {
|
|
91
113
|
const aValue = getSortableRowValues(a)[activeSortIndex];
|
|
92
114
|
const bValue = getSortableRowValues(b)[activeSortIndex];
|
|
@@ -100,12 +122,12 @@ export const StickyFirstColumn = () => {
|
|
|
100
122
|
}
|
|
101
123
|
});
|
|
102
124
|
}
|
|
103
|
-
const getSortParams = columnIndex => ({
|
|
125
|
+
const getSortParams = (columnIndex: number) => ({
|
|
104
126
|
sortBy: {
|
|
105
127
|
index: activeSortIndex,
|
|
106
128
|
direction: activeSortDirection
|
|
107
129
|
},
|
|
108
|
-
onSort: (_event, index, direction) => {
|
|
130
|
+
onSort: (_event: React.MouseEvent, index: number, direction: Direction) => {
|
|
109
131
|
setActiveSortIndex(index);
|
|
110
132
|
setActiveSortDirection(direction);
|
|
111
133
|
},
|
|
@@ -148,7 +170,7 @@ export const StickyFirstColumn = () => {
|
|
|
148
170
|
</Tr>
|
|
149
171
|
</Thead>
|
|
150
172
|
<Tbody>
|
|
151
|
-
{sortedFacts.map(fact => (
|
|
173
|
+
{sortedFacts.map((fact) => (
|
|
152
174
|
<Tr key={fact.name}>
|
|
153
175
|
<Th isStickyColumn stickyMinWidth="100px" hasRightBorder modifier="truncate">
|
|
154
176
|
{fact.name}
|
package/src/{docs/demos/table-demos/StickyHeader.jsx → demos/examples/TableStickyHeader.tsx}
RENAMED
|
@@ -2,10 +2,10 @@ import React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { Card, Label, PageSection } from '@patternfly/react-core';
|
|
4
4
|
import { Table, Thead, Tr, Th, Tbody, Td, TableText } from '@patternfly/react-table';
|
|
5
|
-
import { DashboardWrapper } from '@patternfly/react-core/
|
|
6
|
-
import { rows, columns } from '@patternfly/react-table/
|
|
5
|
+
import { DashboardWrapper } from '@patternfly/react-core/dist/esm/demos/DashboardWrapper';
|
|
6
|
+
import { rows, columns } from '@patternfly/react-table/dist/esm/demos/sampleData';
|
|
7
7
|
|
|
8
|
-
export const
|
|
8
|
+
export const TableStickyHeader: React.FunctionComponent = () => {
|
|
9
9
|
const renderLabel = (labelText: string) => {
|
|
10
10
|
switch (labelText) {
|
|
11
11
|
case 'Running':
|