@patternfly/react-core 4.247.1 → 4.249.0

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/esm/components/Icon/Icon.d.ts +25 -0
  3. package/dist/esm/components/Icon/Icon.d.ts.map +1 -0
  4. package/dist/esm/components/Icon/Icon.js +14 -0
  5. package/dist/esm/components/Icon/Icon.js.map +1 -0
  6. package/dist/esm/components/Icon/index.d.ts +2 -0
  7. package/dist/esm/components/Icon/index.d.ts.map +1 -0
  8. package/dist/esm/components/Icon/index.js +2 -0
  9. package/dist/esm/components/Icon/index.js.map +1 -0
  10. package/dist/esm/components/Menu/Menu.d.ts.map +1 -1
  11. package/dist/esm/components/Menu/Menu.js +10 -3
  12. package/dist/esm/components/Menu/Menu.js.map +1 -1
  13. package/dist/esm/components/MenuToggle/MenuToggle.d.ts.map +1 -1
  14. package/dist/esm/components/MenuToggle/MenuToggle.js +1 -1
  15. package/dist/esm/components/MenuToggle/MenuToggle.js.map +1 -1
  16. package/dist/esm/components/index.d.ts +1 -0
  17. package/dist/esm/components/index.d.ts.map +1 -1
  18. package/dist/esm/components/index.js +1 -0
  19. package/dist/esm/components/index.js.map +1 -1
  20. package/dist/js/components/Icon/Icon.d.ts +25 -0
  21. package/dist/js/components/Icon/Icon.d.ts.map +1 -0
  22. package/dist/js/components/Icon/Icon.js +18 -0
  23. package/dist/js/components/Icon/Icon.js.map +1 -0
  24. package/dist/js/components/Icon/index.d.ts +2 -0
  25. package/dist/js/components/Icon/index.d.ts.map +1 -0
  26. package/dist/js/components/Icon/index.js +5 -0
  27. package/dist/js/components/Icon/index.js.map +1 -0
  28. package/dist/js/components/Menu/Menu.d.ts.map +1 -1
  29. package/dist/js/components/Menu/Menu.js +10 -3
  30. package/dist/js/components/Menu/Menu.js.map +1 -1
  31. package/dist/js/components/MenuToggle/MenuToggle.d.ts.map +1 -1
  32. package/dist/js/components/MenuToggle/MenuToggle.js +1 -1
  33. package/dist/js/components/MenuToggle/MenuToggle.js.map +1 -1
  34. package/dist/js/components/index.d.ts +1 -0
  35. package/dist/js/components/index.d.ts.map +1 -1
  36. package/dist/js/components/index.js +1 -0
  37. package/dist/js/components/index.js.map +1 -1
  38. package/dist/umd/react-core.min.css +925 -788
  39. package/dist/umd/react-core.min.js +1 -1
  40. package/package.json +2 -2
  41. package/src/components/Icon/Icon.tsx +66 -0
  42. package/src/components/Icon/__tests__/Icon.test.tsx +196 -0
  43. package/src/components/Icon/__tests__/__snapshots__/Icon.test.tsx.snap +82 -0
  44. package/src/components/Icon/examples/Icon.md +61 -0
  45. package/src/components/Icon/examples/IconBasic.tsx +23 -0
  46. package/src/components/Icon/examples/IconContentSizes.tsx +20 -0
  47. package/src/components/Icon/examples/IconCustomProgress.tsx +24 -0
  48. package/src/components/Icon/examples/IconInline.tsx +62 -0
  49. package/src/components/Icon/examples/IconProgress.tsx +24 -0
  50. package/src/components/Icon/examples/IconSizes.tsx +20 -0
  51. package/src/components/Icon/examples/IconStatus.tsx +27 -0
  52. package/src/components/Icon/index.ts +1 -0
  53. package/src/components/Menu/Menu.tsx +13 -7
  54. package/src/components/MenuToggle/MenuToggle.tsx +1 -0
  55. package/src/components/index.ts +1 -0
  56. package/src/demos/Filters/FilterDemos.md +27 -5
  57. package/src/demos/Filters/examples/FilterAttributeSearch.tsx +701 -0
  58. package/src/demos/Filters/examples/FilterCheckboxSelect.tsx +66 -53
  59. package/src/demos/Filters/examples/FilterFaceted.tsx +512 -0
  60. package/src/demos/Filters/examples/FilterMixedSelectGroup.tsx +569 -0
  61. package/src/demos/Filters/examples/FilterSameSelectGroup.tsx +542 -0
  62. package/src/demos/Filters/examples/FilterSearchInput.tsx +91 -68
  63. package/src/demos/Filters/examples/FilterSingleSelect.tsx +63 -52
@@ -17,7 +17,8 @@ import {
17
17
  Title,
18
18
  EmptyStateBody,
19
19
  EmptyStatePrimary,
20
- Button
20
+ Button,
21
+ Bullseye
21
22
  } from '@patternfly/react-core';
22
23
  import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
23
24
  import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
@@ -36,7 +37,7 @@ const repositories: Repository[] = [
36
37
  { name: 'US-Node 1', threads: '5', apps: '25', workspaces: '5', status: 'Stopped', location: 'Raleigh' },
37
38
  { name: 'US-Node 2', threads: '5', apps: '30', workspaces: '2', status: 'Down', location: 'Westford' },
38
39
  { name: 'US-Node 3', threads: '13', apps: '35', workspaces: '12', status: 'Degraded', location: 'Boston' },
39
- { name: 'US-Node 4', threads: '2', apps: '5', workspaces: '18', status: 'Needs Maintainence', location: 'Raleigh' },
40
+ { name: 'US-Node 4', threads: '2', apps: '5', workspaces: '18', status: 'Needs Maintenance', location: 'Raleigh' },
40
41
  { name: 'US-Node 5', threads: '7', apps: '30', workspaces: '5', status: 'Running', location: 'Boston' },
41
42
  { name: 'US-Node 6', threads: '5', apps: '20', workspaces: '15', status: 'Stopped', location: 'Raleigh' },
42
43
  { name: 'CZ-Node 1', threads: '12', apps: '48', workspaces: '13', status: 'Down', location: 'Brno' },
@@ -56,11 +57,32 @@ const columnNames = {
56
57
 
57
58
  /* eslint-disable patternfly-react/no-anonymous-functions */
58
59
  export const FilterSearchInput: React.FunctionComponent = () => {
59
- const isRepoSelectable = (repo: Repository) => repo.name !== 'a'; // Arbitrary logic for this example
60
- const selectableRepos = repositories.filter(isRepoSelectable);
60
+ // Set up repo filtering
61
+ const [searchValue, setSearchValue] = React.useState('');
62
+
63
+ const onSearchChange = (value: string) => {
64
+ setSearchValue(value);
65
+ };
66
+
67
+ const onFilter = (repo: Repository) => {
68
+ if (searchValue === '') {
69
+ return true;
70
+ }
61
71
 
72
+ let input: RegExp;
73
+ try {
74
+ input = new RegExp(searchValue, 'i');
75
+ } catch (err) {
76
+ input = new RegExp(searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
77
+ }
78
+ return repo.name.search(input) >= 0;
79
+ };
80
+ const filteredRepos = repositories.filter(onFilter);
81
+
82
+ // Set up table row selection
62
83
  // In this example, selected rows are tracked by the repo names from each row. This could be any unique identifier.
63
84
  // This is to prevent state from being based on row order index in case we later add sorting.
85
+ const isRepoSelectable = (repo: Repository) => repo.name !== 'a'; // Arbitrary logic for this example
64
86
  const [selectedRepoNames, setSelectedRepoNames] = React.useState<string[]>([]);
65
87
  const setRepoSelected = (repo: Repository, isSelecting = true) =>
66
88
  setSelectedRepoNames(prevSelected => {
@@ -68,8 +90,8 @@ export const FilterSearchInput: React.FunctionComponent = () => {
68
90
  return isSelecting && isRepoSelectable(repo) ? [...otherSelectedRepoNames, repo.name] : otherSelectedRepoNames;
69
91
  });
70
92
  const selectAllRepos = (isSelecting = true) =>
71
- setSelectedRepoNames(isSelecting ? selectableRepos.map(r => r.name) : []);
72
- const areAllReposSelected = selectedRepoNames.length === selectableRepos.length;
93
+ setSelectedRepoNames(isSelecting ? filteredRepos.map(r => r.name) : []); // Selecting all should only select all currently filtered rows
94
+ const areAllReposSelected = selectedRepoNames.length === filteredRepos.length && filteredRepos.length > 0;
73
95
  const areSomeReposSelected = selectedRepoNames.length > 0;
74
96
  const isRepoSelected = (repo: Repository) => selectedRepoNames.includes(repo.name);
75
97
 
@@ -113,21 +135,13 @@ export const FilterSearchInput: React.FunctionComponent = () => {
113
135
  };
114
136
  }, []);
115
137
 
116
- const bulkSelectMenuRef = React.createRef<HTMLDivElement>();
117
- const bulkSelectToggleRef = React.createRef<any>();
118
- const containerRef = React.createRef<HTMLDivElement>();
138
+ // Set up bulk selection menu
139
+ const bulkSelectMenuRef = React.useRef<HTMLDivElement>(null);
140
+ const bulkSelectToggleRef = React.useRef<any>(null);
141
+ const bulkSelectContainerRef = React.useRef<HTMLDivElement>(null);
119
142
 
120
143
  const [isBulkSelectOpen, setIsBulkSelectOpen] = React.useState<boolean>(false);
121
144
 
122
- React.useEffect(() => {
123
- window.addEventListener('keydown', handleBulkSelectMenuKeys);
124
- window.addEventListener('click', handleBulkSelectClickOutside);
125
- return () => {
126
- window.removeEventListener('keydown', handleBulkSelectMenuKeys);
127
- window.removeEventListener('click', handleBulkSelectClickOutside);
128
- };
129
- }, [isBulkSelectOpen, bulkSelectMenuRef]);
130
-
131
145
  const handleBulkSelectClickOutside = (event: MouseEvent) => {
132
146
  if (isBulkSelectOpen && !bulkSelectMenuRef.current?.contains(event.target as Node)) {
133
147
  setIsBulkSelectOpen(false);
@@ -144,11 +158,20 @@ export const FilterSearchInput: React.FunctionComponent = () => {
144
158
  ) {
145
159
  if (event.key === 'Escape' || event.key === 'Tab') {
146
160
  setIsBulkSelectOpen(!isBulkSelectOpen);
147
- bulkSelectToggleRef.current?.focus();
161
+ bulkSelectToggleRef.current?.querySelector('button').focus();
148
162
  }
149
163
  }
150
164
  };
151
165
 
166
+ React.useEffect(() => {
167
+ window.addEventListener('keydown', handleBulkSelectMenuKeys);
168
+ window.addEventListener('click', handleBulkSelectClickOutside);
169
+ return () => {
170
+ window.removeEventListener('keydown', handleBulkSelectMenuKeys);
171
+ window.removeEventListener('click', handleBulkSelectClickOutside);
172
+ };
173
+ }, [isBulkSelectOpen, bulkSelectMenuRef]);
174
+
152
175
  const onBulkSelectToggleClick = (ev: React.MouseEvent) => {
153
176
  ev.stopPropagation(); // Stop handleClickOutside from handling
154
177
  setTimeout(() => {
@@ -175,8 +198,8 @@ export const FilterSearchInput: React.FunctionComponent = () => {
175
198
  splitButtonOptions={{
176
199
  items: [
177
200
  <MenuToggleCheckbox
178
- id="select-checkbox"
179
- key="select-checkbox"
201
+ id="search-input-bulk-select"
202
+ key="search-input-bulk-select"
180
203
  aria-label="Select all"
181
204
  isChecked={menuToggleCheckmark}
182
205
  onChange={(checked, _event) => selectAllRepos(checked)}
@@ -188,12 +211,13 @@ export const FilterSearchInput: React.FunctionComponent = () => {
188
211
  );
189
212
 
190
213
  const bulkSelectMenu = (
191
- // eslint-disable-next-line no-console
192
214
  <Menu
215
+ id="search-input-bulk-select"
193
216
  ref={bulkSelectMenuRef}
194
217
  onSelect={(_ev, itemId) => {
195
218
  selectAllRepos(itemId === 1 || itemId === 2);
196
219
  setIsBulkSelectOpen(!isBulkSelectOpen);
220
+ bulkSelectToggleRef.current?.querySelector('button').focus();
197
221
  }}
198
222
  >
199
223
  <MenuContent>
@@ -207,37 +231,17 @@ export const FilterSearchInput: React.FunctionComponent = () => {
207
231
  );
208
232
 
209
233
  const toolbarBulkSelect = (
210
- <div ref={containerRef}>
234
+ <div ref={bulkSelectContainerRef}>
211
235
  <Popper
212
236
  trigger={bulkSelectToggle}
213
237
  popper={bulkSelectMenu}
214
- appendTo={containerRef.current || undefined}
238
+ appendTo={bulkSelectContainerRef.current || undefined}
215
239
  isVisible={isBulkSelectOpen}
216
240
  popperMatchesTriggerWidth={false}
217
241
  />
218
242
  </div>
219
243
  );
220
244
 
221
- const [searchValue, setSearchValue] = React.useState('');
222
-
223
- const onSearchChange = (value: string) => {
224
- setSearchValue(value);
225
- };
226
-
227
- const onFilter = (repo: Repository) => {
228
- if (searchValue === '') {
229
- return true;
230
- }
231
-
232
- let input: RegExp;
233
- try {
234
- input = new RegExp(searchValue, 'i');
235
- } catch (err) {
236
- input = new RegExp(searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
237
- }
238
- return repo.name.search(input) >= 0;
239
- };
240
-
241
245
  const searchInput = (
242
246
  <SearchInput
243
247
  placeholder="Filter by server name"
@@ -269,25 +273,6 @@ export const FilterSearchInput: React.FunctionComponent = () => {
269
273
  </Toolbar>
270
274
  );
271
275
 
272
- const filteredRepos = repositories.filter(onFilter).map((repo, rowIndex) => (
273
- <Tr key={repo.name}>
274
- <Td
275
- select={{
276
- rowIndex,
277
- onSelect: (_event, isSelecting) => onSelectRepo(repo, rowIndex, isSelecting),
278
- isSelected: isRepoSelected(repo),
279
- disable: !isRepoSelectable(repo)
280
- }}
281
- />
282
- <Td dataLabel={columnNames.name}>{repo.name}</Td>
283
- <Td dataLabel={columnNames.threads}>{repo.threads}</Td>
284
- <Td dataLabel={columnNames.apps}>{repo.apps}</Td>
285
- <Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
286
- <Td dataLabel={columnNames.status}>{repo.status}</Td>
287
- <Td dataLabel={columnNames.location}>{repo.location}</Td>
288
- </Tr>
289
- ));
290
-
291
276
  const emptyState = (
292
277
  <EmptyState>
293
278
  <EmptyStateIcon icon={SearchIcon} />
@@ -316,16 +301,54 @@ export const FilterSearchInput: React.FunctionComponent = () => {
316
301
  <Tr>
317
302
  <Th />
318
303
  <Th width={20}>{columnNames.name}</Th>
319
- <Th width={20}>{columnNames.threads}</Th>
320
- <Th width={20}>{columnNames.apps}</Th>
321
- <Th width={20}>{columnNames.workspaces}</Th>
304
+ <Th width={10}>{columnNames.threads}</Th>
305
+ <Th width={10}>{columnNames.apps}</Th>
306
+ <Th width={10}>{columnNames.workspaces}</Th>
322
307
  <Th width={20}>{columnNames.status}</Th>
323
308
  <Th width={20}>{columnNames.location}</Th>
324
309
  </Tr>
325
310
  </Thead>
326
- <Tbody>{filteredRepos.length > 0 && filteredRepos}</Tbody>
311
+ <Tbody>
312
+ {filteredRepos.length > 0 &&
313
+ filteredRepos.map((repo, rowIndex) => (
314
+ <Tr key={repo.name}>
315
+ <Td
316
+ select={{
317
+ rowIndex,
318
+ onSelect: (_event, isSelecting) => onSelectRepo(repo, rowIndex, isSelecting),
319
+ isSelected: isRepoSelected(repo),
320
+ disable: !isRepoSelectable(repo)
321
+ }}
322
+ />
323
+ <Td dataLabel={columnNames.name} modifier="truncate">
324
+ {repo.name}
325
+ </Td>
326
+ <Td dataLabel={columnNames.threads} modifier="truncate">
327
+ {repo.threads}
328
+ </Td>
329
+ <Td dataLabel={columnNames.apps} modifier="truncate">
330
+ {repo.apps}
331
+ </Td>
332
+ <Td dataLabel={columnNames.workspaces} modifier="truncate">
333
+ {repo.workspaces}
334
+ </Td>
335
+ <Td dataLabel={columnNames.status} modifier="truncate">
336
+ {repo.status}
337
+ </Td>
338
+ <Td dataLabel={columnNames.location} modifier="truncate">
339
+ {repo.location}
340
+ </Td>
341
+ </Tr>
342
+ ))}
343
+ {filteredRepos.length === 0 && (
344
+ <Tr>
345
+ <Td colSpan={8}>
346
+ <Bullseye>{emptyState}</Bullseye>
347
+ </Td>
348
+ </Tr>
349
+ )}
350
+ </Tbody>
327
351
  </TableComposable>
328
- {filteredRepos.length === 0 && emptyState}
329
352
  </React.Fragment>
330
353
  );
331
354
  };
@@ -29,7 +29,7 @@ const repositories: Repository[] = [
29
29
  { name: 'US-Node 1', threads: '5', apps: '25', workspaces: '5', status: 'Stopped', location: 'Raleigh' },
30
30
  { name: 'US-Node 2', threads: '5', apps: '30', workspaces: '2', status: 'Down', location: 'Westford' },
31
31
  { name: 'US-Node 3', threads: '13', apps: '35', workspaces: '12', status: 'Degraded', location: 'Boston' },
32
- { name: 'US-Node 4', threads: '2', apps: '5', workspaces: '18', status: 'Needs Maintainence', location: 'Raleigh' },
32
+ { name: 'US-Node 4', threads: '2', apps: '5', workspaces: '18', status: 'Needs Maintenance', location: 'Raleigh' },
33
33
  { name: 'US-Node 5', threads: '7', apps: '30', workspaces: '5', status: 'Running', location: 'Boston' },
34
34
  { name: 'US-Node 6', threads: '5', apps: '20', workspaces: '15', status: 'Stopped', location: 'Raleigh' },
35
35
  { name: 'CZ-Node 1', threads: '12', apps: '48', workspaces: '13', status: 'Down', location: 'Brno' },
@@ -49,12 +49,28 @@ const columnNames = {
49
49
 
50
50
  /* eslint-disable patternfly-react/no-anonymous-functions */
51
51
  export const FilterSingleSelect: React.FunctionComponent = () => {
52
- // Set up table selection
53
- const isRepoSelectable = (repo: Repository) => repo.name !== 'a'; // Arbitrary logic for this example
54
- const selectableRepos = repositories.filter(isRepoSelectable);
52
+ // Set up repo filtering
53
+ const [searchValue, setSearchValue] = React.useState('');
54
+ const onFilter = (repo: Repository) => {
55
+ if (searchValue === 'all') {
56
+ return true;
57
+ }
55
58
 
59
+ let input: RegExp;
60
+ try {
61
+ input = new RegExp(searchValue, 'i');
62
+ } catch (err) {
63
+ input = new RegExp(searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
64
+ }
65
+ return repo.status.search(input) >= 0;
66
+ };
67
+
68
+ const filteredRepos = repositories.filter(onFilter);
69
+
70
+ // Set up table selection
56
71
  // In this example, selected rows are tracked by the repo names from each row. This could be any unique identifier.
57
72
  // This is to prevent state from being based on row order index in case we later add sorting.
73
+ const isRepoSelectable = (repo: Repository) => repo.name !== 'a'; // Arbitrary logic for this example
58
74
  const [selectedRepoNames, setSelectedRepoNames] = React.useState<string[]>([]);
59
75
  const setRepoSelected = (repo: Repository, isSelecting = true) =>
60
76
  setSelectedRepoNames(prevSelected => {
@@ -62,8 +78,8 @@ export const FilterSingleSelect: React.FunctionComponent = () => {
62
78
  return isSelecting && isRepoSelectable(repo) ? [...otherSelectedRepoNames, repo.name] : otherSelectedRepoNames;
63
79
  });
64
80
  const selectAllRepos = (isSelecting = true) =>
65
- setSelectedRepoNames(isSelecting ? selectableRepos.map(r => r.name) : []);
66
- const areAllReposSelected = selectedRepoNames.length === selectableRepos.length;
81
+ setSelectedRepoNames(isSelecting ? filteredRepos.map(r => r.name) : []);
82
+ const areAllReposSelected = selectedRepoNames.length === filteredRepos.length && filteredRepos.length > 0;
67
83
  const areSomeReposSelected = selectedRepoNames.length > 0;
68
84
  const isRepoSelected = (repo: Repository) => selectedRepoNames.includes(repo.name);
69
85
 
@@ -108,21 +124,12 @@ export const FilterSingleSelect: React.FunctionComponent = () => {
108
124
  }, []);
109
125
 
110
126
  // Set up bulk selection menu
111
- const bulkSelectMenuRef = React.createRef<HTMLDivElement>();
112
- const bulkSelectToggleRef = React.createRef<any>();
113
- const bulkSelectcontainerRef = React.createRef<HTMLDivElement>();
127
+ const bulkSelectMenuRef = React.useRef<HTMLDivElement>(null);
128
+ const bulkSelectToggleRef = React.useRef<any>(null);
129
+ const bulkSelectContainerRef = React.useRef<HTMLDivElement>(null);
114
130
 
115
131
  const [isBulkSelectOpen, setIsBulkSelectOpen] = React.useState<boolean>(false);
116
132
 
117
- React.useEffect(() => {
118
- window.addEventListener('keydown', handleBulkSelectMenuKeys);
119
- window.addEventListener('click', handleBulkSelectClickOutside);
120
- return () => {
121
- window.removeEventListener('keydown', handleBulkSelectMenuKeys);
122
- window.removeEventListener('click', handleBulkSelectClickOutside);
123
- };
124
- }, [isBulkSelectOpen, bulkSelectMenuRef]);
125
-
126
133
  const handleBulkSelectClickOutside = (event: MouseEvent) => {
127
134
  if (isBulkSelectOpen && !bulkSelectMenuRef.current?.contains(event.target as Node)) {
128
135
  setIsBulkSelectOpen(false);
@@ -139,11 +146,20 @@ export const FilterSingleSelect: React.FunctionComponent = () => {
139
146
  ) {
140
147
  if (event.key === 'Escape' || event.key === 'Tab') {
141
148
  setIsBulkSelectOpen(!isBulkSelectOpen);
142
- bulkSelectToggleRef.current?.focus();
149
+ bulkSelectToggleRef.current?.querySelector('button').focus();
143
150
  }
144
151
  }
145
152
  };
146
153
 
154
+ React.useEffect(() => {
155
+ window.addEventListener('keydown', handleBulkSelectMenuKeys);
156
+ window.addEventListener('click', handleBulkSelectClickOutside);
157
+ return () => {
158
+ window.removeEventListener('keydown', handleBulkSelectMenuKeys);
159
+ window.removeEventListener('click', handleBulkSelectClickOutside);
160
+ };
161
+ }, [isBulkSelectOpen, bulkSelectMenuRef]);
162
+
147
163
  const onBulkSelectToggleClick = (ev: React.MouseEvent) => {
148
164
  ev.stopPropagation(); // Stop handleClickOutside from handling
149
165
  setTimeout(() => {
@@ -170,8 +186,8 @@ export const FilterSingleSelect: React.FunctionComponent = () => {
170
186
  splitButtonOptions={{
171
187
  items: [
172
188
  <MenuToggleCheckbox
173
- id="select-checkbox"
174
- key="select-checkbox"
189
+ id="single-bulk-select"
190
+ key="single-bulk-select"
175
191
  aria-label="Select all"
176
192
  isChecked={menuToggleCheckmark}
177
193
  onChange={(checked, _event) => selectAllRepos(checked)}
@@ -183,12 +199,12 @@ export const FilterSingleSelect: React.FunctionComponent = () => {
183
199
  );
184
200
 
185
201
  const bulkSelectMenu = (
186
- // eslint-disable-next-line no-console
187
202
  <Menu
188
203
  ref={bulkSelectMenuRef}
189
204
  onSelect={(_ev, itemId) => {
190
205
  selectAllRepos(itemId === 1 || itemId === 2);
191
206
  setIsBulkSelectOpen(!isBulkSelectOpen);
207
+ bulkSelectToggleRef.current?.querySelector('button').focus();
192
208
  }}
193
209
  >
194
210
  <MenuContent>
@@ -202,34 +218,17 @@ export const FilterSingleSelect: React.FunctionComponent = () => {
202
218
  );
203
219
 
204
220
  const toolbarBulkSelect = (
205
- <div ref={bulkSelectcontainerRef}>
221
+ <div ref={bulkSelectContainerRef}>
206
222
  <Popper
207
223
  trigger={bulkSelectToggle}
208
224
  popper={bulkSelectMenu}
209
- appendTo={bulkSelectcontainerRef.current || undefined}
225
+ appendTo={bulkSelectContainerRef.current || undefined}
210
226
  isVisible={isBulkSelectOpen}
211
227
  popperMatchesTriggerWidth={false}
212
228
  />
213
229
  </div>
214
230
  );
215
231
 
216
- // Set up table filtering
217
- const [searchValue, setSearchValue] = React.useState('');
218
-
219
- const onFilter = (repo: Repository) => {
220
- if (searchValue === 'all') {
221
- return true;
222
- }
223
-
224
- let input: RegExp;
225
- try {
226
- input = new RegExp(searchValue, 'i');
227
- } catch (err) {
228
- input = new RegExp(searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
229
- }
230
- return repo.status.search(input) >= 0;
231
- };
232
-
233
232
  // Set up single select menu & state
234
233
  const [isOpen, setIsOpen] = React.useState<boolean>(false);
235
234
  const [menuSelection, setMenuSelection] = React.useState<string>('all');
@@ -308,7 +307,7 @@ export const FilterSingleSelect: React.FunctionComponent = () => {
308
307
  );
309
308
 
310
309
  const menu = (
311
- <Menu ref={menuRef} id="select-menu" onSelect={onSelect} selected={menuSelection}>
310
+ <Menu ref={menuRef} id="single-select-menu" onSelect={onSelect} selected={menuSelection}>
312
311
  <MenuContent>
313
312
  <MenuList>
314
313
  <MenuItem itemId="all">All statuses</MenuItem>
@@ -359,15 +358,15 @@ export const FilterSingleSelect: React.FunctionComponent = () => {
359
358
  <Tr>
360
359
  <Th />
361
360
  <Th width={20}>{columnNames.name}</Th>
362
- <Th width={20}>{columnNames.threads}</Th>
363
- <Th width={20}>{columnNames.apps}</Th>
364
- <Th width={20}>{columnNames.workspaces}</Th>
361
+ <Th width={10}>{columnNames.threads}</Th>
362
+ <Th width={10}>{columnNames.apps}</Th>
363
+ <Th width={10}>{columnNames.workspaces}</Th>
365
364
  <Th width={20}>{columnNames.status}</Th>
366
365
  <Th width={20}>{columnNames.location}</Th>
367
366
  </Tr>
368
367
  </Thead>
369
368
  <Tbody>
370
- {repositories.filter(onFilter).map((repo, rowIndex) => (
369
+ {filteredRepos.map((repo, rowIndex) => (
371
370
  <Tr key={repo.name}>
372
371
  <Td
373
372
  select={{
@@ -377,12 +376,24 @@ export const FilterSingleSelect: React.FunctionComponent = () => {
377
376
  disable: !isRepoSelectable(repo)
378
377
  }}
379
378
  />
380
- <Td dataLabel={columnNames.name}>{repo.name}</Td>
381
- <Td dataLabel={columnNames.threads}>{repo.threads}</Td>
382
- <Td dataLabel={columnNames.apps}>{repo.apps}</Td>
383
- <Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
384
- <Td dataLabel={columnNames.status}>{repo.status}</Td>
385
- <Td dataLabel={columnNames.location}>{repo.location}</Td>
379
+ <Td dataLabel={columnNames.name} modifier="truncate">
380
+ {repo.name}
381
+ </Td>
382
+ <Td dataLabel={columnNames.threads} modifier="truncate">
383
+ {repo.threads}
384
+ </Td>
385
+ <Td dataLabel={columnNames.apps} modifier="truncate">
386
+ {repo.apps}
387
+ </Td>
388
+ <Td dataLabel={columnNames.workspaces} modifier="truncate">
389
+ {repo.workspaces}
390
+ </Td>
391
+ <Td dataLabel={columnNames.status} modifier="truncate">
392
+ {repo.status}
393
+ </Td>
394
+ <Td dataLabel={columnNames.location} modifier="truncate">
395
+ {repo.location}
396
+ </Td>
386
397
  </Tr>
387
398
  ))}
388
399
  </Tbody>