1 | ---
|
2 | id: Card view
|
3 | section: demos
|
4 | ---
|
5 |
|
6 | import DashboardWrapper from '../examples/DashboardWrapper';
|
7 |
|
8 | import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon';
|
9 | import TrashIcon from '@patternfly/react-icons/dist/esm/icons/trash-icon';
|
10 | import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon';
|
11 | import pfIcon from './pf-logo-small.svg';
|
12 | import activeMQIcon from './activemq-core_200x150.png';
|
13 | import avroIcon from './camel-avro_200x150.png';
|
14 | import dropBoxIcon from './camel-dropbox_200x150.png';
|
15 | import infinispanIcon from './camel-infinispan_200x150.png';
|
16 | import saxonIcon from './camel-saxon_200x150.png';
|
17 | import sparkIcon from './camel-spark_200x150.png';
|
18 | import swaggerIcon from './camel-swagger-java_200x150.png';
|
19 | import azureIcon from './FuseConnector_Icons_AzureServices.png';
|
20 | import restIcon from './FuseConnector_Icons_REST.png';
|
21 |
|
22 | ## Demos
|
23 |
|
24 | This demonstrates how you can assemble a full page view that contains a grid of equal sized cards that includes a toolbar for managing card grid contents.
|
25 |
|
26 | ### Card view
|
27 |
|
28 | ```js isFullscreen
|
29 | import React from 'react';
|
30 | import {
|
31 | Bullseye,
|
32 | Button,
|
33 | Card,
|
34 | CardHeader,
|
35 | CardActions,
|
36 | CardTitle,
|
37 | CardBody,
|
38 | Checkbox,
|
39 | Dropdown,
|
40 | DropdownToggle,
|
41 | DropdownItem,
|
42 | DropdownSeparator,
|
43 | DropdownPosition,
|
44 | DropdownToggleCheckbox,
|
45 | EmptyState,
|
46 | EmptyStateIcon,
|
47 | EmptyStateVariant,
|
48 | EmptyStateSecondaryActions,
|
49 | Gallery,
|
50 | KebabToggle,
|
51 | OverflowMenu,
|
52 | OverflowMenuControl,
|
53 | OverflowMenuDropdownItem,
|
54 | OverflowMenuItem,
|
55 | PageSection,
|
56 | PageSectionVariants,
|
57 | Pagination,
|
58 | Select,
|
59 | SelectOption,
|
60 | SelectVariant,
|
61 | TextContent,
|
62 | Text,
|
63 | Title,
|
64 | Toolbar,
|
65 | ToolbarItem,
|
66 | ToolbarFilter,
|
67 | ToolbarContent
|
68 | } from '@patternfly/react-core';
|
69 | import DashboardWrapper from '../examples/DashboardWrapper';
|
70 |
|
71 | import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon';
|
72 | import TrashIcon from '@patternfly/react-icons/dist/esm/icons/trash-icon';
|
73 | import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon';
|
74 | import pfIcon from './pf-logo-small.svg';
|
75 | import activeMQIcon from './activemq-core_200x150.png';
|
76 | import avroIcon from './camel-avro_200x150.png';
|
77 | import dropBoxIcon from './camel-dropbox_200x150.png';
|
78 | import infinispanIcon from './camel-infinispan_200x150.png';
|
79 | import saxonIcon from './camel-saxon_200x150.png';
|
80 | import sparkIcon from './camel-spark_200x150.png';
|
81 | import swaggerIcon from './camel-swagger-java_200x150.png';
|
82 | import azureIcon from './FuseConnector_Icons_AzureServices.png';
|
83 | import restIcon from './FuseConnector_Icons_REST.png';
|
84 |
|
85 | class CardViewBasic extends React.Component {
|
86 | constructor(props) {
|
87 | super(props);
|
88 |
|
89 | this.state = {
|
90 | filters: {
|
91 | products: []
|
92 | },
|
93 | res: [],
|
94 | isChecked: false,
|
95 | selectedItems: [],
|
96 | areAllSelected: false,
|
97 | isUpperToolbarDropdownOpen: false,
|
98 | isUpperToolbarKebabDropdownOpen: false,
|
99 | isLowerToolbarDropdownOpen: false,
|
100 | isLowerToolbarKebabDropdownOpen: false,
|
101 | isCardKebabDropdownOpen: false,
|
102 | activeItem: 0,
|
103 | splitButtonDropdownIsOpen: false,
|
104 | page: 1,
|
105 | perPage: 10,
|
106 | totalItemCount: 10
|
107 | };
|
108 |
|
109 | this.onToolbarDropdownToggle = isLowerToolbarDropdownOpen => {
|
110 | this.setState(prevState => ({
|
111 | isLowerToolbarDropdownOpen
|
112 | }));
|
113 | };
|
114 |
|
115 | this.onToolbarKebabDropdownToggle = isLowerToolbarKebabDropdownOpen => {
|
116 | this.setState({
|
117 | isLowerToolbarKebabDropdownOpen
|
118 | });
|
119 | };
|
120 |
|
121 | this.onToolbarKebabDropdownSelect = event => {
|
122 | this.setState({
|
123 | isLowerToolbarKebabDropdownOpen: !this.state.isLowerToolbarKebabDropdownOpen
|
124 | });
|
125 | };
|
126 |
|
127 | this.onCardKebabDropdownToggle = (key, isCardKebabDropdownOpen) => {
|
128 | this.setState({
|
129 | [key]: isCardKebabDropdownOpen
|
130 | });
|
131 | };
|
132 |
|
133 | this.onCardKebabDropdownSelect = (key, event) => {
|
134 | this.setState({
|
135 | [key]: !this.state[key]
|
136 | });
|
137 | };
|
138 |
|
139 | this.deleteItem = item => event => {
|
140 | const filter = getter => val => getter(val) !== item.id;
|
141 | this.setState({
|
142 | res: this.state.res.filter(filter(({ id }) => id)),
|
143 | selectedItems: this.state.selectedItems.filter(filter(id => id))
|
144 | });
|
145 | };
|
146 |
|
147 | this.onSetPage = (_event, pageNumber) => {
|
148 | this.setState({
|
149 | page: pageNumber
|
150 | });
|
151 | };
|
152 |
|
153 | this.onPerPageSelect = (_event, perPage) => {
|
154 | this.setState({
|
155 | perPage
|
156 | });
|
157 | };
|
158 |
|
159 | this.onSplitButtonToggle = isOpen => {
|
160 | this.setState({
|
161 | splitButtonDropdownIsOpen: isOpen
|
162 | });
|
163 | };
|
164 |
|
165 | this.onSplitButtonSelect = event => {
|
166 | this.setState((prevState, props) => {
|
167 | return { splitButtonDropdownIsOpen: !prevState.splitButtonDropdownIsOpen };
|
168 | });
|
169 | };
|
170 |
|
171 | this.onNameSelect = (event, selection) => {
|
172 | const checked = event.target.checked;
|
173 | this.setState(prevState => {
|
174 | const prevSelections = prevState.filters['products'];
|
175 | return {
|
176 | filters: {
|
177 | ...prevState.filters,
|
178 | ['products']: checked ? [...prevSelections, selection] : prevSelections.filter(value => value !== selection)
|
179 | }
|
180 | };
|
181 | });
|
182 | };
|
183 |
|
184 | this.onDelete = (type = '', id = '') => {
|
185 | if (type) {
|
186 | this.setState(prevState => {
|
187 | prevState.filters[type.toLowerCase()] = prevState.filters[type.toLowerCase()].filter(s => s !== id);
|
188 | return {
|
189 | filters: prevState.filters
|
190 | };
|
191 | });
|
192 | } else {
|
193 | this.setState({
|
194 | filters: {
|
195 | products: []
|
196 | }
|
197 | });
|
198 | }
|
199 | };
|
200 |
|
201 | this.onKeyDown = (event, productId) => {
|
202 | console.log(productId);
|
203 | if (event.target !== event.currentTarget) {
|
204 | return;
|
205 | }
|
206 | if ([' ', 'Enter'].includes(event.key)) {
|
207 | event.preventDefault();
|
208 | this.setState(prevState => {
|
209 | return prevState.selectedItems.includes(productId * 1)
|
210 | ? {
|
211 | selectedItems: [...prevState.selectedItems.filter(id => productId * 1 != id)],
|
212 | areAllSelected: false
|
213 | }
|
214 | : {
|
215 | selectedItems: [...prevState.selectedItems, productId * 1],
|
216 | areAllSelected: prevState.totalItemCount === prevState.selectedItems.length + 1
|
217 | };
|
218 | });
|
219 | }
|
220 | };
|
221 |
|
222 | this.onClick = productId => {
|
223 | this.setState(prevState => {
|
224 | return prevState.selectedItems.includes(productId * 1)
|
225 | ? {
|
226 | selectedItems: [...prevState.selectedItems.filter(id => productId * 1 != id)],
|
227 | areAllSelected: false
|
228 | }
|
229 | : {
|
230 | selectedItems: [...prevState.selectedItems, productId * 1],
|
231 | areAllSelected: prevState.totalItemCount === prevState.selectedItems.length + 1
|
232 | };
|
233 | });
|
234 | };
|
235 | }
|
236 |
|
237 | selectedItems(e) {
|
238 | const { value, checked } = e.target;
|
239 | let { selectedItems } = this.state;
|
240 |
|
241 | if (checked) {
|
242 | selectedItems = [...selectedItems, value];
|
243 | } else {
|
244 | selectedItems = selectedItems.filter(el => el !== value);
|
245 | if (this.state.areAllSelected) {
|
246 | this.setState({
|
247 | areAllSelected: !this.state.areAllSelected
|
248 | });
|
249 | }
|
250 | }
|
251 | this.setState({ selectedItems });
|
252 | }
|
253 |
|
254 | splitCheckboxSelectAll(e) {
|
255 | const { checked } = e.target;
|
256 | const { isChecked, res } = this.state;
|
257 | let collection = [];
|
258 |
|
259 | if (checked) {
|
260 | for (var i = 0; i <= 9; i++) collection = [...collection, i];
|
261 | }
|
262 |
|
263 | this.setState(
|
264 | {
|
265 | selectedItems: collection,
|
266 | isChecked: isChecked,
|
267 | areAllSelected: checked
|
268 | },
|
269 | this.updateSelected
|
270 | );
|
271 | }
|
272 |
|
273 | selectPage(e) {
|
274 | const { checked } = e.target;
|
275 | const { isChecked, totalItemCount, perPage } = this.state;
|
276 | let collection = [];
|
277 |
|
278 | collection = this.getAllItems();
|
279 |
|
280 | this.setState(
|
281 | {
|
282 | selectedItems: collection,
|
283 | isChecked: checked,
|
284 | areAllSelected: totalItemCount === perPage ? true : false
|
285 | },
|
286 | this.updateSelected
|
287 | );
|
288 | }
|
289 |
|
290 | selectAll(e) {
|
291 | const { checked } = e.target;
|
292 | const { isChecked } = this.state;
|
293 |
|
294 | let collection = [];
|
295 | for (var i = 0; i <= 9; i++) collection = [...collection, i];
|
296 |
|
297 | this.setState(
|
298 | {
|
299 | selectedItems: collection,
|
300 | isChecked: true,
|
301 | areAllSelected: true
|
302 | },
|
303 | this.updateSelected
|
304 | );
|
305 | }
|
306 |
|
307 | selectNone(e) {
|
308 | const { checked } = e.target;
|
309 | const { isChecked, selectedItems } = this.state;
|
310 | this.setState(
|
311 | {
|
312 | selectedItems: [],
|
313 | isChecked: false,
|
314 | areAllSelected: false
|
315 | },
|
316 | this.updateSelected
|
317 | );
|
318 | }
|
319 |
|
320 | getAllItems() {
|
321 | const { res } = this.state;
|
322 | const collection = [];
|
323 | for (const items of res) {
|
324 | collection.push(items.id);
|
325 | }
|
326 |
|
327 | return collection;
|
328 | }
|
329 |
|
330 | updateSelected() {
|
331 | const { res, selectedItems } = this.state;
|
332 | let rows = res.map(post => {
|
333 | post.selected = selectedItems.includes(post.id);
|
334 | return post;
|
335 | });
|
336 |
|
337 | this.setState({
|
338 | res: rows
|
339 | });
|
340 | }
|
341 |
|
342 | fetch(page, perPage) {
|
343 | fetch(`https://my-json-server.typicode.com/jenny-s51/cardviewdata/posts?_page=${page}&_limit=${perPage}`)
|
344 | .then(resp => resp.json())
|
345 | .then(resp => this.setState({ res: resp, perPage, page }))
|
346 | .then(() => this.updateSelected())
|
347 | .catch(err => this.setState({ error: err }));
|
348 | }
|
349 |
|
350 | componentDidMount() {
|
351 | this.fetch(this.state.page, this.state.perPage);
|
352 | }
|
353 |
|
354 | renderPagination() {
|
355 | const { page, perPage, totalItemCount } = this.state;
|
356 |
|
357 | const defaultPerPageOptions = [
|
358 | {
|
359 | title: '1',
|
360 | value: 1
|
361 | },
|
362 | {
|
363 | title: '5',
|
364 | value: 5
|
365 | },
|
366 | {
|
367 | title: '10',
|
368 | value: 10
|
369 | }
|
370 | ];
|
371 |
|
372 | return (
|
373 | <Pagination
|
374 | itemCount={totalItemCount}
|
375 | page={page}
|
376 | perPage={perPage}
|
377 | perPageOptions={defaultPerPageOptions}
|
378 | onSetPage={(_evt, value) => {
|
379 | this.fetch(value, perPage);
|
380 | }}
|
381 | onPerPageSelect={(_evt, value) => {
|
382 | this.fetch(1, value);
|
383 | }}
|
384 | variant="top"
|
385 | isCompact
|
386 | />
|
387 | );
|
388 | }
|
389 |
|
390 | buildSelectDropdown() {
|
391 | const { splitButtonDropdownIsOpen, selectedItems, areAllSelected } = this.state;
|
392 | const numSelected = selectedItems.length;
|
393 | const allSelected = areAllSelected;
|
394 | const anySelected = numSelected > 0;
|
395 | const someChecked = anySelected ? null : false;
|
396 | const isChecked = allSelected ? true : someChecked;
|
397 | const splitButtonDropdownItems = [
|
398 | <DropdownItem key="item-1" onClick={this.selectNone.bind(this)}>
|
399 | Select none (0 items)
|
400 | </DropdownItem>,
|
401 | <DropdownItem key="item-2" onClick={this.selectPage.bind(this)}>
|
402 | Select page ({this.state.perPage} items)
|
403 | </DropdownItem>,
|
404 | <DropdownItem key="item-3" onClick={this.selectAll.bind(this)}>
|
405 | Select all ({this.state.totalItemCount} items)
|
406 | </DropdownItem>
|
407 | ];
|
408 |
|
409 | return (
|
410 | <Dropdown
|
411 | position={DropdownPosition.left}
|
412 | onSelect={this.onSplitButtonSelect}
|
413 | toggle={
|
414 | <DropdownToggle
|
415 | splitButtonItems={[
|
416 | <DropdownToggleCheckbox
|
417 | id="example-checkbox-2"
|
418 | key="split-checkbox"
|
419 | aria-label={anySelected ? 'Deselect all' : 'Select all'}
|
420 | isChecked={areAllSelected}
|
421 | onClick={this.splitCheckboxSelectAll.bind(this)}
|
422 | ></DropdownToggleCheckbox>
|
423 | ]}
|
424 | onToggle={this.onSplitButtonToggle}
|
425 | >
|
426 | {numSelected !== 0 && <React.Fragment>{numSelected} selected</React.Fragment>}
|
427 | </DropdownToggle>
|
428 | }
|
429 | isOpen={splitButtonDropdownIsOpen}
|
430 | dropdownItems={splitButtonDropdownItems}
|
431 | />
|
432 | );
|
433 | }
|
434 |
|
435 | buildFilterDropdown() {
|
436 | const { isLowerToolbarDropdownOpen, filters } = this.state;
|
437 |
|
438 | const filterDropdownItems = [
|
439 | <SelectOption key="patternfly" value="PatternFly" />,
|
440 | <SelectOption key="activemq" value="ActiveMQ" />,
|
441 | <SelectOption key="apachespark" value="Apache Spark" />,
|
442 | <SelectOption key="avro" value="Avro" />,
|
443 | <SelectOption key="azureservices" value="Azure Services" />,
|
444 | <SelectOption key="crypto" value="Crypto" />,
|
445 | <SelectOption key="dropbox" value="DropBox" />,
|
446 | <SelectOption key="jbossdatagrid" value="JBoss Data Grid" />,
|
447 | <SelectOption key="rest" value="REST" />,
|
448 | <SelectOption key="swagger" value="SWAGGER" />
|
449 | ];
|
450 |
|
451 | return (
|
452 | <ToolbarFilter categoryName="Products" chips={filters.products} deleteChip={this.onDelete}>
|
453 | <Select
|
454 | variant={SelectVariant.checkbox}
|
455 | aria-label="Products"
|
456 | onToggle={this.onToolbarDropdownToggle}
|
457 | onSelect={this.onNameSelect}
|
458 | selections={filters.products}
|
459 | isExpanded={isLowerToolbarDropdownOpen}
|
460 | placeholderText="Creator"
|
461 | >
|
462 | {filterDropdownItems}
|
463 | </Select>
|
464 | </ToolbarFilter>
|
465 | );
|
466 | }
|
467 |
|
468 | render() {
|
469 | const {
|
470 | isUpperToolbarDropdownOpen,
|
471 | isLowerToolbarDropdownOpen,
|
472 | isUpperToolbarKebabDropdownOpen,
|
473 | isLowerToolbarKebabDropdownOpen,
|
474 | isCardKebabDropdownOpen,
|
475 | splitButtonDropdownIsOpen,
|
476 | activeItem,
|
477 | filters,
|
478 | res,
|
479 | checked,
|
480 | selectedItems,
|
481 | areAllSelected,
|
482 | isChecked,
|
483 | page,
|
484 | perPage
|
485 | } = this.state;
|
486 |
|
487 | const toolbarKebabDropdownItems = [
|
488 | <OverflowMenuDropdownItem key="link">Link</OverflowMenuDropdownItem>,
|
489 | <OverflowMenuDropdownItem key="action" component="button">
|
490 | Action
|
491 | </OverflowMenuDropdownItem>,
|
492 | <OverflowMenuDropdownItem key="disabled link" isDisabled>
|
493 | Disabled Link
|
494 | </OverflowMenuDropdownItem>,
|
495 | <OverflowMenuDropdownItem key="disabled action" isDisabled component="button">
|
496 | Disabled Action
|
497 | </OverflowMenuDropdownItem>,
|
498 | <DropdownSeparator key="separator" />,
|
499 | <OverflowMenuDropdownItem key="separated link">Separated Link</OverflowMenuDropdownItem>,
|
500 | <OverflowMenuDropdownItem key="separated action" component="button">
|
501 | Separated Action
|
502 | </OverflowMenuDropdownItem>
|
503 | ];
|
504 |
|
505 | const toolbarItems = (
|
506 | <React.Fragment>
|
507 | <ToolbarItem variant="bulk-select">{this.buildSelectDropdown()}</ToolbarItem>
|
508 | <ToolbarItem breakpoint="xl">{this.buildFilterDropdown()}</ToolbarItem>
|
509 | <ToolbarItem variant="overflow-menu">
|
510 | <OverflowMenu breakpoint="md">
|
511 | <OverflowMenuItem>
|
512 | <Button variant="primary">Create a project</Button>
|
513 | </OverflowMenuItem>
|
514 | <OverflowMenuControl hasAdditionalOptions>
|
515 | <Dropdown
|
516 | onSelect={this.onToolbarKebabDropdownSelect}
|
517 | toggle={<KebabToggle onToggle={this.onToolbarKebabDropdownToggle} id="toggle-id-6" />}
|
518 | isOpen={isLowerToolbarKebabDropdownOpen}
|
519 | isPlain
|
520 | dropdownItems={toolbarKebabDropdownItems}
|
521 | />
|
522 | </OverflowMenuControl>
|
523 | </OverflowMenu>
|
524 | </ToolbarItem>
|
525 | <ToolbarItem variant="pagination" alignment={{ default: 'alignRight' }}>
|
526 | {this.renderPagination()}
|
527 | </ToolbarItem>
|
528 | </React.Fragment>
|
529 | );
|
530 |
|
531 | const filtered =
|
532 | filters.products.length > 0
|
533 | ? res.filter(card => {
|
534 | return filters.products.length === 0 || filters.products.includes(card.name);
|
535 | })
|
536 | : res;
|
537 |
|
538 | const icons = {
|
539 | pfIcon,
|
540 | activeMQIcon,
|
541 | sparkIcon,
|
542 | avroIcon,
|
543 | azureIcon,
|
544 | saxonIcon,
|
545 | dropBoxIcon,
|
546 | infinispanIcon,
|
547 | restIcon,
|
548 | swaggerIcon
|
549 | };
|
550 |
|
551 | return (
|
552 | <React.Fragment>
|
553 | <DashboardWrapper mainContainerId="main-content-card-view-default-nav" breadcrumb={null}>
|
554 | <PageSection variant={PageSectionVariants.light}>
|
555 | <TextContent>
|
556 | <Text component="h1">Projects</Text>
|
557 | <Text component="p">This is a demo that showcases PatternFly cards.</Text>
|
558 | </TextContent>
|
559 | <Toolbar id="toolbar-group-types" clearAllFilters={this.onDelete}>
|
560 | <ToolbarContent>{toolbarItems}</ToolbarContent>
|
561 | </Toolbar>
|
562 | </PageSection>
|
563 | <PageSection isFilled>
|
564 | <Gallery hasGutter aria-label="Selectable card container">
|
565 | <Card isSelectableRaised isCompact>
|
566 | <Bullseye>
|
567 | <EmptyState variant={EmptyStateVariant.xs}>
|
568 | <EmptyStateIcon icon={PlusCircleIcon} />
|
569 | <Title headingLevel="h2" size="md">
|
570 | Add a new card to your page
|
571 | </Title>
|
572 | <EmptyStateSecondaryActions>
|
573 | <Button variant="link">Add card</Button>
|
574 | </EmptyStateSecondaryActions>
|
575 | </EmptyState>
|
576 | </Bullseye>
|
577 | </Card>
|
578 | {filtered.map((product, key) => (
|
579 | <Card
|
580 | isSelectableRaised
|
581 | hasSelectableInput
|
582 | isCompact
|
583 | key={product.name}
|
584 | id={product.name.replace(/ /g, '-')}
|
585 | onKeyDown={e => this.onKeyDown(e, product.id)}
|
586 | onClick={() => this.onClick(product.id)}
|
587 | onSelectableInputChange={() => this.onClick(product.id)}
|
588 | isSelected={selectedItems.includes(product.id)}
|
589 | >
|
590 | <CardHeader>
|
591 | <img src={icons[product.icon]} alt={`${product.name} icon`} style={{ maxWidth: '60px' }} />
|
592 | <CardActions>
|
593 | <Dropdown
|
594 | isPlain
|
595 | position="right"
|
596 | onSelect={e => this.onCardKebabDropdownSelect(key, e)}
|
597 | toggle={
|
598 | <KebabToggle
|
599 | onToggle={isCardKebabDropdownOpen =>
|
600 | this.onCardKebabDropdownToggle(key, isCardKebabDropdownOpen)
|
601 | }
|
602 | />
|
603 | }
|
604 | isOpen={this.state[key]}
|
605 | dropdownItems={[
|
606 | <DropdownItem key="trash" onClick={this.deleteItem(product)} position="right">
|
607 | <TrashIcon />
|
608 | Delete
|
609 | </DropdownItem>
|
610 | ]}
|
611 | />
|
612 | <Checkbox
|
613 | checked={isChecked}
|
614 | value={product.id}
|
615 | isChecked={selectedItems.includes(product.id)}
|
616 | aria-label="card checkbox example"
|
617 | id={`check-${product.id}`}
|
618 | />
|
619 | </CardActions>
|
620 | </CardHeader>
|
621 | <CardTitle>{product.name}</CardTitle>
|
622 | <CardBody>{product.description}</CardBody>
|
623 | </Card>
|
624 | ))}
|
625 | </Gallery>
|
626 | </PageSection>
|
627 | <PageSection isFilled={false} sticky="bottom" padding={{ default: 'noPadding' }} variant="light">
|
628 | <Pagination
|
629 | itemCount={this.state.totalItemCount}
|
630 | page={page}
|
631 | page={this.state.page}
|
632 | perPage={this.state.perPage}
|
633 | onPerPageSelect={this.onPerPageSelect}
|
634 | onSetPage={this.onSetPage}
|
635 | variant="bottom"
|
636 | />
|
637 | </PageSection>
|
638 | </DashboardWrapper>
|
639 | </React.Fragment>
|
640 | );
|
641 | }
|
642 | }
|
643 | ```
|