From 849d9af8c414ab0ceb86b4fa3d52809d47192c7b Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 1 Sep 2018 14:52:29 +0800 Subject: [PATCH 1/9] fix #504 --- packages/react-bootstrap-table2/src/cell.js | 17 +++++++++++++---- .../react-bootstrap-table2/src/header-cell.js | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/react-bootstrap-table2/src/cell.js b/packages/react-bootstrap-table2/src/cell.js index db32d05..e6f2149 100644 --- a/packages/react-bootstrap-table2/src/cell.js +++ b/packages/react-bootstrap-table2/src/cell.js @@ -11,9 +11,18 @@ class Cell extends Component { } shouldComponentUpdate(nextProps) { - const shouldUpdate = - _.get(this.props.row, this.props.column.dataField) - !== _.get(nextProps.row, nextProps.column.dataField) || + let shouldUpdate = false; + if (nextProps.column.isDummyField) { + shouldUpdate = !_.isEqual(this.props.row, nextProps.row); + } else { + shouldUpdate = + _.get(this.props.row, this.props.column.dataField) + !== _.get(nextProps.row, nextProps.column.dataField); + } + + if (shouldUpdate) return true; + + shouldUpdate = this.props.column.hidden !== nextProps.column.hidden || this.props.rowIndex !== nextProps.rowIndex || this.props.columnIndex !== nextProps.columnIndex || @@ -64,7 +73,7 @@ class Cell extends Component { formatExtraData } = column; const attrs = { ...rest }; - let content = _.get(row, dataField); + let content = column.isDummyField ? null : _.get(row, dataField); if (formatter) { content = column.formatter(content, row, rowIndex, formatExtraData); diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js index 52cf7a1..2053453 100644 --- a/packages/react-bootstrap-table2/src/header-cell.js +++ b/packages/react-bootstrap-table2/src/header-cell.js @@ -114,6 +114,7 @@ HeaderCell.propTypes = { column: PropTypes.shape({ dataField: PropTypes.string.isRequired, text: PropTypes.string.isRequired, + isDummyField: PropTypes.bool, hidden: PropTypes.bool, headerFormatter: PropTypes.func, formatter: PropTypes.func, From 3b1fc3a5598d17e4be32c38ec42750c9e90c445a Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 1 Sep 2018 14:55:48 +0800 Subject: [PATCH 2/9] add dummy column story --- .../examples/columns/dummy-column-table.js | 221 ++++++++++++++++++ .../stories/index.js | 4 +- .../react-bootstrap-table2/test/cell.test.js | 53 +++-- 3 files changed, 262 insertions(+), 16 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/columns/dummy-column-table.js diff --git a/packages/react-bootstrap-table2-example/examples/columns/dummy-column-table.js b/packages/react-bootstrap-table2-example/examples/columns/dummy-column-table.js new file mode 100644 index 0000000..10b6948 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/columns/dummy-column-table.js @@ -0,0 +1,221 @@ +/* eslint jsx-a11y/label-has-for: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; + + +const products = [ + { id: 12, name: 'Item 12', price: 12.5, inStock: false }, + { id: 13, name: 'Item 13', price: 13.5, inStock: true }, + { id: 14, name: 'Item 14', price: 14.5, inStock: true } +]; + +const columns = [ + { + dataField: 'id', + text: 'Product ID' + }, + { + dataField: 'name', + text: 'Product Name' + }, + { + dataField: 'price', + text: 'Product Price' + }, + { + dataField: 'inStock', + text: 'In Stock', + formatter: (cellContent, row) => ( +
+ +
+ ) + }, + { + dataField: 'df1', + isDummyField: true, + text: 'Action 1', + formatter: (cellContent, row) => { + if (row.inStock) { + return ( +
+ Available +
+ ); + } + return ( +
+ Backordered +
+ ); + } + }, + { + dataField: 'df2', + isDummyField: true, + text: 'Action 2', + formatter: (cellContent, row) => { + if (row.inStock) { + return ( +
+ Available +
+ ); + } + return ( +
+ Backordered +
+ ); + } + } +]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = [ + { + dataField: 'id', + text: 'Product ID' + }, + { + dataField: 'name', + text: 'Product Name' + }, + { + dataField: 'price', + text: 'Product Price' + }, + { + dataField: 'inStock', + text: 'In Stock', + formatter: (cellContent, row) => ( +
+ +
+ ) + }, + { + dataField: 'df1', + isDummyField: true, + text: 'Action 1', + formatter: (cellContent, row) => { + if (row.inStock) { + return ( +
+ Available +
+ ); + } + return ( +
+ Backordered +
+ ); + } + }, + { + dataField: 'df2', + isDummyField: true, + text: 'Action 2', + formatter: (cellContent, row) => { + if (row.inStock) { + return ( +
+ Available +
+ ); + } + return ( +
+ Backordered +
+ ); + } + } +]; + +class ProductList extends React.Component { + constructor(props) { + super(props); + this.state = { products }; + } + + toggleInStock = () => { + let newProducts = [...this.state.products]; + newProducts = newProducts.map((d) => { + if (d.id === 13) { + return { + ...d, + inStock: !d.inStock + }; + } + return d; + }); + this.setState(curr => ({ ...curr, products: newProducts })); + }; + + render() { + return ( +
+

Products

+ + +
+ ); + } +} +`; + +class ProductList extends React.Component { + constructor(props) { + super(props); + this.state = { products }; + } + + toggleInStock = () => { + let newProducts = [...this.state.products]; + newProducts = newProducts.map((d) => { + if (d.id === 13) { + return { + ...d, + inStock: !d.inStock + }; + } + return d; + }); + this.setState(curr => ({ ...curr, products: newProducts })); + }; + + render() { + return ( +
+

Action 1 and Action 2 are dummy column

+ + + { sourceCode } +
+ ); + } +} + +export default ProductList; diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index eff1ee0..45fb5cc 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -30,6 +30,7 @@ import ColumnTitleTable from 'examples/columns/column-title-table'; import ColumnEventTable from 'examples/columns/column-event-table'; import ColumnHiddenTable from 'examples/columns/column-hidden-table'; import ColumnAttrsTable from 'examples/columns/column-attrs-table'; +import DummyColumnTable from 'examples/columns/dummy-column-table'; // work on header columns import HeaderColumnFormatTable from 'examples/header-columns/column-format-table'; @@ -201,7 +202,8 @@ storiesOf('Work on Columns', module) .add('Column Event', () => ) .add('Customize Column Class', () => ) .add('Customize Column Style', () => ) - .add('Customize Column HTML attribute', () => ); + .add('Customize Column HTML attribute', () => ) + .add('Dummy Column', () => ); storiesOf('Work on Header Columns', module) .addDecorator(bootstrapStyle()) diff --git a/packages/react-bootstrap-table2/test/cell.test.js b/packages/react-bootstrap-table2/test/cell.test.js index 86bf393..e2e42ab 100644 --- a/packages/react-bootstrap-table2/test/cell.test.js +++ b/packages/react-bootstrap-table2/test/cell.test.js @@ -177,22 +177,45 @@ describe('Cell', () => { let props; let nextProps; - describe('when content is change', () => { - const column = { dataField: 'name', text: 'Product Name' }; - beforeEach(() => { - props = { - row, - columnIndex: 1, - rowIndex: 1, - column - }; - wrapper = shallow( - ); - }); + describe('if column.isDummyField is false', () => { + describe('when content is change', () => { + const column = { dataField: 'name', text: 'Product Name' }; + beforeEach(() => { + props = { + row, + columnIndex: 1, + rowIndex: 1, + column + }; + wrapper = shallow( + ); + }); - it('should return true', () => { - nextProps = { ...props, row: { id: 1, name: 'CDE' } }; - expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true); + it('should return true', () => { + nextProps = { ...props, row: { id: 1, name: 'CDE' } }; + expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true); + }); + }); + }); + + describe('if column.isDummyField is true', () => { + describe('when content is change', () => { + const column = { dataField: '', text: 'Product Name', isDummyField: true }; + beforeEach(() => { + props = { + row, + columnIndex: 1, + rowIndex: 1, + column + }; + wrapper = shallow( + ); + }); + + it('should return true', () => { + nextProps = { ...props, row: { id: 1, name: 'CDE', test: 'This is new Field' } }; + expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true); + }); }); }); From a9669007527d0ba7a22b12e099677e7200926967 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 1 Sep 2018 14:55:59 +0800 Subject: [PATCH 3/9] patch docs for #504 --- docs/columns.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/columns.md b/docs/columns.md index d472e67..afeffe7 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -7,6 +7,7 @@ Available properties in a column object: * [text (**required**)](#text) #### Optional +* [isDummyField](#isDummyField) * [hidden](#hidden) * [formatter](#formatter) * [formatExtraData](#formatExtraData) @@ -84,6 +85,11 @@ dataField: 'address.city' ## column.text (**required**) - [String] `text` will be the column text in header column by default, if your header is not only text or you want to customize the header column, please check [`column.headerFormatter`](#headerFormatter) +## column.isDummyField - [Bool] +Sometime, you just want to have a column which is not perform any data but just some action components. In this situation, we suggest you to use `isDummyField`. If column is dummy, the [`column.dataField`](#dataField) can be any string value, cause of it's meaningless. + +There's only one different for dummy column than normal column, which is dummy column will compare the whole row value instead of cell value when call `shouldComponentUpdate`. + ## column.hidden - [Bool] `hidden` allow you to hide column when `true` given. From d136ec319726a99d882b79365c1cbea9eeda6952 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 1 Sep 2018 16:26:48 +0800 Subject: [PATCH 4/9] fix #510 --- .../react-bootstrap-table2-toolkit/README.md | 5 ++++- .../react-bootstrap-table2-toolkit/context.js | 4 +++- .../src/csv/button.js | 2 +- .../src/op/csv.js | 21 +++++++++++++++---- .../src/contexts/index.js | 3 ++- .../src/contexts/selection-context.js | 13 ++++++++++++ 6 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/react-bootstrap-table2-toolkit/README.md b/packages/react-bootstrap-table2-toolkit/README.md index f26c366..0886862 100644 --- a/packages/react-bootstrap-table2-toolkit/README.md +++ b/packages/react-bootstrap-table2-toolkit/README.md @@ -123,4 +123,7 @@ Default is `false`. Give true to avoid to attach the csv header. Default is `true`. #### exportAll - [bool] -Default is `true`. `false` will only export current data which display on table. \ No newline at end of file +Default is `true`. `false` will only export current data which display on table. + +#### onlyExportSelection - [bool] +Default is `false`. `true` will only export the data which is selected. \ No newline at end of file diff --git a/packages/react-bootstrap-table2-toolkit/context.js b/packages/react-bootstrap-table2-toolkit/context.js index d12a7f0..eba442e 100644 --- a/packages/react-bootstrap-table2-toolkit/context.js +++ b/packages/react-bootstrap-table2-toolkit/context.js @@ -26,7 +26,9 @@ class ToolkitProvider extends statelessDrcorator(React.Component) { fileName: PropTypes.string, separator: PropTypes.string, ignoreHeader: PropTypes.bool, - noAutoBOM: PropTypes.bool + noAutoBOM: PropTypes.bool, + exportAll: PropTypes.bool, + onlyExportSelection: PropTypes.bool }) ]) } diff --git a/packages/react-bootstrap-table2-toolkit/src/csv/button.js b/packages/react-bootstrap-table2-toolkit/src/csv/button.js index d0ee010..e85d7ee 100644 --- a/packages/react-bootstrap-table2-toolkit/src/csv/button.js +++ b/packages/react-bootstrap-table2-toolkit/src/csv/button.js @@ -11,7 +11,7 @@ const ExportCSVButton = (props) => { return ( + + ); +}; + + + { + props => ( +
+ +
+ +
+ ) + } +
+`; + +const MyExportCSV = (props) => { + const handleClick = () => { + // passing my custom data + props.onExport(products.filter(r => r.id > 2)); + }; + return ( +
+ +
+ ); +}; + +export default () => ( +
+ + { + props => ( +
+ +
+ +
+ ) + } +
+ { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/csv/export-only-selected.js b/packages/react-bootstrap-table2-example/examples/csv/export-only-selected.js new file mode 100644 index 0000000..e260f53 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/csv/export-only-selected.js @@ -0,0 +1,140 @@ +/* eslint react/prop-types: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import ToolkitProvider, { CSVExport } from 'react-bootstrap-table2-toolkit'; +import paginationFactory from 'react-bootstrap-table2-paginator'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const { ExportCSVButton } = CSVExport; +const products1 = productsGenerator(15); +const products2 = productsGenerator(15); + +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, { CSVExport } from 'react-bootstrap-table2-toolkit'; + +const { ExportCSVButton } = CSVExport; +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const selectRow = { + mode: 'checkbox', + clickToSelect: true +}; + + + { + props => ( +
+ Export CSV!! +
+ +
+ ) + } +
+ + + { + props => ( +
+ Export CSV!! +
+ +
+ ) + } +
+`; + +const selectRow = { + mode: 'checkbox', + clickToSelect: true +}; + +export default () => ( +
+

Export all selected row

+ + { + props => ( +
+ Export CSV!! +
+ +
+ ) + } +
+

Export all selected rows in currect visible rows

+ + { + props => ( +
+ Export CSV!! +
+ +
+ ) + } +
+ { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 45fb5cc..0c652db 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -146,8 +146,10 @@ import ExportCSV from 'examples/csv'; import CSVFormatter from 'examples/csv/csv-column-formatter'; import CustomCSVHeader from 'examples/csv/custom-csv-header'; import HideCSVColumn from 'examples/csv/hide-column'; +import ExportOnlySelected from 'examples/csv/export-only-selected'; import CSVColumnType from 'examples/csv/csv-column-type'; import CustomCSVButton from 'examples/csv/custom-csv-button'; +import ExportCustomData from 'examples/csv/export-custom-data'; import CustomCSV from 'examples/csv/custom-csv'; // loading overlay @@ -330,8 +332,10 @@ storiesOf('Export CSV', module) .add('Format CSV Column', () => ) .add('Custom CSV Header', () => ) .add('Hide CSV Column', () => ) + .add('Only Export Selected Rows', () => ) .add('CSV Column Type', () => ) .add('Custom CSV Button', () => ) + .add('Export Custom Data', () => ) .add('Custom CSV', () => ); storiesOf('EmptyTableOverlay', module) From 591abaae6e6bf68d59dcbbd01a8f9f7951e02ec4 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 1 Sep 2018 16:39:26 +0800 Subject: [PATCH 6/9] fix wonrg title --- .../examples/cell-edit/checkbox-editor-table.js | 2 +- .../examples/cell-edit/custom-editor-table.js | 2 +- .../examples/cell-edit/date-editor-table.js | 2 +- .../examples/cell-edit/textarea-editor-table.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/cell-edit/checkbox-editor-table.js b/packages/react-bootstrap-table2-example/examples/cell-edit/checkbox-editor-table.js index 39a3df0..971f2d9 100644 --- a/packages/react-bootstrap-table2-example/examples/cell-edit/checkbox-editor-table.js +++ b/packages/react-bootstrap-table2-example/examples/cell-edit/checkbox-editor-table.js @@ -52,7 +52,7 @@ const columns = [{ export default () => (
-

Dropdown Editor

+

Checkbox Editor

(
-

Dropdown Editor

+

Custom Editor

(
-

Dropdown Editor

+

Date Editor

(
-

Dropdown Editor

+

Textarea Editor

Date: Sat, 1 Sep 2018 17:00:34 +0800 Subject: [PATCH 7/9] fix #514 --- .../src/checkbox-editor.js | 10 +++++++--- packages/react-bootstrap-table2-editor/src/context.js | 3 ++- .../react-bootstrap-table2-editor/src/date-editor.js | 11 +++++++---- .../src/dropdown-editor.js | 11 +++++++---- .../react-bootstrap-table2-editor/src/editing-cell.js | 6 +++++- .../react-bootstrap-table2-editor/src/text-editor.js | 11 +++++++---- .../src/textarea-editor.js | 11 +++++++---- 7 files changed, 42 insertions(+), 21 deletions(-) diff --git a/packages/react-bootstrap-table2-editor/src/checkbox-editor.js b/packages/react-bootstrap-table2-editor/src/checkbox-editor.js index 561f25c..51dd12b 100644 --- a/packages/react-bootstrap-table2-editor/src/checkbox-editor.js +++ b/packages/react-bootstrap-table2-editor/src/checkbox-editor.js @@ -13,7 +13,9 @@ class CheckBoxEditor extends Component { } componentDidMount() { + const { didMount } = this.props; this.checkbox.focus(); + if (didMount) didMount(); } getValue() { @@ -28,7 +30,7 @@ class CheckBoxEditor extends Component { } render() { - const { defaultValue, className, ...rest } = this.props; + const { defaultValue, didMount, className, ...rest } = this.props; const editorClass = cs('editor edit-chseckbox checkbox', className); return ( +export default (_, onStartEdit) => class EditingCell extends Component { static propTypes = { row: PropTypes.object.isRequired, @@ -151,6 +151,10 @@ export default _ => onBlur: this.handleBlur }; + if (onStartEdit) { + editorProps.didMount = () => onStartEdit(row, column, rowIndex, columnIndex); + } + const isDefaultEditorDefined = _.isObject(column.editor); if (isDefaultEditorDefined) { diff --git a/packages/react-bootstrap-table2-editor/src/text-editor.js b/packages/react-bootstrap-table2-editor/src/text-editor.js index b44c2da..1a28a29 100644 --- a/packages/react-bootstrap-table2-editor/src/text-editor.js +++ b/packages/react-bootstrap-table2-editor/src/text-editor.js @@ -5,9 +5,10 @@ import PropTypes from 'prop-types'; class TextEditor extends Component { componentDidMount() { - const { defaultValue } = this.props; + const { defaultValue, didMount } = this.props; this.text.value = defaultValue; this.text.focus(); + if (didMount) didMount(); } getValue() { @@ -15,7 +16,7 @@ class TextEditor extends Component { } render() { - const { defaultValue, className, ...rest } = this.props; + const { defaultValue, didMount, className, ...rest } = this.props; const editorClass = cs('form-control editor edit-text', className); return ( Date: Sat, 1 Sep 2018 17:01:10 +0800 Subject: [PATCH 8/9] patch story for add cell.onStartEdit(#514) --- .../examples/cell-edit/cell-edit-hooks-table.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-hooks-table.js b/packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-hooks-table.js index afb1523..403dc72 100644 --- a/packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-hooks-table.js +++ b/packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-hooks-table.js @@ -41,6 +41,7 @@ const columns = [{ columns={ columns } cellEdit={ cellEditFactory({ mode: 'click', + onStartEdit: (row, column, rowIndex, columnIndex) => { console.log('start to edit!!!'); }, beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); }, afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); } }) } @@ -55,6 +56,7 @@ export default () => ( columns={ columns } cellEdit={ cellEditFactory({ mode: 'click', + onStartEdit: (row, column, rowIndex, columnIndex) => { console.log('Start to edit!!!'); }, beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); }, afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); } }) } From f0d85520c002c19ce70457b72a8956852dea8ff1 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sat, 1 Sep 2018 21:11:31 +0800 Subject: [PATCH 9/9] Fix typo of peer dependency --- packages/react-bootstrap-table2-example/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2-example/package.json b/packages/react-bootstrap-table2-example/package.json index 99e9838..357a541 100644 --- a/packages/react-bootstrap-table2-example/package.json +++ b/packages/react-bootstrap-table2-example/package.json @@ -15,7 +15,7 @@ "peerDependencies": { "prop-types": "^15.0.0", "react": "^16.3.0", - "react-dom": "^116.3.0" + "react-dom": "^16.3.0" }, "devDependencies": { "@storybook/addon-console": "^1.0.0",