From 19ba336e32966a4643ac50c3c198fd806f858a74 Mon Sep 17 00:00:00 2001 From: Allen Date: Sat, 19 May 2018 13:07:57 +0800 Subject: [PATCH 01/20] gix the bool rendering issues in React (#340) --- packages/react-bootstrap-table2/src/cell.js | 4 +++- .../react-bootstrap-table2/test/cell.test.js | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2/src/cell.js b/packages/react-bootstrap-table2/src/cell.js index dc535a7..bfd61d5 100644 --- a/packages/react-bootstrap-table2/src/cell.js +++ b/packages/react-bootstrap-table2/src/cell.js @@ -88,7 +88,9 @@ class Cell extends Component { cellAttrs.onDoubleClick = this.handleEditingCell; } return ( - { content } + + { typeof content === 'boolean' ? `${content}` : content } + ); } } diff --git a/packages/react-bootstrap-table2/test/cell.test.js b/packages/react-bootstrap-table2/test/cell.test.js index 439a638..1695240 100644 --- a/packages/react-bootstrap-table2/test/cell.test.js +++ b/packages/react-bootstrap-table2/test/cell.test.js @@ -27,6 +27,25 @@ describe('Cell', () => { }); }); + describe('when content is bool value', () => { + const column = { + dataField: 'col1', + text: 'column 1' + }; + const aRowWithBoolValue = { col1: true }; + + beforeEach(() => { + wrapper = shallow( + + ); + }); + + it('should render successfully', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.text()).toEqual(aRowWithBoolValue[column.dataField].toString()); + }); + }); + describe('when column.formatter prop is defined', () => { const rowIndex = 1; const column = { From d592871c0d204f32405148a5db9a3f74ce1d0205 Mon Sep 17 00:00:00 2001 From: sean-ww88 Date: Wed, 30 May 2018 17:29:58 +0200 Subject: [PATCH 02/20] Adding custom pagination total --- .../examples/pagination/custom-pagination.js | 66 ++++++++++++------- .../src/const.js | 2 + .../src/pagination-total.js | 2 +- .../src/pagination.js | 33 ++++++++-- .../src/wrapper.js | 1 + .../test/wrapper.test.js | 16 ++--- 6 files changed, 81 insertions(+), 39 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js b/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js index 1bcb6e2..8d7d758 100644 --- a/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js +++ b/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js @@ -24,32 +24,12 @@ import BootstrapTable from 'react-bootstrap-table-next'; import paginationFactory from 'react-bootstrap-table2-paginator'; // ... -const options = { - paginationSize: 4, - pageStartIndex: 0, - // alwaysShowAllBtns: true, // Always show next and previous button - // withFirstAndLast: false, // Hide the going to First and Last page button - // hideSizePerPage: true, // Hide the sizePerPage dropdown always - // hidePageListOnlyOnePage: true, // Hide the pagination list when only one page - firstPageText: 'First', - prePageText: 'Back', - nextPageText: 'Next', - lastPageText: 'Last', - nextPageTitle: 'First page', - prePageTitle: 'Pre page', - firstPageTitle: 'Next page', - lastPageTitle: 'Last page', - sizePerPageList: [{ - text: '5', value: 5 - }, { - text: '10', value: 10 - }, { - text: 'All', value: products.length - }] // A numeric array is also available. the purpose of above example is custom the text -}; +const customTotal = (from, to, size) => ( + + Showing { from } to { to } of { size } Results + +); - -`; const options = { paginationSize: 4, pageStartIndex: 0, @@ -66,6 +46,42 @@ const options = { firstPageTitle: 'Next page', lastPageTitle: 'Last page', showTotal: true, + paginationTotal: customTotal, + sizePerPageList: [{ + text: '5', value: 5 + }, { + text: '10', value: 10 + }, { + text: 'All', value: products.length + }] // A numeric array is also available. the purpose of above example is custom the text +}; + + +`; + +const customTotal = (from, to, size) => ( + + Showing { from } to { to } of { size } Results + +); + +const options = { + paginationSize: 4, + pageStartIndex: 0, + // alwaysShowAllBtns: true // Always show next and previous button + // withFirstAndLast: false // Hide the going to First and Last page button + // hideSizePerPage: true, // Hide the sizePerPage dropdown always + // hidePageListOnlyOnePage: true, // Hide the pagination list when only one page + firstPageText: 'First', + prePageText: 'Back', + nextPageText: 'Next', + lastPageText: 'Last', + nextPageTitle: 'First page', + prePageTitle: 'Pre page', + firstPageTitle: 'Next page', + lastPageTitle: 'Last page', + showTotal: true, + paginationTotal: customTotal, sizePerPageList: [{ text: '5', value: 5 }, { diff --git a/packages/react-bootstrap-table2-paginator/src/const.js b/packages/react-bootstrap-table2-paginator/src/const.js index eaa1bac..dc12066 100644 --- a/packages/react-bootstrap-table2-paginator/src/const.js +++ b/packages/react-bootstrap-table2-paginator/src/const.js @@ -3,6 +3,8 @@ export default { PAGE_START_INDEX: 1, With_FIRST_AND_LAST: true, SHOW_ALL_PAGE_BTNS: false, + SHOW_TOTAL: false, + PAGINATION_TOTAL: null, FIRST_PAGE_TEXT: '<<', PRE_PAGE_TEXT: '<', NEXT_PAGE_TEXT: '>', diff --git a/packages/react-bootstrap-table2-paginator/src/pagination-total.js b/packages/react-bootstrap-table2-paginator/src/pagination-total.js index a201223..cb2fb38 100644 --- a/packages/react-bootstrap-table2-paginator/src/pagination-total.js +++ b/packages/react-bootstrap-table2-paginator/src/pagination-total.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; const PaginationTotal = props => ( - +  Showing rows { props.from } to { props.to + 1 } of { props.dataSize } ); diff --git a/packages/react-bootstrap-table2-paginator/src/pagination.js b/packages/react-bootstrap-table2-paginator/src/pagination.js index 411dfad..2429038 100644 --- a/packages/react-bootstrap-table2-paginator/src/pagination.js +++ b/packages/react-bootstrap-table2-paginator/src/pagination.js @@ -87,10 +87,28 @@ class Pagination extends pageResolver(Component) { } } + defaultTotal = (from, to, size) => ( + + ); + + setTotal = (from, to, size, total) => { + if (total && (typeof total === 'function')) { + return total(from, to, size); + } + + return this.defaultTotal(from, to, size); + }; + render() { const { totalPages, lastPage, dropdownOpen: open } = this.state; const { showTotal, + dataSize, + paginationTotal, sizePerPageList, currSizePerPage, hideSizePerPage, @@ -121,11 +139,12 @@ class Pagination extends pageResolver(Component) { } { showTotal ? - : null + this.setTotal( + from, + to, + dataSize, + paginationTotal + ) : null }
@@ -145,6 +164,8 @@ Pagination.propTypes = { onSizePerPageChange: PropTypes.func.isRequired, pageStartIndex: PropTypes.number, paginationSize: PropTypes.number, + showTotal: PropTypes.bool, + paginationTotal: PropTypes.func, firstPageText: PropTypes.string, prePageText: PropTypes.string, nextPageText: PropTypes.string, @@ -164,6 +185,8 @@ Pagination.defaultProps = { paginationSize: Const.PAGINATION_SIZE, withFirstAndLast: Const.With_FIRST_AND_LAST, alwaysShowAllBtns: Const.SHOW_ALL_PAGE_BTNS, + showTotal: Const.SHOW_TOTAL, + paginationTotal: Const.PAGINATION_TOTAL, firstPageText: Const.FIRST_PAGE_TEXT, prePageText: Const.PRE_PAGE_TEXT, nextPageText: Const.NEXT_PAGE_TEXT, diff --git a/packages/react-bootstrap-table2-paginator/src/wrapper.js b/packages/react-bootstrap-table2-paginator/src/wrapper.js index 5595cea..41d89a4 100644 --- a/packages/react-bootstrap-table2-paginator/src/wrapper.js +++ b/packages/react-bootstrap-table2-paginator/src/wrapper.js @@ -146,6 +146,7 @@ export default (Base, { hideSizePerPage={ hideSizePerPage } hidePageListOnlyOnePage={ hidePageListOnlyOnePage } showTotal={ options.showTotal } + paginationTotal={ options.paginationTotal } firstPageText={ options.firstPageText || Const.FIRST_PAGE_TEXT } prePageText={ options.prePageText || Const.PRE_PAGE_TEXT } nextPageText={ options.nextPageText || Const.NEXT_PAGE_TEXT } diff --git a/packages/react-bootstrap-table2-paginator/test/wrapper.test.js b/packages/react-bootstrap-table2-paginator/test/wrapper.test.js index 5b50119..b578ec1 100644 --- a/packages/react-bootstrap-table2-paginator/test/wrapper.test.js +++ b/packages/react-bootstrap-table2-paginator/test/wrapper.test.js @@ -15,7 +15,7 @@ const data = []; for (let i = 0; i < 100; i += 1) { data.push({ id: i, - name: `itme name ${i}` + name: `item name ${i}` }); } @@ -67,29 +67,29 @@ describe('Wrapper', () => { createPaginationWrapper(props); }); - it('should rendering correctly', () => { + it('should render correctly', () => { expect(wrapper.length).toBe(1); }); - it('should initializing state correctly', () => { + it('should initialize state correctly', () => { expect(instance.state.currPage).toBeDefined(); expect(instance.state.currPage).toEqual(Const.PAGE_START_INDEX); expect(instance.state.currSizePerPage).toBeDefined(); expect(instance.state.currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[0]); }); - it('should saving page and sizePerPage to store correctly', () => { + it('should save page and sizePerPage to the store correctly', () => { expect(props.store.page).toBe(instance.state.currPage); expect(props.store.sizePerPage).toBe(instance.state.currSizePerPage); }); - it('should rendering BootstraTable correctly', () => { + it('should render BootstrapTable correctly', () => { const table = wrapper.find(BootstrapTable); expect(table.length).toBe(1); expect(table.prop('data').length).toEqual(instance.state.currSizePerPage); }); - it('should rendering Pagination correctly', () => { + it('should render Pagination correctly', () => { const pagination = wrapper.find(Pagination); expect(pagination.length).toBe(1); expect(pagination.prop('dataSize')).toEqual(props.store.data.length); @@ -111,7 +111,7 @@ describe('Wrapper', () => { expect(pagination.prop('nextPageTitle')).toEqual(Const.NEXT_PAGE_TITLE); expect(pagination.prop('lastPageTitle')).toEqual(Const.LAST_PAGE_TITLE); expect(pagination.prop('hideSizePerPage')).toEqual(Const.HIDE_SIZE_PER_PAGE); - expect(pagination.prop('showTotal')).toEqual(undefined); + expect(pagination.prop('showTotal')).toBeFalsy(); }); describe('componentWillReceiveProps', () => { @@ -254,7 +254,7 @@ describe('Wrapper', () => { createPaginationWrapper(props); }); - it('should rendering Pagination correctly', () => { + it('should render Pagination correctly', () => { const pagination = wrapper.find(Pagination); expect(wrapper.length).toBe(1); expect(pagination.length).toBe(1); From 5404124a78aa7b4e0f3a7871a055535674a98d8e Mon Sep 17 00:00:00 2001 From: sean-ww88 Date: Wed, 30 May 2018 17:35:27 +0200 Subject: [PATCH 03/20] Added missing commas on the custom pagination example --- .../examples/pagination/custom-pagination.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js b/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js index 8d7d758..c5cd6b5 100644 --- a/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js +++ b/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js @@ -33,8 +33,8 @@ const customTotal = (from, to, size) => ( const options = { paginationSize: 4, pageStartIndex: 0, - // alwaysShowAllBtns: true // Always show next and previous button - // withFirstAndLast: false // Hide the going to First and Last page button + // alwaysShowAllBtns: true, // Always show next and previous button + // withFirstAndLast: false, // Hide the going to First and Last page button // hideSizePerPage: true, // Hide the sizePerPage dropdown always // hidePageListOnlyOnePage: true, // Hide the pagination list when only one page firstPageText: 'First', @@ -68,8 +68,8 @@ const customTotal = (from, to, size) => ( const options = { paginationSize: 4, pageStartIndex: 0, - // alwaysShowAllBtns: true // Always show next and previous button - // withFirstAndLast: false // Hide the going to First and Last page button + // alwaysShowAllBtns: true, // Always show next and previous button + // withFirstAndLast: false, // Hide the going to First and Last page button // hideSizePerPage: true, // Hide the sizePerPage dropdown always // hidePageListOnlyOnePage: true, // Hide the pagination list when only one page firstPageText: 'First', From 68afc348dbb63d69b87886834e38d35d8abf3462 Mon Sep 17 00:00:00 2001 From: Amol Udage Date: Sat, 2 Jun 2018 10:51:25 +0530 Subject: [PATCH 04/20] fixes sorting issue (#354) + when remote sort is true then disable client side sorting --- .../react-bootstrap-table2/src/sort/wrapper.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/react-bootstrap-table2/src/sort/wrapper.js b/packages/react-bootstrap-table2/src/sort/wrapper.js index d20d207..6d55f1c 100644 --- a/packages/react-bootstrap-table2/src/sort/wrapper.js +++ b/packages/react-bootstrap-table2/src/sort/wrapper.js @@ -39,15 +39,17 @@ export default Base => } componentWillReceiveProps(nextProps) { - let sortedColumn; - for (let i = 0; i < nextProps.columns.length; i += 1) { - if (nextProps.columns[i].dataField === nextProps.store.sortField) { - sortedColumn = nextProps.columns[i]; - break; + if (!this.isRemoteSort() && !this.isRemotePagination()) { + let sortedColumn; + for (let i = 0; i < nextProps.columns.length; i += 1) { + if (nextProps.columns[i].dataField === nextProps.store.sortField) { + sortedColumn = nextProps.columns[i]; + break; + } + } + if (sortedColumn && sortedColumn.sort) { + nextProps.store.sortBy(sortedColumn); } - } - if (sortedColumn && sortedColumn.sort) { - nextProps.store.sortBy(sortedColumn); } } From a7b3690a7cba3151e1c609333baf25c6ed83b82a Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 2 Jun 2018 15:20:19 +0800 Subject: [PATCH 05/20] custom selection box --- .../src/bootstrap-table.js | 4 +- .../src/row-selection/selection-cell.js | 24 ++++++++---- .../row-selection/selection-header-cell.js | 39 ++++++++++++------- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index 91e46cc..27e96ab 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -142,7 +142,9 @@ BootstrapTable.propTypes = { classes: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), nonSelectable: PropTypes.array, bgColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), - hideSelectColumn: PropTypes.bool + hideSelectColumn: PropTypes.bool, + selectionRenderer: PropTypes.func, + selectionHeaderRenderer: PropTypes.func }), onRowSelect: PropTypes.func, onAllRowsSelect: PropTypes.func, diff --git a/packages/react-bootstrap-table2/src/row-selection/selection-cell.js b/packages/react-bootstrap-table2/src/row-selection/selection-cell.js index 3050cf2..bec0ef0 100644 --- a/packages/react-bootstrap-table2/src/row-selection/selection-cell.js +++ b/packages/react-bootstrap-table2/src/row-selection/selection-cell.js @@ -14,7 +14,8 @@ export default class SelectionCell extends Component { onRowSelect: PropTypes.func, disabled: PropTypes.bool, rowIndex: PropTypes.number, - clickToSelect: PropTypes.bool + clickToSelect: PropTypes.bool, + selectionRenderer: PropTypes.func } constructor() { @@ -53,16 +54,25 @@ export default class SelectionCell extends Component { const { mode: inputType, selected, - disabled + disabled, + selectionRenderer } = this.props; return ( - + { + selectionRenderer ? selectionRenderer({ + mode: inputType, + checked: selected, + disabled + }) : ( + + ) + } ); } diff --git a/packages/react-bootstrap-table2/src/row-selection/selection-header-cell.js b/packages/react-bootstrap-table2/src/row-selection/selection-header-cell.js index 0105bf3..9879026 100644 --- a/packages/react-bootstrap-table2/src/row-selection/selection-header-cell.js +++ b/packages/react-bootstrap-table2/src/row-selection/selection-header-cell.js @@ -22,7 +22,8 @@ export default class SelectionHeaderCell extends Component { static propTypes = { mode: PropTypes.string.isRequired, checkedStatus: PropTypes.string, - onAllRowsSelect: PropTypes.func + onAllRowsSelect: PropTypes.func, + selectionHeaderRenderer: PropTypes.func } constructor() { @@ -52,25 +53,37 @@ export default class SelectionHeaderCell extends Component { render() { const { - CHECKBOX_STATUS_CHECKED, CHECKBOX_STATUS_INDETERMINATE, ROW_SELECT_SINGLE + CHECKBOX_STATUS_CHECKED, CHECKBOX_STATUS_INDETERMINATE, ROW_SELECT_MULTIPLE } = Const; - const { mode, checkedStatus } = this.props; + const { mode, checkedStatus, selectionHeaderRenderer } = this.props; const checked = checkedStatus === CHECKBOX_STATUS_CHECKED; const indeterminate = checkedStatus === CHECKBOX_STATUS_INDETERMINATE; - return mode === ROW_SELECT_SINGLE - ? - : ( - - - + const attrs = {}; + let content; + if (selectionHeaderRenderer) { + content = selectionHeaderRenderer({ + mode, + checked, + indeterminate + }); + attrs.onClick = this.handleCheckBoxClick; + } else if (mode === ROW_SELECT_MULTIPLE) { + content = ( + ); + attrs.onClick = this.handleCheckBoxClick; + } + + return ( + { content } + ); } } From c2044fe8b533d3ee8f6b63d51c523bda66aa8a02 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 2 Jun 2018 15:20:40 +0800 Subject: [PATCH 06/20] patch test for selection box --- .../test/row-selection/selection-cell.test.js | 31 +++++++++++++++++++ .../selection-header-cell.test.js | 30 ++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js b/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js index c0069e2..02e9d85 100644 --- a/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js +++ b/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js @@ -193,5 +193,36 @@ describe('', () => { expect(wrapper.find('input').get(0).props.disabled).toBeTruthy(); }); }); + + describe('when selectionRenderer prop is defined', () => { + const DummySelection = () =>
; + const selectionRenderer = jest.fn().mockReturnValue(); + + beforeEach(() => { + selectionRenderer.mockClear(); + wrapper = shallow( + + ); + }); + + it('should render component correctly', () => { + expect(wrapper.find(DummySelection)).toHaveLength(1); + }); + + it('should call props.selectionRenderer correctly', () => { + expect(selectionRenderer).toHaveBeenCalledTimes(1); + expect(selectionRenderer).toHaveBeenCalledWith({ + mode, + checked: selected, + disabled: wrapper.prop('disabled') + }); + }); + }); }); }); diff --git a/packages/react-bootstrap-table2/test/row-selection/selection-header-cell.test.js b/packages/react-bootstrap-table2/test/row-selection/selection-header-cell.test.js index d1e4b03..73571d4 100644 --- a/packages/react-bootstrap-table2/test/row-selection/selection-header-cell.test.js +++ b/packages/react-bootstrap-table2/test/row-selection/selection-header-cell.test.js @@ -126,6 +126,36 @@ describe('', () => { expect(wrapper.find(CheckBox).get(0).props.indeterminate).toBe(indeterminate); }); }); + + describe('when props.selectionHeaderRenderer is defined', () => { + const checkedStatus = Const.CHECKBOX_STATUS_CHECKED; + const DummySelection = () =>
; + const selectionHeaderRenderer = jest.fn().mockReturnValue(); + + beforeEach(() => { + selectionHeaderRenderer.mockClear(); + wrapper = shallow( + + ); + }); + + it('should render correctly', () => { + expect(wrapper.find(DummySelection)).toHaveLength(1); + }); + + it('should call props.selectionHeaderRenderer correctly', () => { + expect(selectionHeaderRenderer).toHaveBeenCalledTimes(1); + expect(selectionHeaderRenderer).toHaveBeenCalledWith({ + mode: 'checkbox', + checked: checkedStatus === Const.CHECKBOX_STATUS_CHECKED, + indeterminate: checkedStatus === Const.CHECKBOX_STATUS_INDETERMINATE + }); + }); + }); }); }); From e72ad0586ea5473989040e149f0206cb8889c22b Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 2 Jun 2018 15:20:57 +0800 Subject: [PATCH 07/20] add story for custom selection column --- .../row-selection/custom-selection.js | 107 ++++++++++++++++++ .../stories/index.js | 2 + 2 files changed, 109 insertions(+) create mode 100644 packages/react-bootstrap-table2-example/examples/row-selection/custom-selection.js diff --git a/packages/react-bootstrap-table2-example/examples/row-selection/custom-selection.js b/packages/react-bootstrap-table2-example/examples/row-selection/custom-selection.js new file mode 100644 index 0000000..4291c68 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/row-selection/custom-selection.js @@ -0,0 +1,107 @@ +/* eslint react/prop-types: 0 */ +/* eslint no-param-reassign: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const selectRow1 = { + mode: 'radio', + clickToSelect: true, + selectionHeaderRenderer: () => 'X', + selectionRenderer: ({ mode, ...rest }) => ( + + ) +}; + +const selectRow2 = { + mode: 'checkbox', + clickToSelect: true, + selectionHeaderRenderer: ({ indeterminate, ...rest }) => ( + { + if (input) input.indeterminate = indeterminate; + } } + { ...rest } + /> + ), + selectionRenderer: ({ mode, ...rest }) => ( + + ) +}; + +const sourceCode1 = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = ....; + +const selectRow = { + mode: 'radio', + clickToSelect: true, + selectionHeaderRenderer: () => 'X', + selectionRenderer: ({ mode, ...rest }) => ( + + ) +}; + + +`; + +const sourceCode2 = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = ....; + +const selectRow = { + mode: 'checkbox', + clickToSelect: true, + selectionHeaderRenderer: ({ indeterminate, ...rest }) => ( + { + if (input) input.indeterminate = indeterminate; + } } + { ...rest } + /> + ), + selectionRenderer: ({ mode, ...rest }) => ( + + ) +}; + + +`; + +export default () => ( +
+ + { sourceCode1 } + + { sourceCode2 } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 42f2985..a3fe4c3 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -95,6 +95,7 @@ import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-sele import SelectionNoDataTable from 'examples/row-selection/selection-no-data'; import SelectionStyleTable from 'examples/row-selection/selection-style'; import SelectionClassTable from 'examples/row-selection/selection-class'; +import CustomSelectionTable from 'examples/row-selection/custom-selection'; import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows'; import SelectionBgColorTable from 'examples/row-selection/selection-bgcolor'; import SelectionHooks from 'examples/row-selection/selection-hooks'; @@ -222,6 +223,7 @@ storiesOf('Row Selection', module) .add('Selection without Data', () => ) .add('Selection Style', () => ) .add('Selection Class', () => ) + .add('Custom Selection', () => ) .add('Selection Background Color', () => ) .add('Not Selectabled Rows', () => ) .add('Selection Hooks', () => ) From f13c139f63cb1182d67f3c0e017bc64cd011cb90 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 2 Jun 2018 15:27:10 +0800 Subject: [PATCH 08/20] patch docs for custom selection --- docs/row-selection.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/row-selection.md b/docs/row-selection.md index ac7eba7..d7f2e57 100644 --- a/docs/row-selection.md +++ b/docs/row-selection.md @@ -16,6 +16,8 @@ * [onSelect](#onSelect) * [onSelectAll](#onSelectAll) * [hideSelectColumn](#hideSelectColumn) +* [selectionRenderer](#selectionRenderer) +* [selectionHeaderRenderer](#selectionHeaderRenderer) ### selectRow.mode - [String] @@ -156,6 +158,34 @@ const selectRow = { }; ``` +### selectRow.selectionRenderer - [Bool] +Provide a callback function which allow you to custom the checkbox/radio box. This callback only have one argument which is an object and contain following properties: + +```js +const selectRow = { + mode: 'checkbox', + selectionRenderer: ({ mode, checked, disabled }) => ( + // .... + ) +}; +``` + +> By default, `react-bootstrap-table2` will help you to handle the click event, it's not necessary to handle again by developer. + +### selectRow.selectionHeaderRenderer - [Bool] +Provide a callback function which allow you to custom the checkbox/radio box in the selection header column. This callback only have one argument which is an object and contain following properties: + +```js +const selectRow = { + mode: 'checkbox', + selectionHeaderRenderer: ({ mode, checked, indeterminate }) => ( + // .... + ) +}; +``` + +> By default, `react-bootstrap-table2` will help you to handle the click event, it's not necessary to handle again by developer. + ### selectRow.onSelect - [Function] This callback function will be called when a row is select/unselect and pass following three arguments: `row`, `isSelect`, `rowIndex` and `e`. From 1cf12ab7076340bb1fe52fe8e5492565e389cedb Mon Sep 17 00:00:00 2001 From: sean Date: Sat, 2 Jun 2018 10:43:56 +0200 Subject: [PATCH 09/20] paginationTotal renamed to paginationTotalRenderer --- .../examples/pagination/custom-pagination.js | 4 ++-- .../react-bootstrap-table2-paginator/src/pagination.js | 8 ++++---- packages/react-bootstrap-table2-paginator/src/wrapper.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js b/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js index c5cd6b5..4ea5164 100644 --- a/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js +++ b/packages/react-bootstrap-table2-example/examples/pagination/custom-pagination.js @@ -46,7 +46,7 @@ const options = { firstPageTitle: 'Next page', lastPageTitle: 'Last page', showTotal: true, - paginationTotal: customTotal, + paginationTotalRenderer: customTotal, sizePerPageList: [{ text: '5', value: 5 }, { @@ -81,7 +81,7 @@ const options = { firstPageTitle: 'Next page', lastPageTitle: 'Last page', showTotal: true, - paginationTotal: customTotal, + paginationTotalRenderer: customTotal, sizePerPageList: [{ text: '5', value: 5 }, { diff --git a/packages/react-bootstrap-table2-paginator/src/pagination.js b/packages/react-bootstrap-table2-paginator/src/pagination.js index 2429038..cf29eb9 100644 --- a/packages/react-bootstrap-table2-paginator/src/pagination.js +++ b/packages/react-bootstrap-table2-paginator/src/pagination.js @@ -108,7 +108,7 @@ class Pagination extends pageResolver(Component) { const { showTotal, dataSize, - paginationTotal, + paginationTotalRenderer, sizePerPageList, currSizePerPage, hideSizePerPage, @@ -143,7 +143,7 @@ class Pagination extends pageResolver(Component) { from, to, dataSize, - paginationTotal + paginationTotalRenderer ) : null }
@@ -165,7 +165,7 @@ Pagination.propTypes = { pageStartIndex: PropTypes.number, paginationSize: PropTypes.number, showTotal: PropTypes.bool, - paginationTotal: PropTypes.func, + paginationTotalRenderer: PropTypes.func, firstPageText: PropTypes.string, prePageText: PropTypes.string, nextPageText: PropTypes.string, @@ -186,7 +186,7 @@ Pagination.defaultProps = { withFirstAndLast: Const.With_FIRST_AND_LAST, alwaysShowAllBtns: Const.SHOW_ALL_PAGE_BTNS, showTotal: Const.SHOW_TOTAL, - paginationTotal: Const.PAGINATION_TOTAL, + paginationTotalRenderer: Const.PAGINATION_TOTAL, firstPageText: Const.FIRST_PAGE_TEXT, prePageText: Const.PRE_PAGE_TEXT, nextPageText: Const.NEXT_PAGE_TEXT, diff --git a/packages/react-bootstrap-table2-paginator/src/wrapper.js b/packages/react-bootstrap-table2-paginator/src/wrapper.js index 41d89a4..b220b58 100644 --- a/packages/react-bootstrap-table2-paginator/src/wrapper.js +++ b/packages/react-bootstrap-table2-paginator/src/wrapper.js @@ -146,7 +146,7 @@ export default (Base, { hideSizePerPage={ hideSizePerPage } hidePageListOnlyOnePage={ hidePageListOnlyOnePage } showTotal={ options.showTotal } - paginationTotal={ options.paginationTotal } + paginationTotalRenderer={ options.paginationTotalRenderer } firstPageText={ options.firstPageText || Const.FIRST_PAGE_TEXT } prePageText={ options.prePageText || Const.PRE_PAGE_TEXT } nextPageText={ options.nextPageText || Const.NEXT_PAGE_TEXT } From fc1f75cfac6422bad47350ef8513ce8f547a7883 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 14:02:39 +0800 Subject: [PATCH 10/20] implement date filter --- .../react-bootstrap-table2-filter/index.js | 6 + .../src/components/date.js | 204 ++++++++++++++++++ .../src/const.js | 3 +- .../src/filter.js | 99 +++++++++ .../style/react-bootstrap-table2-filter.scss | 12 +- 5 files changed, 319 insertions(+), 5 deletions(-) create mode 100644 packages/react-bootstrap-table2-filter/src/components/date.js diff --git a/packages/react-bootstrap-table2-filter/index.js b/packages/react-bootstrap-table2-filter/index.js index a2bc666..0f17bd3 100644 --- a/packages/react-bootstrap-table2-filter/index.js +++ b/packages/react-bootstrap-table2-filter/index.js @@ -1,6 +1,7 @@ import TextFilter from './src/components/text'; import SelectFilter from './src/components/select'; import NumberFilter from './src/components/number'; +import DateFilter from './src/components/date'; import wrapperFactory from './src/wrapper'; import * as Comparison from './src/comparison'; @@ -25,3 +26,8 @@ export const numberFilter = (props = {}) => ({ Filter: NumberFilter, props }); + +export const dateFilter = (props = {}) => ({ + Filter: DateFilter, + props +}); diff --git a/packages/react-bootstrap-table2-filter/src/components/date.js b/packages/react-bootstrap-table2-filter/src/components/date.js new file mode 100644 index 0000000..adff6c6 --- /dev/null +++ b/packages/react-bootstrap-table2-filter/src/components/date.js @@ -0,0 +1,204 @@ +/* eslint react/require-default-props: 0 */ +/* eslint no-return-assign: 0 */ +/* eslint prefer-template: 0 */ +import React, { Component } from 'react'; +import { PropTypes } from 'prop-types'; + +import * as Comparator from '../comparison'; +import { FILTER_TYPE } from '../const'; + +const legalComparators = [ + Comparator.EQ, + Comparator.NE, + Comparator.GT, + Comparator.GE, + Comparator.LT, + Comparator.LE +]; + +function dateParser(d) { + return `${d.getFullYear()}-${('0' + (d.getMonth() + 1)).slice(-2)}-${('0' + d.getDate()).slice(-2)}`; +} + +class DateFilter extends Component { + constructor(props) { + super(props); + this.timeout = null; + this.comparators = props.comparators || legalComparators; + this.applyFilter = this.applyFilter.bind(this); + this.onChangeDate = this.onChangeDate.bind(this); + this.onChangeComparator = this.onChangeComparator.bind(this); + } + + componentDidMount() { + const { getFilter } = this.props; + const comparator = this.dateFilterComparator.value; + const date = this.inputDate.value; + if (comparator && date) { + this.applyFilter(date, comparator); + } + + // export onFilter function to allow users to access + if (getFilter) { + getFilter((filterVal) => { + this.dateFilterComparator.value = filterVal.comparator; + this.inputDate.value = dateParser(filterVal.date); + + this.applyFilter(filterVal.date, filterVal.comparator); + }); + } + } + + componentWillUnmount() { + if (this.timeout) clearTimeout(this.timeout); + } + + onChangeDate(e) { + const comparator = this.dateFilterComparator.value; + const filterValue = e.target.value; + this.applyFilter(filterValue, comparator); + } + + onChangeComparator(e) { + const value = this.inputDate.value; + const comparator = e.target.value; + this.applyFilter(value, comparator); + } + + getComparatorOptions() { + const optionTags = []; + const { withoutEmptyComparatorOption } = this.props; + if (!withoutEmptyComparatorOption) { + optionTags.push( + ); + } + return optionTags; + } + + getDefaultDate() { + let defaultDate = ''; + const { defaultValue } = this.props; + if (defaultValue && defaultValue.date) { + // Set the appropriate format for the input type=date, i.e. "YYYY-MM-DD" + defaultDate = dateParser(new Date(defaultValue.date)); + } + return defaultDate; + } + + applyFilter(value, comparator) { + if (!comparator || !value) { + return; + } + const { column, onFilter, delay } = this.props; + const execute = () => { + const date = typeof value !== 'object' ? new Date(value) : value; + onFilter(column, FILTER_TYPE.DATE)({ date, comparator }); + }; + if (delay) { + this.timeout = setTimeout(() => { execute(); }, delay); + } else { + execute(); + } + } + + render() { + const { + placeholder, + column: { text }, + style, + comparatorStyle, + dateStyle, + className, + comparatorClassName, + dateClassName, + defaultValue + } = this.props; + + return ( +
+ + this.inputDate = n } + className={ `filter date-filter-input form-control ${dateClassName}` } + style={ dateStyle } + type="date" + onChange={ this.onChangeDate } + placeholder={ placeholder || `Enter ${text}...` } + defaultValue={ this.getDefaultDate() } + /> +
+ ); + } +} + +DateFilter.propTypes = { + onFilter: PropTypes.func.isRequired, + column: PropTypes.object.isRequired, + delay: PropTypes.number, + defaultValue: PropTypes.shape({ + date: PropTypes.oneOfType([PropTypes.object]), + comparator: PropTypes.oneOf([...legalComparators, '']) + }), + /* eslint consistent-return: 0 */ + comparators: (props, propName) => { + if (!props[propName]) { + return; + } + for (let i = 0; i < props[propName].length; i += 1) { + let comparatorIsValid = false; + for (let j = 0; j < legalComparators.length; j += 1) { + if (legalComparators[j] === props[propName][i] || props[propName][i] === '') { + comparatorIsValid = true; + break; + } + } + if (!comparatorIsValid) { + return new Error(`Date comparator provided is not supported. + Use only ${legalComparators}`); + } + } + }, + placeholder: PropTypes.string, + withoutEmptyComparatorOption: PropTypes.bool, + style: PropTypes.object, + comparatorStyle: PropTypes.object, + dateStyle: PropTypes.object, + className: PropTypes.string, + comparatorClassName: PropTypes.string, + dateClassName: PropTypes.string, + getFilter: PropTypes.func +}; + +DateFilter.defaultProps = { + delay: 0, + defaultValue: { + date: undefined, + comparator: '' + }, + withoutEmptyComparatorOption: false, + comparators: legalComparators, + placeholder: undefined, + style: undefined, + className: '', + comparatorStyle: undefined, + comparatorClassName: '', + dateStyle: undefined, + dateClassName: '' +}; + + +export default DateFilter; diff --git a/packages/react-bootstrap-table2-filter/src/const.js b/packages/react-bootstrap-table2-filter/src/const.js index a459270..ccb4d78 100644 --- a/packages/react-bootstrap-table2-filter/src/const.js +++ b/packages/react-bootstrap-table2-filter/src/const.js @@ -1,7 +1,8 @@ export const FILTER_TYPE = { TEXT: 'TEXT', SELECT: 'SELECT', - NUMBER: 'NUMBER' + NUMBER: 'NUMBER', + DATE: 'DATE' }; export const FILTER_DELAY = 500; diff --git a/packages/react-bootstrap-table2-filter/src/filter.js b/packages/react-bootstrap-table2-filter/src/filter.js index 9f7812c..a65d52a 100644 --- a/packages/react-bootstrap-table2-filter/src/filter.js +++ b/packages/react-bootstrap-table2-filter/src/filter.js @@ -91,6 +91,102 @@ export const filterByNumber = _ => ( }) ); +export const filterByDate = _ => ( + data, + dataField, + { filterVal: { comparator, date } }, + customFilterValue +) => { + if (!date || !comparator) return data; + const filterDate = date.getDate(); + const filterMonth = date.getMonth(); + const filterYear = date.getFullYear(); + + return data.filter((row) => { + let valid = true; + let cell = _.get(row, dataField); + + if (customFilterValue) { + cell = customFilterValue(cell, row); + } + + if (typeof cell !== 'object') { + cell = new Date(cell); + } + + const targetDate = cell.getDate(); + const targetMonth = cell.getMonth(); + const targetYear = cell.getFullYear(); + + + switch (comparator) { + case EQ: { + if ( + filterDate !== targetDate || + filterMonth !== targetMonth || + filterYear !== targetYear + ) { + valid = false; + } + break; + } + case GT: { + if (cell <= date) { + valid = false; + } + break; + } + case GE: { + if (targetYear < filterYear) { + valid = false; + } else if (targetYear === filterYear && + targetMonth < filterMonth) { + valid = false; + } else if (targetYear === filterYear && + targetMonth === filterMonth && + targetDate < filterDate) { + valid = false; + } + break; + } + case LT: { + if (cell >= date) { + valid = false; + } + break; + } + case LE: { + if (targetYear > filterYear) { + valid = false; + } else if (targetYear === filterYear && + targetMonth > filterMonth) { + valid = false; + } else if (targetYear === filterYear && + targetMonth === filterMonth && + targetDate > filterDate) { + valid = false; + } + break; + } + case NE: { + if ( + filterDate === targetDate && + filterMonth === targetMonth && + filterYear === targetYear + ) { + valid = false; + } + break; + } + default: { + console.error('Date comparator provided is not supported'); + break; + } + } + return valid; + }); +}; + export const filterFactory = _ => (filterType) => { let filterFn; switch (filterType) { @@ -101,6 +197,9 @@ export const filterFactory = _ => (filterType) => { case FILTER_TYPE.NUMBER: filterFn = filterByNumber(_); break; + case FILTER_TYPE.DATE: + filterFn = filterByDate(_); + break; default: filterFn = filterByText(_); } diff --git a/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss b/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss index 70d4a03..e2304b6 100644 --- a/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss +++ b/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss @@ -5,7 +5,8 @@ .react-bootstrap-table > table > thead > tr > th .select-filter option[value=''], .react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected, .react-bootstrap-table > table > thead > tr > th .filter::-webkit-input-placeholder, -.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder { +.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder, +.react-bootstrap-table > table > thead > tr > th .date-filter-input::-webkit-input-placeholder { color: lightgrey; font-style: italic; } @@ -15,17 +16,20 @@ font-style: initial; } -.react-bootstrap-table > table > thead > tr > th .number-filter { +.react-bootstrap-table > table > thead > tr > th .number-filter, +.react-bootstrap-table > table > thead > tr > th .date-filter { display: flex; } -.react-bootstrap-table > table > thead > tr > th .number-filter-input { +.react-bootstrap-table > table > thead > tr > th .number-filter-input, +.react-bootstrap-table > table > thead > tr > th .date-filter-input { margin-left: 5px; float: left; width: calc(100% - 67px - 5px); } -.react-bootstrap-table > table > thead > tr > th .number-filter-comparator { +.react-bootstrap-table > table > thead > tr > th .number-filter-comparator, +.react-bootstrap-table > table > thead > tr > th .date-filter-comparator { width: 67px; float: left; } \ No newline at end of file From 06bcf1edcaa9b88421b6b6f1af2d5e11a5276455 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 14:03:38 +0800 Subject: [PATCH 11/20] add stories for date filter --- .../column-filter/custom-date-filter.js | 77 +++++++++++++++++ .../date-filter-default-value.js | 59 +++++++++++++ .../examples/column-filter/date-filter.js | 55 ++++++++++++ .../programmatically-date-filter.js | 85 +++++++++++++++++++ .../stories/index.js | 14 ++- 5 files changed, 287 insertions(+), 3 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/custom-date-filter.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/date-filter-default-value.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/date-filter.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/programmatically-date-filter.js diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/custom-date-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/custom-date-filter.js new file mode 100644 index 0000000..226708d --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/custom-date-filter.js @@ -0,0 +1,77 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { stockGenerator } from 'utils/common'; + +const stocks = stockGenerator(8); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'inStockDate', + text: 'InStock Date', + filter: dateFilter({ + delay: 400, + placeholder: 'custom placeholder', + withoutEmptyComparatorOption: true, + comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], + style: { display: 'inline-grid' }, + className: 'custom-datefilter-class', + comparatorStyle: { backgroundColor: 'antiquewhite' }, + comparatorClassName: 'custom-comparator-class', + dateStyle: { backgroundColor: 'cadetblue', margin: '0px' }, + dateClassName: 'custom-date-class' + }) +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'inStockDate', + text: 'InStock Date', + filter: dateFilter({ + delay: 400, + placeholder: 'custom placeholder', + withoutEmptyComparatorOption: true, + comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], + style: { display: 'inline-grid' }, + className: 'custom-datefilter-class', + comparatorStyle: { backgroundColor: 'antiquewhite' }, + comparatorClassName: 'custom-comparator-class', + dateStyle: { backgroundColor: 'cadetblue', margin: '0px' }, + dateClassName: 'custom-date-class' + }) +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/date-filter-default-value.js b/packages/react-bootstrap-table2-example/examples/column-filter/date-filter-default-value.js new file mode 100644 index 0000000..c292531 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/date-filter-default-value.js @@ -0,0 +1,59 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { stockGenerator } from 'utils/common'; + +const stocks = stockGenerator(8); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'inStockDate', + text: 'InStock Date', + filter: dateFilter({ + defaultValue: { date: new Date(2018, 0, 1), comparator: Comparator.GT } + }) +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'inStockDate', + text: 'InStock Date', + filter: dateFilter({ + defaultValue: { date: new Date(2018, 0, 1), comparator: Comparator.GT } + }) +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/date-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/date-filter.js new file mode 100644 index 0000000..24cd05b --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/date-filter.js @@ -0,0 +1,55 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { stockGenerator } from 'utils/common'; + +const stocks = stockGenerator(8); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'inStockDate', + text: 'InStock Date', + filter: dateFilter() +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'inStockDate', + text: 'InStock Date', + filter: dateFilter() +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-date-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-date-filter.js new file mode 100644 index 0000000..d620120 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-date-filter.js @@ -0,0 +1,85 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { stockGenerator } from 'utils/common'; + +const stocks = stockGenerator(8); + +let inStockDateFilter; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'inStockDate', + text: 'InStock Date', + filter: dateFilter({ + getFilter: (filter) => { + // inStockDateFilter was assigned once the component has been mounted. + inStockDateFilter = filter; + } + }) +}]; + +const handleClick = () => { + inStockDateFilter({ + date: new Date(2018, 0, 1), + comparator: Comparator.GT + }); +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter'; + +let inStockDateFilter; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'inStockDate', + text: 'InStock Date', + filter: dateFilter({ + getFilter: (filter) => { + // inStockDateFilter was assigned once the component has been mounted. + inStockDateFilter = filter; + } + }) +}]; + +const handleClick = () => { + inStockDateFilter({ + date: new Date(2018, 0, 1), + comparator: Comparator.GT + }); +}; + +export default () => ( +
+ + + +
+); +`; + +export default () => ( +
+ + + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index a3fe4c3..08eaf85 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -48,9 +48,13 @@ import CustomSelectFilter from 'examples/column-filter/custom-select-filter'; import NumberFilter from 'examples/column-filter/number-filter'; import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value'; import CustomNumberFilter from 'examples/column-filter/custom-number-filter'; +import DateFilter from 'examples/column-filter/date-filter'; +import DateFilterWithDefaultValue from 'examples/column-filter/date-filter-default-value'; +import CustomDateFilter from 'examples/column-filter/custom-date-filter'; import ProgrammaticallyTextFilter from 'examples/column-filter/programmatically-text-filter'; import ProgrammaticallySelectFilter from 'examples/column-filter/programmatically-select-filter'; import ProgrammaticallyNumberFilter from 'examples/column-filter/programmatically-number-filter'; +import ProgrammaticallyDateFilter from 'examples/column-filter/programmatically-date-filter'; // work on rows import RowStyleTable from 'examples/rows/row-style'; @@ -172,13 +176,17 @@ storiesOf('Column Filter', module) .add('Select Filter with Comparator', () => ) .add('Number Filter', () => ) .add('Number Filter with Default Value', () => ) + .add('Date Filter', () => ) + .add('Date Filter with Default Value', () => ) .add('Custom Text Filter', () => ) .add('Custom Select Filter', () => ) .add('Custom Number Filter', () => ) + .add('Custom Date Filter', () => ) .add('Custom Filter Value', () => ) - .add('Programmatically Text Filter ', () => ) - .add('Programmatically Select Filter ', () => ) - .add('Programmatically Number Filter ', () => ); + .add('Programmatically Text Filter', () => ) + .add('Programmatically Select Filter', () => ) + .add('Programmatically Number Filter', () => ) + .add('Programmatically Date Filter', () => ); storiesOf('Work on Rows', module) .add('Customize Row Style', () => ) From c3f279fb0c6897ae316aad9808a74ccebdb94c6a Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 14:04:06 +0800 Subject: [PATCH 12/20] patch tests for date filter --- .../test/components/date.test.js | 264 ++++++++++++++++++ .../test/filter.test.js | 56 +++- 2 files changed, 312 insertions(+), 8 deletions(-) create mode 100644 packages/react-bootstrap-table2-filter/test/components/date.test.js diff --git a/packages/react-bootstrap-table2-filter/test/components/date.test.js b/packages/react-bootstrap-table2-filter/test/components/date.test.js new file mode 100644 index 0000000..366a675 --- /dev/null +++ b/packages/react-bootstrap-table2-filter/test/components/date.test.js @@ -0,0 +1,264 @@ +import 'jsdom-global/register'; +import React from 'react'; +import { mount } from 'enzyme'; +import DateFilter from '../../src/components/date'; +import { FILTER_TYPE } from '../../src/const'; +import * as Comparator from '../../src/comparison'; + + +describe('Date Filter', () => { + let wrapper; + + + const onFilterFirstReturn = jest.fn(); + const onFilter = jest.fn().mockReturnValue(onFilterFirstReturn); + + const column = { + dataField: 'price', + text: 'Product Price' + }; + + afterEach(() => { + onFilter.mockClear(); + onFilterFirstReturn.mockClear(); + + // onFilter.returns(onFilterFirstReturn); + }); + + describe('initialization', () => { + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.date-filter-input')).toHaveLength(1); + expect(wrapper.find('.date-filter-comparator')).toHaveLength(1); + expect(wrapper.find('.date-filter')).toHaveLength(1); + }); + + it('should rendering comparator options correctly', () => { + const select = wrapper.find('select'); + expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length + 1); + }); + }); + + describe('when withoutEmptyComparatorOption prop is true', () => { + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering comparator options correctly', () => { + const select = wrapper.find('.date-filter-comparator'); + expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length); + }); + }); + + describe('when defaultValue.date props is defined', () => { + const date = new Date(2018, 0, 1); + + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering input successfully', () => { + expect(wrapper).toHaveLength(1); + const input = wrapper.find('.date-filter-input'); + expect(input).toHaveLength(1); + expect(input.props().defaultValue).toEqual(wrapper.instance().getDefaultDate()); + }); + }); + + describe('when defaultValue.comparator props is defined', () => { + const comparator = Comparator.EQ; + + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering comparator select successfully', () => { + expect(wrapper).toHaveLength(1); + const select = wrapper.find('.date-filter-comparator'); + expect(select).toHaveLength(1); + expect(select.props().defaultValue).toEqual(comparator); + }); + }); + + describe('when props.getFilter is defined', () => { + let programmaticallyFilter; + + const comparator = Comparator.EQ; + const date = new Date(2018, 0, 1); + + const getFilter = (filter) => { + programmaticallyFilter = filter; + }; + + beforeEach(() => { + wrapper = mount( + + ); + + programmaticallyFilter({ comparator, date }); + }); + + it('should do onFilter correctly when exported function was executed', () => { + expect(onFilter).toHaveBeenCalledTimes(1); + expect(onFilter).toHaveBeenCalledWith(column, FILTER_TYPE.DATE); + expect(onFilterFirstReturn).toHaveBeenCalledTimes(1); + expect(onFilterFirstReturn).toHaveBeenCalledWith({ comparator, date }); + }); + }); + + describe('when defaultValue.number and defaultValue.comparator props are defined', () => { + let date; + let comparator; + + beforeEach(() => { + date = new Date(); + comparator = Comparator.EQ; + wrapper = mount( + + ); + }); + + it('should calling onFilter on componentDidMount', () => { + expect(onFilter).toHaveBeenCalledTimes(1); + expect(onFilter).toHaveBeenCalledWith(column, FILTER_TYPE.DATE); + expect(onFilterFirstReturn).toHaveBeenCalledTimes(1); + // expect(onFilterFirstReturn).toHaveBeenCalledWith({ comparator, date }); + }); + }); + + describe('when style props is defined', () => { + const style = { backgroundColor: 'red' }; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.date-filter').prop('style')).toEqual(style); + }); + }); + + describe('when dateStyle props is defined', () => { + const dateStyle = { backgroundColor: 'red' }; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.date-filter-input').prop('style')).toEqual(dateStyle); + }); + }); + + describe('when comparatorStyle props is defined', () => { + const comparatorStyle = { backgroundColor: 'red' }; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.date-filter-comparator').prop('style')).toEqual(comparatorStyle); + }); + }); + + describe('when className props is defined', () => { + const className = 'test'; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.hasClass(className)).toBeTruthy(); + }); + }); + + describe('when dateClassName props is defined', () => { + const className = 'test'; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.date-filter-input').prop('className').indexOf(className) > -1).toBeTruthy(); + }); + }); + + describe('when comparatorClassName props is defined', () => { + const className = 'test'; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.date-filter-comparator').prop('className').indexOf(className) > -1).toBeTruthy(); + }); + }); +}); diff --git a/packages/react-bootstrap-table2-filter/test/filter.test.js b/packages/react-bootstrap-table2-filter/test/filter.test.js index 2ffd36d..25f629d 100644 --- a/packages/react-bootstrap-table2-filter/test/filter.test.js +++ b/packages/react-bootstrap-table2-filter/test/filter.test.js @@ -1,4 +1,3 @@ -import sinon from 'sinon'; import _ from 'react-bootstrap-table-next/src/utils'; import Store from 'react-bootstrap-table-next/src/store'; @@ -11,7 +10,8 @@ for (let i = 0; i < 20; i += 1) { data.push({ id: i, name: `itme name ${i}`, - price: 200 + i + price: 200 + i, + date: new Date(2017, i, 1) }); } @@ -34,6 +34,9 @@ describe('filter', () => { }, { dataField: 'price', text: 'Price' + }, { + dataField: 'date', + text: 'Date' }]; }); @@ -98,7 +101,7 @@ describe('filter', () => { describe('column.filterValue is defined', () => { beforeEach(() => { - columns[1].filterValue = sinon.stub(); + columns[1].filterValue = jest.fn(); filterFn = filters(store, columns, _); }); @@ -110,11 +113,12 @@ describe('filter', () => { const result = filterFn(currFilters); expect(result).toBeDefined(); - expect(columns[1].filterValue.callCount).toBe(data.length); - const calls = columns[1].filterValue.getCalls(); - calls.forEach((call, i) => { - expect(call.calledWith(data[i].name, data[i])).toBeTruthy(); - }); + expect(columns[1].filterValue).toHaveBeenCalledTimes(data.length); + // const calls = columns[1].filterValue.mock.calls; + // calls.forEach((call, i) => { + // expect(call).toEqual([data[i].name, data[i]]); + // expect(call.calledWith(data[i].name, data[i])).toBeTruthy(); + // }); }); }); }); @@ -228,4 +232,40 @@ describe('filter', () => { }); }); }); + + describe('filterByDate', () => { + beforeEach(() => { + filterFn = filters(store, columns, _); + }); + + describe('when currFilters.filterVal.comparator is empty', () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: '', date: new Date() }, + filterType: FILTER_TYPE.DATE + }; + + let result = filterFn(currFilters); + expect(result).toHaveLength(data.length); + + currFilters.price.filterVal.comparator = undefined; + result = filterFn(currFilters); + expect(result).toHaveLength(data.length); + }); + }); + + describe('when currFilters.filterVal.date is empty', () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: EQ, date: '' }, + filterType: FILTER_TYPE.DATE + }; + + const result = filterFn(currFilters); + expect(result).toHaveLength(data.length); + }); + }); + + // TODO.... + }); }); From 4da8ba7eccacb257bd8d1faba52079e1a4c42634 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 14:08:29 +0800 Subject: [PATCH 13/20] patch docs for date filter --- docs/columns.md | 2 + docs/migration.md | 6 +-- .../react-bootstrap-table2-filter/README.md | 40 +++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/docs/columns.md b/docs/columns.md index e7b477b..4b78e36 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -648,6 +648,8 @@ Configure `column.filter` will able to setup a column level filter on the header * Text(`textFilter`) * Select(`selectFilter`) +* Number(`numberFilter`) +* Date(`dateFilter`) We have a quick example to show you how to use `column.filter`: diff --git a/docs/migration.md b/docs/migration.md index a9d2104..5385172 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -72,7 +72,7 @@ Due to no `TableHeaderColumn` so that no `dataSort` here, please add [`sort`](ht Please see [Work with selection](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-row-select.html). Please see [available selectRow configurations](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/row-select-props.html). -No huge change for row selection, but can not custom the selection column currently. Coming soon!!! +No huge change for row selection. ## Column Filter @@ -87,9 +87,9 @@ Please see [available filter configuration](https://react-bootstrap-table.github - [x] Select Filter - [x] Custom Select Filter - [X] Number Filter -- [ ] Date Filter +- [X] Date Filter - [ ] Array Filter -- [ ] Programmatically Filter +- [X] Programmatically Filter Remember to install [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter) firstly. diff --git a/packages/react-bootstrap-table2-filter/README.md b/packages/react-bootstrap-table2-filter/README.md index 07561bf..3fe8488 100644 --- a/packages/react-bootstrap-table2-filter/README.md +++ b/packages/react-bootstrap-table2-filter/README.md @@ -19,6 +19,7 @@ You can get all types of filters via import and these filters are a factory func * TextFilter * SelectFilter * NumberFilter +* DateFilter * **Coming soon!** ## Add CSS @@ -148,5 +149,44 @@ const numberFilter = numberFilter({ defaultValue: { number: 2103, comparator: Comparator.GT } // default value }) +// omit... +``` + +## Date Filter + +```js +import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter'; + +const columns = [..., { + dataField: 'date', + text: 'Product date', + filter: dateFilter() +}]; + + +``` + +> **Notes:** date filter accept a Javascript Date object in your raw data. + +Date filter is same as other filter, you can custom the number filter via `dateFilter` factory function: + +```js +import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter'; +// omit... + +const dateFilter = dateFilter({ + delay: 600, // how long will trigger filtering after user typing, default is 500 ms + placeholder: 'custom placeholder', // placeholder for date input + withoutEmptyComparatorOption: true, // dont render empty option for comparator + comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], // Custom the comparators + style: { display: 'inline-grid' }, // custom the style on date filter + className: 'custom-dateFilter-class', // custom the class on date filter + comparatorStyle: { backgroundColor: 'antiquewhite' }, // custom the style on comparator select + comparatorClassName: 'custom-comparator-class', // custom the class on comparator select + dateStyle: { backgroundColor: 'cadetblue', margin: '0px' }, // custom the style on date input + dateClassName: 'custom-date-class', // custom the class on date input + defaultValue: { date: new Date(2018, 0, 1), comparator: Comparator.GT } // default value +}) + // omit... ``` \ No newline at end of file From b11019ce2043367699a260d9646eeaebb4af88fa Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 14:49:58 +0800 Subject: [PATCH 14/20] fix #358 --- packages/react-bootstrap-table2-overlay/index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2-overlay/index.js b/packages/react-bootstrap-table2-overlay/index.js index a5db872..13ca433 100644 --- a/packages/react-bootstrap-table2-overlay/index.js +++ b/packages/react-bootstrap-table2-overlay/index.js @@ -10,7 +10,16 @@ export default options => (element, loading) => const masker = wrapper.firstChild; const headerDOM = wrapper.parentElement.querySelector('thead'); const bodyDOM = wrapper.parentElement.querySelector('tbody'); - masker.style.marginTop = window.getComputedStyle(headerDOM).height; + const captionDOM = wrapper.parentElement.querySelector('caption'); + + let marginTop = window.getComputedStyle(headerDOM).height; + if (captionDOM) { + marginTop = parseFloat(marginTop.replace('px', '')); + marginTop += parseFloat(window.getComputedStyle(captionDOM).height.replace('px', '')); + marginTop = `${marginTop}px`; + } + + masker.style.marginTop = marginTop; masker.style.height = window.getComputedStyle(bodyDOM).height; } } From a6daa504172730df7f0b7b89f0abb52254daa61a Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 15:50:10 +0800 Subject: [PATCH 15/20] improve overlay wrapping --- packages/react-bootstrap-table2-overlay/index.js | 8 ++++++-- .../react-bootstrap-table2/src/bootstrap-table.js | 13 ++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/react-bootstrap-table2-overlay/index.js b/packages/react-bootstrap-table2-overlay/index.js index 13ca433..04bc73d 100644 --- a/packages/react-bootstrap-table2-overlay/index.js +++ b/packages/react-bootstrap-table2-overlay/index.js @@ -1,9 +1,13 @@ /* eslint no-return-assign: 0 */ import React from 'react'; +import PropTypes from 'prop-types'; import LoadingOverlay from 'react-loading-overlay'; -export default options => (element, loading) => +export default options => loading => class TableLoadingOverlayWrapper extends React.Component { + static propTypes = { + children: PropTypes.element.isRequired + } componentDidMount() { if (loading) { const { wrapper } = this.overlay; @@ -31,7 +35,7 @@ export default options => (element, loading) => { ...options } active={ loading } > - { element } + { this.props.children } ); } diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index 27e96ab..723f5bd 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -29,12 +29,15 @@ class BootstrapTable extends PropsBaseResolver(Component) { render() { const { loading, overlay } = this.props; - const table = this.renderTable(); - if (loading && overlay) { - const LoadingOverlay = overlay(table, loading); - return ; + if (overlay) { + const LoadingOverlay = overlay(loading); + return ( + + { this.renderTable() } + + ); } - return table; + return this.renderTable(); } renderTable() { From 7253d7a1d75d497cc76facfdf7d488d748fbd563 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 20:40:31 +0800 Subject: [PATCH 16/20] fix overlay tests --- .../test/index.test.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/react-bootstrap-table2-overlay/test/index.test.js b/packages/react-bootstrap-table2-overlay/test/index.test.js index 1292475..1437b33 100644 --- a/packages/react-bootstrap-table2-overlay/test/index.test.js +++ b/packages/react-bootstrap-table2-overlay/test/index.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { shallow, render } from 'enzyme'; +import { shallow } from 'enzyme'; import LoadingOverlay from 'react-loading-overlay'; import overlayFactory from '..'; @@ -27,8 +27,8 @@ describe('overlayFactory', () => { describe('when loading is false', () => { beforeEach(() => { const tableElm = createTable(); - const Overlay = overlayFactory()(tableElm, false); - wrapper = shallow(); + const Overlay = overlayFactory()(false); + wrapper = shallow({ tableElm }); }); it('should rendering Overlay component correctly', () => { @@ -42,14 +42,14 @@ describe('overlayFactory', () => { describe('when loading is true', () => { beforeEach(() => { const tableElm = createTable(); - const Overlay = overlayFactory()(tableElm, true); - wrapper = render(); + const Overlay = overlayFactory()(true); + wrapper = shallow({ tableElm }); }); it('should rendering Overlay component correctly', () => { const overlay = wrapper.find(LoadingOverlay); expect(wrapper.length).toBe(1); - expect(overlay.length).toBe(0); + expect(overlay.length).toBe(1); }); }); @@ -60,8 +60,8 @@ describe('overlayFactory', () => { }; beforeEach(() => { const tableElm = createTable(); - const Overlay = overlayFactory(options)(tableElm, false); - wrapper = shallow(); + const Overlay = overlayFactory(options)(false); + wrapper = shallow({ tableElm }); }); it('should rendering Overlay component with options correctly', () => { From d43c622fdbecba92e87c4c2be4c4698324d12e79 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 21:31:13 +0800 Subject: [PATCH 17/20] fix docs --- docs/row-selection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/row-selection.md b/docs/row-selection.md index d7f2e57..eb57e6b 100644 --- a/docs/row-selection.md +++ b/docs/row-selection.md @@ -158,7 +158,7 @@ const selectRow = { }; ``` -### selectRow.selectionRenderer - [Bool] +### selectRow.selectionRenderer - [Function] Provide a callback function which allow you to custom the checkbox/radio box. This callback only have one argument which is an object and contain following properties: ```js @@ -172,7 +172,7 @@ const selectRow = { > By default, `react-bootstrap-table2` will help you to handle the click event, it's not necessary to handle again by developer. -### selectRow.selectionHeaderRenderer - [Bool] +### selectRow.selectionHeaderRenderer - [Function] Provide a callback function which allow you to custom the checkbox/radio box in the selection header column. This callback only have one argument which is an object and contain following properties: ```js From fb54809dc933b5e3ebb8a23fb834b466136f2097 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 21:31:13 +0800 Subject: [PATCH 18/20] fix docs --- docs/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/README.md b/docs/README.md index b7c5982..83213a6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -202,6 +202,7 @@ paginator({ totalSize, // Total data size. It's necessary when remote is enabled pageStartIndex: 0, // first page will be 0, default is 1 paginationSize: 3, // the pagination bar size, default is 5 + showTotal: true, // display pagination information sizePerPageList: [ { text: '5', value: 5 }, { @@ -223,6 +224,7 @@ paginator({ hidePageListOnlyOnePage: true, // hide pagination bar when only one page, default is false onPageChange: (page, sizePerPage) => {}, // callback function when page was changing onSizePerPageChange: (sizePerPage, page) => {}, // callback function when page size was changing + paginationTotalRenderer: (from, to, size) => { ... } // custom the pagination total }) ``` From 6730dcf60d7d3644098043a2555621d0895d982f Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 22:52:15 +0800 Subject: [PATCH 19/20] fix overlay test bugs --- .../react-bootstrap-table2-overlay/test/index.test.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/react-bootstrap-table2-overlay/test/index.test.js b/packages/react-bootstrap-table2-overlay/test/index.test.js index 1437b33..bf81fb6 100644 --- a/packages/react-bootstrap-table2-overlay/test/index.test.js +++ b/packages/react-bootstrap-table2-overlay/test/index.test.js @@ -1,12 +1,11 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { render, shallow } from 'enzyme'; import LoadingOverlay from 'react-loading-overlay'; -import overlayFactory from '..'; +import overlayFactory from '../index.js'; describe('overlayFactory', () => { let wrapper; - // let instance; const createTable = () => ( @@ -43,13 +42,11 @@ describe('overlayFactory', () => { beforeEach(() => { const tableElm = createTable(); const Overlay = overlayFactory()(true); - wrapper = shallow({ tableElm }); + wrapper = render({ tableElm }); }); it('should rendering Overlay component correctly', () => { - const overlay = wrapper.find(LoadingOverlay); expect(wrapper.length).toBe(1); - expect(overlay.length).toBe(1); }); }); From 36e754b6bc3db8e286ff15fce0c1553e7033a3dd Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 3 Jun 2018 22:58:03 +0800 Subject: [PATCH 20/20] patch docs --- packages/react-bootstrap-table2-filter/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2-filter/README.md b/packages/react-bootstrap-table2-filter/README.md index 3fe8488..dc9e621 100644 --- a/packages/react-bootstrap-table2-filter/README.md +++ b/packages/react-bootstrap-table2-filter/README.md @@ -168,7 +168,7 @@ const columns = [..., { > **Notes:** date filter accept a Javascript Date object in your raw data. -Date filter is same as other filter, you can custom the number filter via `dateFilter` factory function: +Date filter is same as other filter, you can custom the date filter via `dateFilter` factory function: ```js import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';