Merge pull request #208 from keithjgrant/toolbar-render-prop

use a render prop for PaginatedDataList toolbar
This commit is contained in:
Keith Grant
2019-05-20 06:16:48 -07:00
committed by GitHub
8 changed files with 135 additions and 145 deletions

View File

@@ -176,11 +176,8 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
> >
<Route> <Route>
<PaginatedDataList <PaginatedDataList
additionalControls={Array []}
alignToolbarLeft={false}
history={"/history/"} history={"/history/"}
i18n={"/i18n/"} i18n={"/i18n/"}
isAllSelected={false}
itemCount={2} itemCount={2}
itemName="notification" itemName="notification"
itemNamePlural="" itemNamePlural=""
@@ -216,7 +213,6 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
"url": "", "url": "",
} }
} }
onSelectAll={null}
qsConfig={ qsConfig={
Object { Object {
"defaultParams": Object { "defaultParams": Object {
@@ -232,8 +228,8 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
} }
} }
renderItem={[Function]} renderItem={[Function]}
renderToolbar={[Function]}
showPageSizeOptions={true} showPageSizeOptions={true}
showSelectAll={false}
toolbarColumns={ toolbarColumns={
Array [ Array [
Object { Object {
@@ -257,7 +253,6 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
} }
> >
<WithI18n <WithI18n
additionalControls={Array []}
columns={ columns={
Array [ Array [
Object { Object {
@@ -279,12 +274,8 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
}, },
] ]
} }
isAllSelected={false}
noLeftMargin={false}
onSearch={[Function]} onSearch={[Function]}
onSelectAll={null}
onSort={[Function]} onSort={[Function]}
showSelectAll={false}
sortOrder="ascending" sortOrder="ascending"
sortedColumnKey="name" sortedColumnKey="name"
> >

View File

@@ -4,6 +4,7 @@ import { withRouter } from 'react-router-dom';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import PaginatedDataList from '../PaginatedDataList'; import PaginatedDataList from '../PaginatedDataList';
import DataListToolbar from '../DataListToolbar';
import CheckboxListItem from '../ListItem'; import CheckboxListItem from '../ListItem';
import SelectedList from '../SelectedList'; import SelectedList from '../SelectedList';
import { getQSConfig, parseNamespacedQueryString } from '../../util/qs'; import { getQSConfig, parseNamespacedQueryString } from '../../util/qs';
@@ -102,9 +103,7 @@ class SelectResourceStep extends React.Component {
itemCount={count} itemCount={count}
itemName={itemName} itemName={itemName}
qsConfig={this.qsConfig} qsConfig={this.qsConfig}
toolbarColumns={ toolbarColumns={columns}
columns
}
renderItem={item => ( renderItem={item => (
<CheckboxListItem <CheckboxListItem
isSelected={selectedResourceRows.some(i => i.id === item.id)} isSelected={selectedResourceRows.some(i => i.id === item.id)}
@@ -114,7 +113,9 @@ class SelectResourceStep extends React.Component {
onSelect={() => onRowClick(item)} onSelect={() => onRowClick(item)}
/> />
)} )}
alignToolbarLeft renderToolbar={(props) => (
<DataListToolbar {...props} alignToolbarLeft />
)}
showPageSizeOptions={false} showPageSizeOptions={false}
/> />
</Fragment> </Fragment>

View File

@@ -14,6 +14,7 @@ import { t } from '@lingui/macro';
import { withNetwork } from '../../contexts/Network'; import { withNetwork } from '../../contexts/Network';
import PaginatedDataList from '../PaginatedDataList'; import PaginatedDataList from '../PaginatedDataList';
import DataListToolbar from '../DataListToolbar';
import CheckboxListItem from '../ListItem'; import CheckboxListItem from '../ListItem';
import SelectedList from '../SelectedList'; import SelectedList from '../SelectedList';
import { getQSConfig, parseNamespacedQueryString } from '../../util/qs'; import { getQSConfig, parseNamespacedQueryString } from '../../util/qs';
@@ -176,7 +177,9 @@ class Lookup extends React.Component {
onSelect={() => this.toggleSelected(item)} onSelect={() => this.toggleSelected(item)}
/> />
)} )}
alignToolbarLeft renderToolbar={(props) => (
<DataListToolbar {...props} alignToolbarLeft />
)}
showPageSizeOptions={false} showPageSizeOptions={false}
/> />
{lookupSelectedItems.length > 0 && ( {lookupSelectedItems.length > 0 && (

View File

@@ -1,12 +1,7 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes, { arrayOf, shape, string, bool, node } from 'prop-types'; import PropTypes, { arrayOf, shape, string, bool } from 'prop-types';
import { import {
DataList, DataList,
DataListItem,
DataListItemRow,
DataListItemCells,
DataListCell,
TextContent,
Title, Title,
EmptyState, EmptyState,
EmptyStateIcon, EmptyStateIcon,
@@ -15,11 +10,12 @@ import {
import { CubesIcon } from '@patternfly/react-icons'; import { CubesIcon } from '@patternfly/react-icons';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { withRouter, Link } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import styled from 'styled-components'; import styled from 'styled-components';
import Pagination from '../Pagination'; import Pagination from '../Pagination';
import DataListToolbar from '../DataListToolbar'; import DataListToolbar from '../DataListToolbar';
import PaginatedDataListItem from './PaginatedDataListItem';
import { import {
parseNamespacedQueryString, parseNamespacedQueryString,
updateNamespacedQueryString, updateNamespacedQueryString,
@@ -38,13 +34,6 @@ const EmptyStateControlsWrapper = styled.div`
margin-left: 20px; margin-left: 20px;
} }
`; `;
const ListItemGrid = styled(TextContent)`
display: grid;
grid-template-columns: minmax(70px,max-content) repeat(auto-fit, minmax(60px,max-content));
grid-gap: 10px;
`;
class PaginatedDataList extends React.Component { class PaginatedDataList extends React.Component {
constructor (props) { constructor (props) {
super(props); super(props);
@@ -58,12 +47,6 @@ class PaginatedDataList extends React.Component {
this.handleSort = this.handleSort.bind(this); this.handleSort = this.handleSort.bind(this);
} }
getPageCount () {
const { itemCount, qsConfig, location } = this.props;
const queryParams = parseNamespacedQueryString(qsConfig, location.search);
return Math.ceil(itemCount / queryParams.page_size);
}
getSortOrder () { getSortOrder () {
const { qsConfig, location } = this.props; const { qsConfig, location } = this.props;
const queryParams = parseNamespacedQueryString(qsConfig, location.search); const queryParams = parseNamespacedQueryString(qsConfig, location.search);
@@ -95,11 +78,6 @@ class PaginatedDataList extends React.Component {
history.push(`${pathname}?${qs}`); history.push(`${pathname}?${qs}`);
} }
getPluralItemName () {
const { itemName, itemNamePlural } = this.props;
return itemNamePlural || `${itemName}s`;
}
render () { render () {
const { const {
emptyStateControls, emptyStateControls,
@@ -108,16 +86,12 @@ class PaginatedDataList extends React.Component {
qsConfig, qsConfig,
renderItem, renderItem,
toolbarColumns, toolbarColumns,
additionalControls,
itemName, itemName,
itemNamePlural, itemNamePlural,
showSelectAll,
isAllSelected,
onSelectAll,
alignToolbarLeft,
showPageSizeOptions, showPageSizeOptions,
location, location,
i18n i18n,
renderToolbar,
} = this.props; } = this.props;
const { error } = this.state; const { error } = this.state;
const [orderBy, sortOrder] = this.getSortOrder(); const [orderBy, sortOrder] = this.getSortOrder();
@@ -133,8 +107,7 @@ class PaginatedDataList extends React.Component {
)} )}
</Fragment> // TODO: replace with proper error handling </Fragment> // TODO: replace with proper error handling
)} )}
{items.length === 0 {items.length === 0 ? (
? (
<Fragment> <Fragment>
<EmptyStateControlsWrapper> <EmptyStateControlsWrapper>
{emptyStateControls} {emptyStateControls}
@@ -150,43 +123,18 @@ class PaginatedDataList extends React.Component {
</EmptyStateBody> </EmptyStateBody>
</EmptyState> </EmptyState>
</Fragment> </Fragment>
) ) : (
: (
<Fragment> <Fragment>
<DataListToolbar {renderToolbar({
sortedColumnKey={orderBy} sortedColumnKey: orderBy,
sortOrder={sortOrder} sortOrder,
columns={columns} columns,
onSearch={() => { }} onSearch: () => { },
onSort={this.handleSort} onSort: this.handleSort,
showSelectAll={showSelectAll} })}
isAllSelected={isAllSelected}
onSelectAll={onSelectAll}
additionalControls={additionalControls}
noLeftMargin={alignToolbarLeft}
/>
<DataList aria-label={i18n._(t`${ucFirst(pluralize(itemName))} List`)}> <DataList aria-label={i18n._(t`${ucFirst(pluralize(itemName))} List`)}>
{items.map(item => (renderItem ? renderItem(item) : ( {items.map(item => (renderItem ? renderItem(item) : (
<DataListItem <PaginatedDataListItem key={item.id} item={item} />
aria-labelledby={`items-list-item-${item.id}`}
key={item.id}
>
<DataListItemRow>
<DataListItemCells dataListCells={[
<DataListCell key="team-name">
<ListItemGrid>
<Link to={{ pathname: item.url }}>
<b id={`items-list-item-${item.id}`}>
{item.name}
</b>
</Link>
</ListItemGrid>
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
)))} )))}
</DataList> </DataList>
<Pagination <Pagination
@@ -228,25 +176,17 @@ PaginatedDataList.propTypes = {
key: string.isRequired, key: string.isRequired,
isSortable: bool, isSortable: bool,
})), })),
additionalControls: arrayOf(node),
showSelectAll: PropTypes.bool,
isAllSelected: PropTypes.bool,
onSelectAll: PropTypes.func,
alignToolbarLeft: PropTypes.bool,
showPageSizeOptions: PropTypes.bool, showPageSizeOptions: PropTypes.bool,
renderToolbar: PropTypes.func,
}; };
PaginatedDataList.defaultProps = { PaginatedDataList.defaultProps = {
renderItem: null, renderItem: null,
toolbarColumns: [], toolbarColumns: [],
additionalControls: [],
itemName: 'item', itemName: 'item',
itemNamePlural: '', itemNamePlural: '',
showSelectAll: false,
isAllSelected: false,
onSelectAll: null,
alignToolbarLeft: false,
showPageSizeOptions: true, showPageSizeOptions: true,
renderToolbar: (props) => (<DataListToolbar {...props} />),
}; };
export { PaginatedDataList as _PaginatedDataList }; export { PaginatedDataList as _PaginatedDataList };

View File

@@ -0,0 +1,42 @@
import React from 'react';
import { Link } from 'react-router-dom';
import {
DataListItem,
DataListItemRow,
DataListItemCells,
DataListCell,
TextContent,
} from '@patternfly/react-core';
import styled from 'styled-components';
const DetailWrapper = styled(TextContent)`
display: grid;
grid-template-columns:
minmax(70px, max-content)
repeat(auto-fit, minmax(60px, max-content));
grid-gap: 10px;
`;
export default function PaginatedDataListItem ({ item }) {
return (
<DataListItem
aria-labelledby={`items-list-item-${item.id}`}
key={item.id}
>
<DataListItemRow>
<DataListItemCells dataListCells={[
<DataListCell key="team-name">
<DetailWrapper>
<Link to={{ pathname: item.url }}>
<b id={`items-list-item-${item.id}`}>
{item.name}
</b>
</Link>
</DetailWrapper>
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
);
}

View File

@@ -1,5 +1,6 @@
import PaginatedDataList from './PaginatedDataList'; import PaginatedDataList from './PaginatedDataList';
export default PaginatedDataList; export default PaginatedDataList;
export { default as PaginatedDataListItem } from './PaginatedDataListItem';
export { default as ToolbarDeleteButton } from './ToolbarDeleteButton'; export { default as ToolbarDeleteButton } from './ToolbarDeleteButton';
export { default as ToolbarAddButton } from './ToolbarAddButton'; export { default as ToolbarAddButton } from './ToolbarAddButton';

View File

@@ -3,6 +3,7 @@ import { withRouter } from 'react-router-dom';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import PaginatedDataList, { ToolbarAddButton } from '../../../../components/PaginatedDataList'; import PaginatedDataList, { ToolbarAddButton } from '../../../../components/PaginatedDataList';
import DataListToolbar from '../../../../components/DataListToolbar';
import OrganizationAccessItem from '../../components/OrganizationAccessItem'; import OrganizationAccessItem from '../../components/OrganizationAccessItem';
import DeleteRoleConfirmationModal from '../../components/DeleteRoleConfirmationModal'; import DeleteRoleConfirmationModal from '../../components/DeleteRoleConfirmationModal';
import AddResourceRole from '../../../../components/AddRole/AddResourceRole'; import AddResourceRole from '../../../../components/AddRole/AddResourceRole';
@@ -172,9 +173,14 @@ class OrganizationAccess extends React.Component {
{ name: i18n._(t`Username`), key: 'username', isSortable: true }, { name: i18n._(t`Username`), key: 'username', isSortable: true },
{ name: i18n._(t`Last Name`), key: 'last_name', isSortable: true }, { name: i18n._(t`Last Name`), key: 'last_name', isSortable: true },
]} ]}
renderToolbar={(props) => (
<DataListToolbar
{...props}
additionalControls={canEdit ? [ additionalControls={canEdit ? [
<ToolbarAddButton key="add" onClick={this.toggleAddModal} /> <ToolbarAddButton key="add" onClick={this.toggleAddModal} />
] : null} ] : null}
/>
)}
renderItem={accessRecord => ( renderItem={accessRecord => (
<OrganizationAccessItem <OrganizationAccessItem
key={accessRecord.id} key={accessRecord.id}

View File

@@ -13,6 +13,7 @@ import PaginatedDataList, {
ToolbarDeleteButton, ToolbarDeleteButton,
ToolbarAddButton ToolbarAddButton
} from '../../../components/PaginatedDataList'; } from '../../../components/PaginatedDataList';
import DataListToolbar from '../../../components/DataListToolbar';
import OrganizationListItem from '../components/OrganizationListItem'; import OrganizationListItem from '../components/OrganizationListItem';
import { getQSConfig, parseNamespacedQueryString } from '../../../util/qs'; import { getQSConfig, parseNamespacedQueryString } from '../../../util/qs';
@@ -163,6 +164,9 @@ class OrganizationsList extends Component {
{ name: i18n._(t`Modified`), key: 'modified', isSortable: true, isNumeric: true }, { name: i18n._(t`Modified`), key: 'modified', isSortable: true, isNumeric: true },
{ name: i18n._(t`Created`), key: 'created', isSortable: true, isNumeric: true }, { name: i18n._(t`Created`), key: 'created', isSortable: true, isNumeric: true },
]} ]}
renderToolbar={(props) => (
<DataListToolbar
{...props}
showSelectAll showSelectAll
isAllSelected={isAllSelected} isAllSelected={isAllSelected}
onSelectAll={this.handleSelectAll} onSelectAll={this.handleSelectAll}
@@ -177,6 +181,8 @@ class OrganizationsList extends Component {
? <ToolbarAddButton key="add" linkTo={`${match.url}/add`} /> ? <ToolbarAddButton key="add" linkTo={`${match.url}/add`} />
: null, : null,
]} ]}
/>
)}
renderItem={(o) => ( renderItem={(o) => (
<OrganizationListItem <OrganizationListItem
key={o.id} key={o.id}