Compare commits

...

14 Commits

Author SHA1 Message Date
AllenFang
345cb83493 Publish
- react-bootstrap-table2-example@1.0.2
 - react-bootstrap-table2-paginator@1.0.2
 - react-bootstrap-table2-toolkit@1.0.2
 - react-bootstrap-table-next@1.1.2
2018-08-21 17:05:08 +08:00
Allen
6e526f455b Merge pull request #500 from react-bootstrap-table/develop
20180821 release
2018-08-21 17:03:00 +08:00
AllenFang
b05cf48f36 Merge branch 'COzero-issue-363' into develop 2018-08-20 23:36:42 +08:00
AllenFang
28249c9089 fixed version 2018-08-20 23:36:22 +08:00
AllenFang
2b6081ab31 Merge branch 'issue-363' of https://github.com/COzero/react-bootstrap-table2 into COzero-issue-363 2018-08-20 23:23:32 +08:00
AllenFang
c935447266 Merge branch 'develop' of https://github.com/react-bootstrap-table/react-bootstrap-table2 into develop 2018-08-20 22:59:36 +08:00
AllenFang
ba1d6fa3ed fix #498 2018-08-20 22:59:14 +08:00
Allen
1b3b68f8a7 fix controlled page state will effect the internal page state when internal table rerender (#492) 2018-08-19 12:43:52 +08:00
copas2
4a3486cc3c fix #488
* updated test for pagination fix

* suspected bug in page.js

Local pagination aligning returns start page when eg editing cell locally. This results in state change, too. Not really getting the purpose of the original idea. Please consider this modification. It only checks if page fits in the data size range. As I saw, this alignment only affects local pagination, not remote.

* modified fix w/ pageStartIndex

I forgot to mind pageStartIndex
2018-08-16 17:16:47 +08:00
Allen
cb49455a4e Merge pull request #489 from react-bootstrap-table/bugfix/infinite-remote-search
Bugfix/infinite remote search
2018-08-15 23:16:52 +08:00
AllenFang
5e63d6ae59 avoid infinite remote search 2018-08-15 23:08:46 +08:00
Jeremy Nagel
96d33a60ba Add snapshot tests 2018-08-13 16:50:43 +10:00
Jeremy Nagel
03389aece0 Merge branch 'master' of github.com:react-bootstrap-table/react-bootstrap-table2 into issue-363 2018-08-13 16:45:34 +10:00
Jeremy Nagel
f35d644608 [BUGFIX] Fix issue with missing onChange prop for selection checkbox 2018-07-16 11:18:02 +10:00
18 changed files with 148 additions and 181 deletions

View File

@@ -52,6 +52,7 @@
"css-loader": "0.28.1", "css-loader": "0.28.1",
"enzyme": "3.3.0", "enzyme": "3.3.0",
"enzyme-adapter-react-16": "1.1.1", "enzyme-adapter-react-16": "1.1.1",
"enzyme-to-json": "3.3.4",
"eslint": "4.5.0", "eslint": "4.5.0",
"eslint-config-airbnb": "15.1.0", "eslint-config-airbnb": "15.1.0",
"eslint-loader": "1.9.0", "eslint-loader": "1.9.0",

View File

@@ -22,8 +22,19 @@ const columns = [{
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
// ... // ...
const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize }) => ( const NoDataIndication = () => (
<div className="spinner">
<div className="rect1" />
<div className="rect2" />
<div className="rect3" />
<div className="rect4" />
<div className="rect5" />
</div>
);
const Table = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
<div> <div>
<BootstrapTable <BootstrapTable
remote remote
@@ -32,12 +43,13 @@ const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize })
columns={ columns } columns={ columns }
pagination={ paginationFactory({ page, sizePerPage, totalSize }) } pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange } onTableChange={ onTableChange }
noDataIndication={ () => <NoDataIndication /> }
/> />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );
class Container extends React.Component { class EmptyTableOverlay extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@@ -47,7 +59,7 @@ class Container extends React.Component {
}; };
} }
handleTableChange = ({ page, sizePerPage }) => { handleTableChange = (type, { page, sizePerPage }) => {
const currentIndex = (page - 1) * sizePerPage; const currentIndex = (page - 1) * sizePerPage;
setTimeout(() => { setTimeout(() => {
this.setState(() => ({ this.setState(() => ({
@@ -55,13 +67,14 @@ class Container extends React.Component {
data: products.slice(currentIndex, currentIndex + sizePerPage), data: products.slice(currentIndex, currentIndex + sizePerPage),
sizePerPage sizePerPage
})); }));
}, 2000); }, 3000);
this.setState(() => ({ data: [] }));
} }
render() { render() {
const { data, sizePerPage, page } = this.state; const { data, sizePerPage, page } = this.state;
return ( return (
<RemotePagination <Table
data={ data } data={ data }
page={ page } page={ page }
sizePerPage={ sizePerPage } sizePerPage={ sizePerPage }

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-example", "name": "react-bootstrap-table2-example",
"version": "1.0.1", "version": "1.0.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"private": true, "private": true,

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-paginator", "name": "react-bootstrap-table2-paginator",
"version": "1.0.1", "version": "1.0.2",
"description": "it's the pagination addon for react-bootstrap-table2", "description": "it's the pagination addon for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -54,16 +54,13 @@ export default (
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
let needNewState = false; let needNewState = false;
let { currPage, currSizePerPage } = this; let { currPage } = this;
const { page, sizePerPage, onPageChange } = nextProps.pagination.options; const { currSizePerPage } = this;
const { onPageChange } = nextProps.pagination.options;
const pageStartIndex = typeof nextProps.pagination.options.pageStartIndex !== 'undefined' ? const pageStartIndex = typeof nextProps.pagination.options.pageStartIndex !== 'undefined' ?
nextProps.pagination.options.pageStartIndex : Const.PAGE_START_INDEX; nextProps.pagination.options.pageStartIndex : Const.PAGE_START_INDEX;
if (typeof page !== 'undefined' && currPage !== page) { // user defined page
currPage = page;
needNewState = true;
} else {
// user should align the page when the page is not fit to the data size when remote enable // user should align the page when the page is not fit to the data size when remote enable
if (!isRemotePagination()) { if (!isRemotePagination()) {
const newPage = alignPage(nextProps.data, currPage, currSizePerPage, pageStartIndex); const newPage = alignPage(nextProps.data, currPage, currSizePerPage, pageStartIndex);
@@ -72,12 +69,6 @@ export default (
needNewState = true; needNewState = true;
} }
} }
}
if (typeof sizePerPage !== 'undefined' && currSizePerPage !== sizePerPage) {
currSizePerPage = sizePerPage;
needNewState = true;
}
if (needNewState) { if (needNewState) {
if (onPageChange) { if (onPageChange) {

View File

@@ -23,10 +23,9 @@ export const alignPage = (
sizePerPage, sizePerPage,
pageStartIndex pageStartIndex
) => { ) => {
const end = endIndex(page, sizePerPage, pageStartIndex);
const dataSize = data.length; const dataSize = data.length;
if (end - 1 > dataSize) { if (page < pageStartIndex || page > (Math.floor(dataSize / sizePerPage) + pageStartIndex)) {
return pageStartIndex; return pageStartIndex;
} }
return page; return page;

View File

@@ -126,69 +126,6 @@ describe('PaginationContext', () => {
let instance; let instance;
let nextProps; let nextProps;
describe('when nextProps.pagination.options.page is existing', () => {
const onPageChange = jest.fn();
afterEach(() => {
onPageChange.mockReset();
});
describe('and if it is different with currPage', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
instance = wrapper.instance();
wrapper.render();
nextProps = {
data,
pagination: {
options: {
page: 2,
onPageChange
}
}
};
instance.componentWillReceiveProps(nextProps);
});
it('should call options.onPageChange', () => {
expect(onPageChange).toHaveBeenCalledTimes(1);
expect(onPageChange).toHaveBeenCalledWith(
instance.currPage,
instance.currSizePerPage
);
});
it('should set correct currPage', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page);
});
});
describe('and if it is same as currPage', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
instance = wrapper.instance();
wrapper.render();
nextProps = {
data,
pagination: {
options: {
page: 1,
onPageChange
}
}
};
instance.componentWillReceiveProps(nextProps);
});
it('shouldn\'t call options.onPageChange', () => {
expect(onPageChange).toHaveBeenCalledTimes(0);
});
it('should have correct currPage', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page);
});
});
});
describe('when nextProps.pagination.options.page is not existing', () => { describe('when nextProps.pagination.options.page is not existing', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallow(shallowContext({ wrapper = shallow(shallowContext({
@@ -206,69 +143,6 @@ describe('PaginationContext', () => {
}); });
}); });
describe('when nextProps.pagination.options.sizePerPage is existing', () => {
const onPageChange = jest.fn();
afterEach(() => {
onPageChange.mockReset();
});
describe('and if it is different with currSizePerPage', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
instance = wrapper.instance();
wrapper.render();
nextProps = {
data,
pagination: {
options: {
sizePerPage: Const.SIZE_PER_PAGE_LIST[2],
onPageChange
}
}
};
instance.componentWillReceiveProps(nextProps);
});
it('should call options.onPageChange', () => {
expect(onPageChange).toHaveBeenCalledTimes(1);
expect(onPageChange).toHaveBeenCalledWith(
instance.currPage,
instance.currSizePerPage
);
});
it('should set correct currSizePerPage', () => {
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage);
});
});
describe('and if it is same as currSizePerPage', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
instance = wrapper.instance();
wrapper.render();
nextProps = {
data,
pagination: {
options: {
sizePerPage: Const.SIZE_PER_PAGE_LIST[0],
onPageChange
}
}
};
instance.componentWillReceiveProps(nextProps);
});
it('shouldn\'t call options.onPageChange', () => {
expect(onPageChange).toHaveBeenCalledTimes(0);
});
it('should have correct currSizePerPage', () => {
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage);
});
});
});
describe('when nextProps.pagination.options.sizePerPage is not existing', () => { describe('when nextProps.pagination.options.sizePerPage is not existing', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallow(shallowContext({ wrapper = shallow(shallowContext({
@@ -281,10 +155,53 @@ describe('PaginationContext', () => {
instance.componentWillReceiveProps(nextProps); instance.componentWillReceiveProps(nextProps);
}); });
it('should not set currPage', () => { it('should not set currSizePerPage', () => {
expect(instance.currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[2]); expect(instance.currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[2]);
}); });
}); });
describe('when page is not align', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
page: 2
}));
instance = wrapper.instance();
wrapper.render();
nextProps = {
data: [],
pagination: { ...defaultPagination }
};
instance.componentWillReceiveProps(nextProps);
});
it('should reset currPage to first page', () => {
expect(instance.currPage).toEqual(1);
});
describe('if options.onPageChange is defined', () => {
const onPageChange = jest.fn();
beforeEach(() => {
onPageChange.mockClear();
wrapper = shallow(shallowContext({
...defaultPagination,
page: 2
}));
instance = wrapper.instance();
wrapper.render();
nextProps = {
data: [],
pagination: { ...defaultPagination, options: { onPageChange } }
};
instance.componentWillReceiveProps(nextProps);
});
it('should call options.onPageChange correctly', () => {
expect(onPageChange).toHaveBeenCalledTimes(1);
expect(onPageChange).toHaveBeenCalledWith(instance.currPage, instance.currSizePerPage);
});
});
});
}); });
describe('handleChangePage', () => { describe('handleChangePage', () => {

View File

@@ -45,8 +45,8 @@ describe('Page Functions', () => {
describe('alignPage', () => { describe('alignPage', () => {
const pageStartIndex = 1; const pageStartIndex = 1;
const sizePerPage = 10; const sizePerPage = 10;
const page = 2; const page = 3;
describe('if the length of store.data is less than the end page index', () => { describe('if the page does not fit the pages interval calculated from the length of store.data', () => {
beforeEach(() => { beforeEach(() => {
data = []; data = [];
for (let i = 0; i < 15; i += 1) { for (let i = 0; i < 15; i += 1) {

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-toolkit", "name": "react-bootstrap-table2-toolkit",
"version": "1.0.1", "version": "1.0.2",
"description": "The toolkit for react-bootstrap-table2", "description": "The toolkit for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -20,11 +20,26 @@ export default (options = {
searchText: PropTypes.string searchText: PropTypes.string
} }
constructor(props) {
super(props);
this.performRemoteSearch = props.searchText !== '';
}
componentWillReceiveProps(nextProps) {
if (isRemoteSearch()) {
if (nextProps.searchText !== this.props.searchText) {
this.performRemoteSearch = true;
} else {
this.performRemoteSearch = false;
}
}
}
search() { search() {
const { data, columns } = this.props; const { data, columns } = this.props;
let { searchText } = this.props; let { searchText } = this.props;
if (isRemoteSearch()) { if (isRemoteSearch() && this.performRemoteSearch) {
handleRemoteSearchChange(searchText); handleRemoteSearchChange(searchText);
return data; return data;
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table-next", "name": "react-bootstrap-table-next",
"version": "1.1.1", "version": "1.1.2",
"description": "Next generation of react-bootstrap-table", "description": "Next generation of react-bootstrap-table",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -75,6 +75,7 @@ export default class SelectionCell extends Component {
checked={ selected } checked={ selected }
disabled={ disabled } disabled={ disabled }
className={ bootstrap4 ? 'selection-input-4' : '' } className={ bootstrap4 ? 'selection-input-4' : '' }
onChange={ () => {} }
/> />
) )
} }

View File

@@ -12,6 +12,7 @@ export const CheckBox = ({ className, checked, indeterminate }) => (
ref={ (input) => { ref={ (input) => {
if (input) input.indeterminate = indeterminate; // eslint-disable-line no-param-reassign if (input) input.indeterminate = indeterminate; // eslint-disable-line no-param-reassign
} } } }
onChange={ () => {} }
/> />
); );

View File

@@ -0,0 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<SelectionCell /> render should render component correctly 1`] = `
<td
onClick={[Function]}
>
<input
checked={true}
className=""
onChange={[Function]}
type="checkbox"
/>
</td>
`;

View File

@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<CheckBox /> render should render component correctly 1`] = `
<input
checked={true}
onChange={[Function]}
type="checkbox"
/>
`;

View File

@@ -1,6 +1,7 @@
import 'jsdom-global/register'; import 'jsdom-global/register';
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import sinon from 'sinon'; import sinon from 'sinon';
import { shallowWithContext } from '../test-helpers/new-context'; import { shallowWithContext } from '../test-helpers/new-context';
@@ -61,7 +62,8 @@ describe('<SelectionCell />', () => {
mode={ mode } mode={ mode }
rowIndex={ rowIndex } rowIndex={ rowIndex }
onRowSelect={ mockOnRowSelect } onRowSelect={ mockOnRowSelect }
/>, { bootstrap4: false } />,
{ bootstrap4: false }
); );
wrapper.find('td').simulate('click'); wrapper.find('td').simulate('click');
}); });
@@ -72,9 +74,7 @@ describe('<SelectionCell />', () => {
it('should calling onRowSelect callback correctly', () => { it('should calling onRowSelect callback correctly', () => {
expect(mockOnRowSelect.calledOnce).toBe(true); expect(mockOnRowSelect.calledOnce).toBe(true);
expect( expect(mockOnRowSelect.calledWith(rowKey, !selected, rowIndex)).toBe(true);
mockOnRowSelect.calledWith(rowKey, !selected, rowIndex)
).toBe(true);
}); });
}); });
@@ -88,7 +88,8 @@ describe('<SelectionCell />', () => {
rowIndex={ rowIndex } rowIndex={ rowIndex }
onRowSelect={ mockOnRowSelect } onRowSelect={ mockOnRowSelect }
disabled disabled
/>, { bootstrap4: false } />,
{ bootstrap4: false }
); );
wrapper.find('td').simulate('click'); wrapper.find('td').simulate('click');
}); });
@@ -111,7 +112,8 @@ describe('<SelectionCell />', () => {
mode="radio" mode="radio"
rowIndex={ rowIndex } rowIndex={ rowIndex }
onRowSelect={ mockOnRowSelect } onRowSelect={ mockOnRowSelect }
/>, { bootstrap4: false } />,
{ bootstrap4: false }
); );
}); });
@@ -132,11 +134,12 @@ describe('<SelectionCell />', () => {
rowIndex={ rowIndex } rowIndex={ rowIndex }
selected selected
onRowSelect={ mockOnRowSelect } onRowSelect={ mockOnRowSelect }
/>, { bootstrap4: false } />,
{ bootstrap4: false }
); );
}); });
it('should be called with correct paramters', () => { it('should be called with correct parameters', () => {
// first click // first click
wrapper.find('td').simulate('click'); wrapper.find('td').simulate('click');
expect(mockOnRowSelect.callCount).toBe(1); expect(mockOnRowSelect.callCount).toBe(1);
@@ -151,12 +154,8 @@ describe('<SelectionCell />', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallowWithContext( wrapper = shallowWithContext(
<SelectionCell <SelectionCell rowKey={ 1 } mode={ mode } rowIndex={ rowIndex } selected={ selected } />,
rowKey={ 1 } { bootstrap4: false }
mode={ mode }
rowIndex={ rowIndex }
selected={ selected }
/>, { bootstrap4: false }
); );
}); });
@@ -165,6 +164,7 @@ describe('<SelectionCell />', () => {
expect(wrapper.find('input')).toHaveLength(1); expect(wrapper.find('input')).toHaveLength(1);
expect(wrapper.find('input').get(0).props.type).toBe(mode); expect(wrapper.find('input').get(0).props.type).toBe(mode);
expect(wrapper.find('input').get(0).props.checked).toBe(selected); expect(wrapper.find('input').get(0).props.checked).toBe(selected);
expect(toJson(wrapper)).toMatchSnapshot();
}); });
describe('when disabled prop give as true', () => { describe('when disabled prop give as true', () => {
@@ -176,7 +176,8 @@ describe('<SelectionCell />', () => {
rowIndex={ rowIndex } rowIndex={ rowIndex }
selected={ selected } selected={ selected }
disabled disabled
/>, { bootstrap4: false } />,
{ bootstrap4: false }
); );
}); });
@@ -198,7 +199,8 @@ describe('<SelectionCell />', () => {
rowIndex={ rowIndex } rowIndex={ rowIndex }
selected={ selected } selected={ selected }
selectionRenderer={ selectionRenderer } selectionRenderer={ selectionRenderer }
/>, { bootstrap4: false } />,
{ bootstrap4: false }
); );
}); });
@@ -219,12 +221,8 @@ describe('<SelectionCell />', () => {
describe('when bootstrap4 context is true', () => { describe('when bootstrap4 context is true', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallowWithContext( wrapper = shallowWithContext(
<SelectionCell <SelectionCell rowKey={ 1 } mode={ mode } rowIndex={ rowIndex } selected={ selected } />,
rowKey={ 1 } { bootstrap4: true }
mode={ mode }
rowIndex={ rowIndex }
selected={ selected }
/>, { bootstrap4: true }
); );
}); });

View File

@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import sinon from 'sinon'; import sinon from 'sinon';
import { shallowWithContext } from '../test-helpers/new-context'; import { shallowWithContext } from '../test-helpers/new-context';
@@ -201,6 +202,7 @@ describe('<CheckBox />', () => {
expect(wrapper.find('input').length).toBe(1); expect(wrapper.find('input').length).toBe(1);
expect(wrapper.find('input').prop('checked')).toBe(checked); expect(wrapper.find('input').prop('checked')).toBe(checked);
expect(wrapper.find('input').prop('type')).toBe('checkbox'); expect(wrapper.find('input').prop('type')).toBe('checkbox');
expect(toJson(wrapper)).toMatchSnapshot();
}); });
}); });
}); });

View File

@@ -2711,6 +2711,12 @@ enzyme-adapter-utils@^1.3.0:
object.assign "^4.1.0" object.assign "^4.1.0"
prop-types "^15.6.0" prop-types "^15.6.0"
enzyme-to-json@3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.3.4.tgz#67c6040e931182f183418af2eb9f4323258aa77f"
dependencies:
lodash "^4.17.4"
enzyme@3.3.0: enzyme@3.3.0:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479" resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479"