Skip to content

Commit

Permalink
feat(react-grid): Ability to show all rows on a page via page size se…
Browse files Browse the repository at this point in the history
…lector (#150)
  • Loading branch information
SergeyAlexeev authored Jun 21, 2017
1 parent fe60801 commit 8af3dde
Show file tree
Hide file tree
Showing 21 changed files with 443 additions and 49 deletions.
1 change: 1 addition & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ gulp.task('site:docs', function() {
'packages/**/*.md',
'!packages/**/LICENSE.md',
'!packages/dx-react-demos/**/*',
'!packages/dx-testing/**/*',
'!/**/node_modules/**/*'
])
.pipe(rename(function(path) {
Expand Down
28 changes: 22 additions & 6 deletions packages/dx-grid-core/src/plugins/paging-state/computeds.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
export const paginate = (rows, pageSize, page) =>
rows.slice(pageSize * page, pageSize * (page + 1));
export const paginate = (rows, pageSize, page) => (
pageSize ?
rows.slice(pageSize * page, pageSize * (page + 1)) :
rows
);

export const ensurePageHeaders = (rows, pageSize) => {
if (!pageSize) {
return rows;
}

const result = rows.slice();

const headers = [];
Expand All @@ -27,13 +34,22 @@ export const ensurePageHeaders = (rows, pageSize) => {
return result;
};

export const totalPageCount = (rows, pageSize) => Math.ceil(rows.length / pageSize);
export const totalPageCount = (rows, pageSize) => (
pageSize ? Math.ceil(rows.length / pageSize) : 1
);

export const totalCount = rows => rows.length;

export const firstRowOnPage = (currentPage, pageSize) => (currentPage * pageSize) + 1;
export const firstRowOnPage = (currentPage, pageSize) => (
pageSize ? (currentPage * pageSize) + 1 : 1
);

export const lastRowOnPage = (currentPage, pageSize, totalRowCount) => {
const index = (currentPage + 1) * pageSize;
return index > totalRowCount ? totalRowCount : index;
let result = totalRowCount;
if (pageSize) {
const index = (currentPage + 1) * pageSize;
result = index > totalRowCount ? totalRowCount : index;
}

return result;
};
34 changes: 31 additions & 3 deletions packages/dx-grid-core/src/plugins/paging-state/computeds.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ describe('PagingState computeds', () => {

page = paginate(rows, 2, 3);
expect(page).toEqual([]);

page = paginate(rows, 0, 1);
expect(page).toEqual(rows);
});
});

Expand Down Expand Up @@ -141,12 +144,31 @@ describe('PagingState computeds', () => {
expect(computedRows[3]).toBe(rows[3]);
expect(computedRows[4]).toBe(rows[4]);
});

it('should work if pageSize is \'all\'', () => {
const rows = [
{ a: 1, _headerKey: 'a' },
{ a: 2 },
{ a: 3 },
{ a: 4 },
];

const computedRows = ensurePageHeaders(rows, 0);
expect(computedRows).toHaveLength(4);
expect(computedRows[0]).toBe(rows[0]);
expect(computedRows[1]).toBe(rows[1]);
expect(computedRows[2]).toBe(rows[2]);
expect(computedRows[3]).toBe(rows[3]);
});
});

describe('#totalPageCount', () => {
it('should work', () => {
const count = totalPageCount([1, 2, 3], 2);
let count = totalPageCount([1, 2, 3], 2);
expect(count).toEqual(2);

count = totalPageCount([1, 2, 3], 0);
expect(count).toEqual(1);
});
});

Expand All @@ -159,15 +181,21 @@ describe('PagingState computeds', () => {

describe('#firstRowOnPage', () => {
it('should work', () => {
const count = firstRowOnPage(1, 5);
let count = firstRowOnPage(1, 5);
expect(count).toEqual(6);

count = firstRowOnPage(1, 0);
expect(count).toEqual(1);
});
});

describe('#lastRowOnPage', () => {
it('should work', () => {
const count = lastRowOnPage(1, 5, 15);
let count = lastRowOnPage(1, 5, 15);
expect(count).toEqual(10);

count = lastRowOnPage(1, 0, 15);
expect(count).toEqual(15);
});

it('should not be greater than total count', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class PageSizeSelectorDemo extends React.PureComponent {
{ name: 'car', title: 'Car' },
],
rows: generateRows({ length: 60 }),
allowedPageSizes: [5, 10, 15],
allowedPageSizes: [5, 10, 15, 0],
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class PageSizeSelectorDemo extends React.PureComponent {
{ name: 'car', title: 'Car' },
],
rows: generateRows({ length: 60 }),
allowedPageSizes: [5, 10, 15],
allowedPageSizes: [5, 10, 15, 0],
};
}

Expand Down
22 changes: 17 additions & 5 deletions packages/dx-react-grid-bootstrap3/src/plugins/paging-panel.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import { PagingPanel as PagingPanelBase } from '@devexpress/dx-react-grid';
import { Pager } from '../templates/pager';

const pagerTemplate = props => <Pager {...props} />;

export const PagingPanel = props => (
export const PagingPanel = ({ showAllText, ...restProps }) => (
<PagingPanelBase
pagerTemplate={pagerTemplate}
{...props}
pagerTemplate={
props => (
<Pager
showAllText={showAllText}
{...props}
/>
)
}
{...restProps}
/>
);

PagingPanel.propTypes = {
showAllText: PropTypes.string,
};
PagingPanel.defaultProps = {
showAllText: undefined,
};
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';

export const PageSizeSelector = ({ pageSize, onPageSizeChange, allowedPageSizes }) => (
export const PageSizeSelector = ({
pageSize,
onPageSizeChange,
allowedPageSizes,
showAllText,
}) => (
<div style={{ display: 'inline-block' }}>
<select
className="form-control visible-xs-inline-block"
style={{ width: 'auto' }}
value={pageSize}
onChange={e => onPageSizeChange(parseInt(e.target.value, 10))}
>
{allowedPageSizes.map(val => <option key={val} value={val}>{val}</option>)}
{
allowedPageSizes.map(val =>
<option key={val} value={val}>
{val || showAllText}
</option>)
}
</select>
<ul
className="pagination hidden-xs"
Expand All @@ -28,7 +38,7 @@ export const PageSizeSelector = ({ pageSize, onPageSizeChange, allowedPageSizes
onPageSizeChange(item);
}}
>
{item}
{item || showAllText}
</a>
{/* eslint-enable jsx-a11y/href-no-hash */}
</li>
Expand All @@ -41,4 +51,10 @@ PageSizeSelector.propTypes = {
pageSize: PropTypes.number.isRequired,
onPageSizeChange: PropTypes.func.isRequired,
allowedPageSizes: PropTypes.arrayOf(PropTypes.number).isRequired,
showAllText: PropTypes.string,
};

PageSizeSelector.defaultProps = {
showAllText: 'All',
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import { mount } from 'enzyme';
import { PageSizeSelector } from './page-size-selector';

describe('PageSizeSelector', () => {
describe('#render', () => {
const mountPageSizeSelector = ({
pageSize,
allowedPageSizes,
showAllText,
onPageSizeChange = () => {},
}) => mount(<PageSizeSelector
pageSize={pageSize}
allowedPageSizes={allowedPageSizes}
showAllText={showAllText}
onPageSizeChange={onPageSizeChange}
/>);

it('can show info about page sizes', () => {
const tree = mountPageSizeSelector({
pageSize: 10,
allowedPageSizes: [5, 10],
});

const mobileSelector = tree.find('select');
const desktopSelector = tree.find('ul.pagination');
const mobileSelectorItems = mobileSelector.find('option');
const desktopSelectorItems = desktopSelector.find('li');

expect(mobileSelector).toHaveLength(1);
expect(mobileSelector.prop('value')).toBe(10);
expect(mobileSelectorItems).toHaveLength(2);
expect(mobileSelectorItems.at(0).prop('value')).toBe(5);
expect(mobileSelectorItems.at(0).text()).toBe('5');
expect(mobileSelectorItems.at(1).prop('value')).toBe(10);
expect(mobileSelectorItems.at(1).text()).toBe('10');

expect(desktopSelector).toHaveLength(1);
expect(desktopSelectorItems).toHaveLength(2);
expect(desktopSelectorItems.at(0).prop('className')).toBe('');
expect(desktopSelectorItems.at(0).text()).toBe('5');
expect(desktopSelectorItems.at(1).prop('className')).toBe('active');
expect(desktopSelectorItems.at(1).text()).toBe('10');
});

it('can render the \'All\' item', () => {
const tree = mountPageSizeSelector({
pageSize: 10,
allowedPageSizes: [5, 10, 0],
});

const mobileSelector = tree.find('select');
const desktopSelector = tree.find('ul.pagination');
const mobileSelectorItems = mobileSelector.find('option');
const desktopSelectorItems = desktopSelector.find('li');

expect(mobileSelectorItems).toHaveLength(3);
expect(mobileSelectorItems.at(2).prop('value')).toBe(0);
expect(mobileSelectorItems.at(2).text()).toBe('All');

expect(desktopSelectorItems).toHaveLength(3);
expect(desktopSelectorItems.at(2).text()).toBe('All');
});

it('can customize the \'All\' item text', () => {
const tree = mountPageSizeSelector({
pageSize: 10,
allowedPageSizes: [5, 10, 0],
showAllText: 'Show all',
});

const mobileSelector = tree.find('select');
const desktopSelector = tree.find('ul.pagination');

expect(mobileSelector.find('option').at(2).text()).toBe('Show all');
expect(desktopSelector.find('li').at(2).text()).toBe('Show all');
});

it('can handle the \'onPageSizeChange\' event', () => {
const onPageSizeChange = jest.fn();
const tree = mountPageSizeSelector({
pageSize: 5,
allowedPageSizes: [5, 10],
onPageSizeChange,
});

const mobileSelector = tree.find('select');
const desktopSelector = tree.find('ul.pagination');

mobileSelector.simulate('change', { target: { value: 10 } });
desktopSelector.find('li > a').at(0).simulate('click');

expect(onPageSizeChange.mock.calls[0][0]).toBe(10);
expect(onPageSizeChange.mock.calls[1][0]).toBe(5);
});
});
});
7 changes: 7 additions & 0 deletions packages/dx-react-grid-bootstrap3/src/templates/pager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ export const Pager = ({
onPageSizeChange,
allowedPageSizes,
totalCount,
showAllText,
}) => (
<div className="clearfix">
{!!allowedPageSizes.length && <PageSizeSelector
pageSize={pageSize}
onPageSizeChange={onPageSizeChange}
allowedPageSizes={allowedPageSizes}
showAllText={showAllText}
/>}
<Pagination
style={{
Expand Down Expand Up @@ -67,4 +69,9 @@ Pager.propTypes = {
onPageSizeChange: PropTypes.func.isRequired,
allowedPageSizes: PropTypes.arrayOf(PropTypes.number).isRequired,
totalCount: PropTypes.number.isRequired,
showAllText: PropTypes.string,
};

Pager.defaultProps = {
showAllText: undefined,
};
27 changes: 27 additions & 0 deletions packages/dx-react-grid-bootstrap3/src/templates/pager.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('Pager', () => {
totalPages,
pageSize,
totalCount,
showAllText,
allowedPageSizes = [],
onPageSizeChange = () => {},
onCurrentPageChange = () => {},
Expand All @@ -17,6 +18,7 @@ describe('Pager', () => {
currentPage={currentPage}
totalCount={totalCount}
pageSize={pageSize}
showAllText={showAllText}
allowedPageSizes={allowedPageSizes}
onCurrentPageChange={onCurrentPageChange}
onPageSizeChange={onPageSizeChange}
Expand Down Expand Up @@ -96,5 +98,30 @@ describe('Pager', () => {
expect(next.hasClass('disabled')).toBeTruthy();
expect(onCurrentPageChange.mock.calls).toHaveLength(1);
});

it('renders page selector', () => {
const pageSizeSelector = mountPager({
totalPages: 10,
currentPage: 9,
totalCount: 96,
pageSize: 5,
allowedPageSizes: [5, 10],
showAllText: 'Show all',
}).find('PageSizeSelector');

expect(pageSizeSelector).toHaveLength(1);
expect(pageSizeSelector.at(0).prop('showAllText')).toBe('Show all');
});

it('doesn\'t render page selector if the allowedPageSizes option is not defined ', () => {
const pageSizeSelector = mountPager({
totalPages: 10,
currentPage: 9,
totalCount: 96,
pageSize: 5,
}).find('PageSizeSelector');

expect(pageSizeSelector).toHaveLength(0);
});
});
});
Loading

0 comments on commit 8af3dde

Please sign in to comment.