From 8e940112f5a7d85d63d006f5d3bf0c6cf39808aa Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 23 Feb 2019 16:13:40 +0800 Subject: [PATCH 1/6] fix #811 --- packages/react-bootstrap-table2-filter/src/context.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2-filter/src/context.js b/packages/react-bootstrap-table2-filter/src/context.js index 019013f..f54e327 100644 --- a/packages/react-bootstrap-table2-filter/src/context.js +++ b/packages/react-bootstrap-table2-filter/src/context.js @@ -40,7 +40,7 @@ export default ( componentWillReceiveProps(nextProps) { let nextData = nextProps.data; - if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.props.data)) { + if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.state.data)) { nextData = this.doFilter(nextProps); } this.setState({ From d26c13b9beafc0fa7e4c79c5c96a68dbbbab3726 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 24 Feb 2019 14:11:05 +0800 Subject: [PATCH 2/6] fix #815 --- packages/react-bootstrap-table2/src/contexts/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-bootstrap-table2/src/contexts/index.js b/packages/react-bootstrap-table2/src/contexts/index.js index 3288d0a..d735c1a 100644 --- a/packages/react-bootstrap-table2/src/contexts/index.js +++ b/packages/react-bootstrap-table2/src/contexts/index.js @@ -294,6 +294,7 @@ const withContext = Base => return rootProps => ( this.cellEditContext = n } selectRow={ this.props.selectRow } cellEdit={ this.props.cellEdit } data={ rootProps.getData() } From c01f45a719702ad44a3b22c70291927962e7eee0 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 24 Feb 2019 14:56:27 +0800 Subject: [PATCH 3/6] fix #789 --- .../src/contexts/selection-context.js | 45 ++++++++--------- .../test/contexts/selection-context.test.js | 49 ++++++++++--------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/packages/react-bootstrap-table2/src/contexts/selection-context.js b/packages/react-bootstrap-table2/src/contexts/selection-context.js index 9c44cff..573c54f 100644 --- a/packages/react-bootstrap-table2/src/contexts/selection-context.js +++ b/packages/react-bootstrap-table2/src/contexts/selection-context.js @@ -14,26 +14,27 @@ class SelectionProvider extends React.Component { keyField: PropTypes.string.isRequired } - state = { selected: this.props.selectRow.selected || [] }; + constructor(props) { + super(props); + this.selected = props.selectRow.selected || []; + } componentWillReceiveProps(nextProps) { if (nextProps.selectRow) { - this.setState(() => ({ - selected: nextProps.selectRow.selected || this.state.selected - })); + this.selected = nextProps.selectRow.selected || this.selected; } } // exposed API getSelected() { - return this.state.selected; + return this.selected; } handleRowSelect = (rowKey, checked, rowIndex, e) => { const { data, keyField, selectRow: { mode, onSelect } } = this.props; const { ROW_SELECT_SINGLE } = Const; - let currSelected = [...this.state.selected]; + let currSelected = [...this.selected]; let result = true; if (onSelect) { @@ -41,18 +42,17 @@ class SelectionProvider extends React.Component { result = onSelect(row, checked, rowIndex, e); } - this.setState(() => { - if (result === true || result === undefined) { - if (mode === ROW_SELECT_SINGLE) { // when select mode is radio - currSelected = [rowKey]; - } else if (checked) { // when select mode is checkbox - currSelected.push(rowKey); - } else { - currSelected = currSelected.filter(value => value !== rowKey); - } + if (result === true || result === undefined) { + if (mode === ROW_SELECT_SINGLE) { // when select mode is radio + currSelected = [rowKey]; + } else if (checked) { // when select mode is checkbox + currSelected.push(rowKey); + } else { + currSelected = currSelected.filter(value => value !== rowKey); } - return { selected: currSelected }; - }); + } + this.selected = currSelected; + this.forceUpdate(); } handleAllRowsSelect = (e, isUnSelect) => { @@ -64,7 +64,7 @@ class SelectionProvider extends React.Component { nonSelectable } } = this.props; - const { selected } = this.state; + const { selected } = this; let currSelected; @@ -81,7 +81,7 @@ class SelectionProvider extends React.Component { dataOperator.getSelectedRows( data, keyField, - isUnSelect ? this.state.selected : currSelected + isUnSelect ? selected : currSelected ), e ); @@ -89,7 +89,8 @@ class SelectionProvider extends React.Component { currSelected = result; } } - this.setState(() => ({ selected: currSelected })); + this.selected = currSelected; + this.forceUpdate(); } render() { @@ -99,7 +100,7 @@ class SelectionProvider extends React.Component { } = getSelectionSummary( this.props.data, this.props.keyField, - this.state.selected + this.selected ); let checkedStatus; @@ -113,7 +114,7 @@ class SelectionProvider extends React.Component { { expect(SelectionContext.Consumer).toBeDefined(); }); - it('should have correct state.data', () => { - expect(wrapper.state().selected).toEqual([]); + it('should have correct this.selected', () => { + expect(wrapper.instance().selected).toEqual([]); }); it('should pass correct sort props to children element', () => { expect(wrapper.length).toBe(1); expect(mockBase).toHaveBeenCalledWith({ ...defaultSelectRow, - selected: wrapper.state().selected, + selected: wrapper.instance().selected, onRowSelect: wrapper.instance().handleRowSelect, onAllRowsSelect: wrapper.instance().handleAllRowsSelect, allRowsNotSelected: true, @@ -104,8 +104,8 @@ describe('DataContext', () => { }); }); - it('should have correct state.selected', () => { - expect(wrapper.state().selected).toEqual(newSelectRow.selected); + it('should have correct this.selected', () => { + expect(wrapper.instance().selected).toEqual(newSelectRow.selected); }); describe('if nextProps.selectRow is not existing', () => { @@ -120,8 +120,8 @@ describe('DataContext', () => { }); }); - it('should keep origin state.selected', () => { - expect(wrapper.state().selected).toEqual(defaultSelected); + it('should keep origin this.selected', () => { + expect(wrapper.instance().selected).toEqual(defaultSelected); }); }); @@ -131,8 +131,8 @@ describe('DataContext', () => { wrapper.instance().componentWillReceiveProps({}); }); - it('should not set state.selected', () => { - expect(wrapper.state().selected).toEqual([]); + it('should not set this.selected', () => { + expect(wrapper.instance().selected).toEqual([]); }); }); }); @@ -148,8 +148,8 @@ describe('DataContext', () => { wrapper = shallow(shallowContext(selectRow)); }); - it('should have correct state.data', () => { - expect(wrapper.state().selected).toEqual(selectRow.selected); + it('should have correct this.selected', () => { + expect(wrapper.instance().selected).toEqual(selectRow.selected); }); }); @@ -164,12 +164,12 @@ describe('DataContext', () => { wrapper = shallow(shallowContext(selectRow)); }); - it('should set state.selected correctly', () => { + it('should set this.selected correctly', () => { wrapper.instance().handleRowSelect(firstSelectedRow, true, rowIndex); - expect(wrapper.state('selected')).toEqual([firstSelectedRow]); + expect(wrapper.instance().selected).toEqual([firstSelectedRow]); wrapper.instance().handleRowSelect(secondSelectedRow, true, rowIndex); - expect(wrapper.state('selected')).toEqual([secondSelectedRow]); + expect(wrapper.instance().selected).toEqual([secondSelectedRow]); }); }); @@ -178,18 +178,19 @@ describe('DataContext', () => { wrapper = shallow(shallowContext()); }); - it('should set state.selected correctly', () => { + it('should set this.selected correctly', () => { wrapper.instance().handleRowSelect(firstSelectedRow, true, rowIndex); - expect(wrapper.state('selected')).toEqual(expect.arrayContaining([firstSelectedRow])); + expect(wrapper.instance().selected).toEqual(expect.arrayContaining([firstSelectedRow])); wrapper.instance().handleRowSelect(secondSelectedRow, true, rowIndex); - expect(wrapper.state('selected')).toEqual(expect.arrayContaining([firstSelectedRow, secondSelectedRow])); + expect(wrapper.instance().selected) + .toEqual(expect.arrayContaining([firstSelectedRow, secondSelectedRow])); wrapper.instance().handleRowSelect(firstSelectedRow, false, rowIndex); - expect(wrapper.state('selected')).toEqual(expect.arrayContaining([secondSelectedRow])); + expect(wrapper.instance().selected).toEqual(expect.arrayContaining([secondSelectedRow])); wrapper.instance().handleRowSelect(secondSelectedRow, false, rowIndex); - expect(wrapper.state('selected')).toEqual([]); + expect(wrapper.instance().selected).toEqual([]); }); }); @@ -220,8 +221,8 @@ describe('DataContext', () => { wrapper.instance().handleAllRowsSelect(e, false); }); - it('should set state.selected correctly', () => { - expect(wrapper.state('selected')).toEqual(data.map(d => d[keyField])); + it('should set this.selected correctly', () => { + expect(wrapper.instance().selected).toEqual(data.map(d => d[keyField])); }); describe('when selectRow.onSelectAll is defined', () => { @@ -237,7 +238,7 @@ describe('DataContext', () => { it('should call selectRow.onSelectAll correctly', () => { expect(onSelectAll).toHaveBeenCalledWith( true, - dataOperator.getSelectedRows(data, keyField, wrapper.state('selected')), + dataOperator.getSelectedRows(data, keyField, wrapper.instance().selected), e ); }); @@ -253,8 +254,8 @@ describe('DataContext', () => { wrapper.instance().handleAllRowsSelect(e, true); }); - it('should set state.selected correctly', () => { - expect(wrapper.state('selected')).toEqual([]); + it('should set this.selected correctly', () => { + expect(wrapper.instance().selected).toEqual([]); }); describe('when selectRow.onSelectAll is defined', () => { From bf0c5c43a2e88ea1fa38c8d5f3e8fcedae53f528 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 24 Feb 2019 15:50:13 +0800 Subject: [PATCH 4/6] fix #735 --- packages/react-bootstrap-table2/src/cell.js | 3 ++ .../react-bootstrap-table2/test/cell.test.js | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/packages/react-bootstrap-table2/src/cell.js b/packages/react-bootstrap-table2/src/cell.js index 46b10ea..d09f689 100644 --- a/packages/react-bootstrap-table2/src/cell.js +++ b/packages/react-bootstrap-table2/src/cell.js @@ -23,7 +23,10 @@ class Cell extends eventDelegater(Component) { if (shouldUpdate) return true; + // if (nextProps.formatter) + shouldUpdate = + nextProps.column.formatter ? !_.isEqual(this.props.row, nextProps.row) : false || this.props.column.hidden !== nextProps.column.hidden || this.props.rowIndex !== nextProps.rowIndex || this.props.columnIndex !== nextProps.columnIndex || diff --git a/packages/react-bootstrap-table2/test/cell.test.js b/packages/react-bootstrap-table2/test/cell.test.js index 1187c13..d0ceb95 100644 --- a/packages/react-bootstrap-table2/test/cell.test.js +++ b/packages/react-bootstrap-table2/test/cell.test.js @@ -218,6 +218,47 @@ describe('Cell', () => { }); }); + describe('when props.row is change', () => { + describe('and column.formatter is enable', () => { + const column = { dataField: 'name', text: 'Product Name', formatter: () => 123 }; + beforeEach(() => { + props = { + row, + columnIndex: 1, + rowIndex: 1, + tabIndex: 5, + column + }; + wrapper = shallow( + ); + }); + + it('should return true', () => { + nextProps = { ...props, row: { ...row, alert: 'test' } }; + expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true); + }); + }); + describe('but column.formatter is disable', () => { + const column = { dataField: 'name', text: 'Product Name' }; + beforeEach(() => { + props = { + row, + columnIndex: 1, + rowIndex: 1, + tabIndex: 5, + column + }; + wrapper = shallow( + ); + }); + + it('should return true', () => { + nextProps = { ...props, row: { ...row, alert: 'test' } }; + expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(false); + }); + }); + }); + describe('if column.isDummyField is true', () => { describe('when content is change', () => { const column = { dataField: '', text: 'Product Name', isDummyField: true }; From 09f21e81303e37ae1f1a12aeacaae237ee3fac2c Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 24 Feb 2019 16:11:38 +0800 Subject: [PATCH 5/6] allow to custom className on clear search and export csv button --- .../examples/bootstrap4/toolkits.js | 90 +++++++++++++++++++ .../stories/index.js | 4 +- .../src/csv/button.js | 4 +- .../src/search/clear-button.js | 9 +- 4 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/bootstrap4/toolkits.js diff --git a/packages/react-bootstrap-table2-example/examples/bootstrap4/toolkits.js b/packages/react-bootstrap-table2-example/examples/bootstrap4/toolkits.js new file mode 100644 index 0000000..4313cf0 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/bootstrap4/toolkits.js @@ -0,0 +1,90 @@ +/* eslint react/prop-types: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import ToolkitProvider, { Search, CSVExport } from 'react-bootstrap-table2-toolkit'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const { SearchBar, ClearSearchButton } = Search; +const { ExportCSVButton } = CSVExport; +const products = productsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import ToolkitProvider, { Search, CSVExport } from 'react-bootstrap-table2-toolkit'; + +const { SearchBar, ClearSearchButton } = Search; +const { ExportCSVButton } = CSVExport; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + + + { + props => ( +
+

Input something at below input field:

+ + +
+ + Export CSV!! +
+ ) + } +
+`; + +export default () => ( +
+ + { + props => ( +
+

Input something at below input field:

+ + +
+ + Export CSV!! +
+ ) + } +
+ { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 4265375..39be4b7 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -21,6 +21,7 @@ import Bootstrap4DefaultSortTable from 'examples/bootstrap4/sort'; import Bootstrap4RowSelectionTable from 'examples/bootstrap4/row-selection'; import Bootstrap4PaginationTable from 'examples/bootstrap4/pagination'; import Bootstrap4ColumnToggleTable from 'examples/bootstrap4/column-toggle'; +import ToolkitsTable from 'examples/bootstrap4/toolkits'; // work on columns import NestedDataTable from 'examples/columns/nested-data-table'; @@ -249,7 +250,8 @@ storiesOf('Bootstrap 4', module) .add('Sort table with bootstrap 4', () => ) .add('Row selection table with bootstrap 4', () => ) .add('Pagination table with bootstrap 4', () => ) - .add('Column Toggle with bootstrap 4', () => ); + .add('Column Toggle with bootstrap 4', () => ) + .add('toolkits Table bootstrap 4', () => ); storiesOf('Work on Columns', module) .addDecorator(bootstrapStyle()) diff --git a/packages/react-bootstrap-table2-toolkit/src/csv/button.js b/packages/react-bootstrap-table2-toolkit/src/csv/button.js index e85d7ee..18faf48 100644 --- a/packages/react-bootstrap-table2-toolkit/src/csv/button.js +++ b/packages/react-bootstrap-table2-toolkit/src/csv/button.js @@ -5,12 +5,14 @@ const ExportCSVButton = (props) => { const { onExport, children, + className, ...rest } = props; return ( + ); ClearButton.propTypes = { onClear: PropTypes.func.isRequired, + className: PropTypes.string, text: PropTypes.string }; ClearButton.defaultProps = { - text: 'Clear' + text: 'Clear', + className: '' }; export default ClearButton; From 3ffccce1fe3e48234c45919411424d2c7fa0bb73 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 24 Feb 2019 16:20:44 +0800 Subject: [PATCH 6/6] fix #817 --- .../examples/cell-edit/custom-editor-table.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/react-bootstrap-table2-example/examples/cell-edit/custom-editor-table.js b/packages/react-bootstrap-table2-example/examples/cell-edit/custom-editor-table.js index a75a98a..8b548a5 100644 --- a/packages/react-bootstrap-table2-example/examples/cell-edit/custom-editor-table.js +++ b/packages/react-bootstrap-table2-example/examples/cell-edit/custom-editor-table.js @@ -18,6 +18,11 @@ class QualityRanger extends React.Component { static defaultProps = { value: 0 } + + componentDidMount() { + this.range.focus(); + } + getValue() { return parseInt(this.range.value, 10); }