From abcd74e6814324dcf82b475bdc5fdd67e42e76f5 Mon Sep 17 00:00:00 2001 From: Luka Murn Date: Thu, 17 Aug 2017 14:51:14 +0200 Subject: [PATCH 1/5] Initial commit, including react-bootstrap-table and react-data-grid --- .../packs/shared/data_grid/DataGrid.jsx | 74 +++++++++++++++++++ .../packs/shared/data_table/DataTable.jsx | 59 +++++++++++++++ app/javascript/packs/styles/main.scss | 1 + package.json | 4 +- 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 app/javascript/packs/shared/data_grid/DataGrid.jsx create mode 100644 app/javascript/packs/shared/data_table/DataTable.jsx diff --git a/app/javascript/packs/shared/data_grid/DataGrid.jsx b/app/javascript/packs/shared/data_grid/DataGrid.jsx new file mode 100644 index 000000000..3f46438ad --- /dev/null +++ b/app/javascript/packs/shared/data_grid/DataGrid.jsx @@ -0,0 +1,74 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import ReactDataGrid from 'react-data-grid'; + +class DataGrid extends Component { + constructor(props) { + super(props); + this.cleanProps = this.cleanProps.bind(this); + this.transformColumns = this.transformColumns.bind(this); + this.setupDefaultProps = this.setupDefaultProps.bind(this); + + this.transformColumns(); + this.setupDefaultProps(); + } + + transformColumns() { + // Transform columns from the "sciNote" representation into + // ReactDataGrid-compatible representation + this._columns = + this.props.columns + .sort((a, b) => b.position - a.position) + .filter((col) => col.visible) + .map((col) => { + return { + key: col.textId, + name: col.name, + locked: col.locked + }; + }); + } + + setupDefaultProps() { + // Setup the default props if they're not provided + const self = this; + + if ('rowGetter' in this.props) { + this._rowGetter = this.props.rowGetter; + } else { + this._rowGetter = function(i) { + return this.props.data[i]; + }.bind(this); + } + if ('rowsCount' in this.props) { + this._rowsCount = this.props.rowsCount; + } else { + this._rowsCount = this.props.data.length; + } + } + + cleanProps() { + // Remove additional props from the props value + const cleanProps = {...this.props}; + delete cleanProps.columns; + delete cleanProps.rowGetter; + delete cleanProps.rowsCount; + return cleanProps; + } + + render() { + return ( + + ); + } +} + +DataGrid.propTypes = { +}; + +export default DataGrid; \ No newline at end of file diff --git a/app/javascript/packs/shared/data_table/DataTable.jsx b/app/javascript/packs/shared/data_table/DataTable.jsx new file mode 100644 index 000000000..a313ca56d --- /dev/null +++ b/app/javascript/packs/shared/data_table/DataTable.jsx @@ -0,0 +1,59 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table'; + +class DataTable extends Component { + constructor(props) { + super(props); + this.cleanProps = this.cleanProps.bind(this); + this.displayHeader = this.displayHeader.bind(this); + } + + cleanProps() { + // Remove additional props from the props value + const cleanProps = {...this.props}; + delete cleanProps.columns; + return cleanProps; + } + + displayHeader() { + const orderedCols = [...this.props.columns].sort((a, b) => b.position - a.position); + return orderedCols.map((col) => { + return ( + + ); + }); + } + + render() { + return ( + + {this.displayHeader()} + + ); + } +} + +DataTable.propTypes = { + columns: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.number.isRequired, + isKey: PropTypes.bool.isRequired, + textId: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + position: PropTypes.number.isRequired, + visible: PropTypes.bool, + sortable: PropTypes.bool, + locked: PropTypes.bool + }) + ).isRequired +}; + +export default DataTable; \ No newline at end of file diff --git a/app/javascript/packs/styles/main.scss b/app/javascript/packs/styles/main.scss index 975dbeb83..772249944 100644 --- a/app/javascript/packs/styles/main.scss +++ b/app/javascript/packs/styles/main.scss @@ -1,4 +1,5 @@ @import 'constants'; +@import '~react-bootstrap-table/dist/react-bootstrap-table.min'; body { background-color: $color-concrete; diff --git a/package.json b/package.json index 2f80c6f0e..d6a98afc1 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,8 @@ "styled-components": "^2.1.1", "webpack": "^3.2.0", "webpack-manifest-plugin": "^1.1.2", - "webpack-merge": "^4.1.0" + "webpack-merge": "^4.1.0", + "react-bootstrap-table": "^4.0.0", + "react-data-grid": "^2.0.2" } } From f4f0cd234f3c36880b4e2903525820a2e1832fcc Mon Sep 17 00:00:00 2001 From: Luka Murn Date: Mon, 21 Aug 2017 15:36:22 +0200 Subject: [PATCH 2/5] Add support for sorting to both tables --- .../packs/shared/data_grid/DataGrid.jsx | 106 +++++++++++++----- .../packs/shared/data_table/DataTable.jsx | 42 ++++--- app/javascript/packs/styles/main.scss | 41 +++++++ 3 files changed, 142 insertions(+), 47 deletions(-) diff --git a/app/javascript/packs/shared/data_grid/DataGrid.jsx b/app/javascript/packs/shared/data_grid/DataGrid.jsx index 3f46438ad..00f6c6045 100644 --- a/app/javascript/packs/shared/data_grid/DataGrid.jsx +++ b/app/javascript/packs/shared/data_grid/DataGrid.jsx @@ -11,6 +11,53 @@ class DataGrid extends Component { this.transformColumns(); this.setupDefaultProps(); + + // Store the original rows array, and make a copy that + // can be used for modifying eg.filtering, sorting + this.state = { + originalRows: this.props.data, + rows: this.props.data.slice(0) + }; + } + + setupDefaultProps() { + // Setup the default props if they're not provided + if ('rowGetter' in this.props) { + this._rowGetter = this.props.rowGetter; + } else { + this._rowGetter = ((i) => this.state.rows[i]); + } + this._rowGetter = this._rowGetter.bind(this); + + if ('rowsCount' in this.props) { + this._rowsCount = this.props.rowsCount; + } else { + this._rowsCount = this.props.data.length; + } + + if ('onGridSort' in this.props) { + this._onGridSort = this.props.onGridSort; + } else { + this._onGridSort = ((sortColumn, sortDirection) => { + const comparer = (a, b) => { + if (sortDirection === 'ASC') { + return (a[sortColumn] > b[sortColumn]) ? 1 : -1; + } else if (sortDirection === 'DESC') { + return (a[sortColumn] < b[sortColumn]) ? 1 : -1; + } + return 0; + }; + let rows; + if (sortDirection === 'NONE') { + rows = this.state.originalRows.slice(0); + } else { + rows = this.state.rows.sort(comparer); + } + + this.setState({ rows }); + }); + } + this._onGridSort = this._onGridSort.bind(this); } transformColumns() { @@ -18,41 +65,21 @@ class DataGrid extends Component { // ReactDataGrid-compatible representation this._columns = this.props.columns - .sort((a, b) => b.position - a.position) - .filter((col) => col.visible) - .map((col) => { - return { - key: col.textId, - name: col.name, - locked: col.locked - }; - }); - } - - setupDefaultProps() { - // Setup the default props if they're not provided - const self = this; - - if ('rowGetter' in this.props) { - this._rowGetter = this.props.rowGetter; - } else { - this._rowGetter = function(i) { - return this.props.data[i]; - }.bind(this); - } - if ('rowsCount' in this.props) { - this._rowsCount = this.props.rowsCount; - } else { - this._rowsCount = this.props.data.length; - } + .sort((a, b) => a.position - b.position) + .filter((col) => (!('visible' in col) || col.visible)) + .map((col) => ({ + key: col.textId, + name: col.name, + locked: col.locked, + sortable: col.sortable + })); } cleanProps() { // Remove additional props from the props value - const cleanProps = {...this.props}; - delete cleanProps.columns; - delete cleanProps.rowGetter; - delete cleanProps.rowsCount; + const { + columns, rowGetter, rowsCount, ...cleanProps + } = this.props; return cleanProps; } @@ -62,6 +89,7 @@ class DataGrid extends Component { columns={this._columns} rowGetter={this._rowGetter} rowsCount={this._rowsCount} + onGridSort={this._onGridSort} {...this.cleanProps()} /> ); @@ -69,6 +97,22 @@ class DataGrid extends Component { } DataGrid.propTypes = { + columns: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.number.isRequired, + isKey: PropTypes.bool.isRequired, + textId: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + position: PropTypes.number.isRequired, + visible: PropTypes.bool, + sortable: PropTypes.bool, + locked: PropTypes.bool + }) + ).isRequired, + data: PropTypes.arrayOf(PropTypes.object).isRequired, + rowGetter: PropTypes.func, + rowsCount: PropTypes.number, + onGridSort: PropTypes.func }; export default DataGrid; \ No newline at end of file diff --git a/app/javascript/packs/shared/data_table/DataTable.jsx b/app/javascript/packs/shared/data_table/DataTable.jsx index a313ca56d..58ddf0d53 100644 --- a/app/javascript/packs/shared/data_table/DataTable.jsx +++ b/app/javascript/packs/shared/data_table/DataTable.jsx @@ -3,6 +3,15 @@ import PropTypes from "prop-types"; import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table'; class DataTable extends Component { + static cleanColumnAttributes(col) { + // Remove additional attributes from the columns + const { + id, isKey, textId, name, position, visible, + sortable, locked, ...cleanCol + } = col; + return cleanCol; + } + constructor(props) { super(props); this.cleanProps = this.cleanProps.bind(this); @@ -11,25 +20,25 @@ class DataTable extends Component { cleanProps() { // Remove additional props from the props value - const cleanProps = {...this.props}; - delete cleanProps.columns; + const {columns, ...cleanProps} = this.props; return cleanProps; } + displayHeader() { - const orderedCols = [...this.props.columns].sort((a, b) => b.position - a.position); - return orderedCols.map((col) => { - return ( - - ); - }); + const orderedCols = [...this.props.columns].sort((a, b) => a.position - b.position); + return orderedCols.map((col) => + + ); } render() { @@ -53,7 +62,8 @@ DataTable.propTypes = { sortable: PropTypes.bool, locked: PropTypes.bool }) - ).isRequired + ).isRequired, + data: PropTypes.arrayOf(PropTypes.object).isRequired }; export default DataTable; \ No newline at end of file diff --git a/app/javascript/packs/styles/main.scss b/app/javascript/packs/styles/main.scss index 772249944..6d077be06 100644 --- a/app/javascript/packs/styles/main.scss +++ b/app/javascript/packs/styles/main.scss @@ -7,3 +7,44 @@ body { font-family: "Open Sans",Arial,Helvetica,sans-serif; font-size: 13px; } + +.react-bs-table { + thead { + background-color: #909088; + + > tr > th, + >tr > td { + padding: 6px; + padding-right: 30px; + } + + > tr > th { + border-bottom: 2px solid #ddd; + border-bottom-width: 0; + border-left: 2px solid #fcfcfc; + color: #fff; + font-weight: normal; + vertical-align: bottom; + + &:first-child { + border-left: none; + } + } + } + + td, th { + box-sizing: content-box; + } + + td { + overflow-wrap: break-word; + text-overflow: ellipsis; + word-break: break-word; + } + + .sorting_desc, + .sorting_asc { + background-color: #37a0d9; + } +} + From b70b6091095d67560ea2ea423c4737da900147e4 Mon Sep 17 00:00:00 2001 From: Luka Murn Date: Mon, 21 Aug 2017 17:55:45 +0200 Subject: [PATCH 3/5] Update styling of data grid a bit --- app/javascript/packs/styles/main.scss | 30 ++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/app/javascript/packs/styles/main.scss b/app/javascript/packs/styles/main.scss index 6d077be06..886083ad8 100644 --- a/app/javascript/packs/styles/main.scss +++ b/app/javascript/packs/styles/main.scss @@ -41,10 +41,30 @@ body { text-overflow: ellipsis; word-break: break-word; } - - .sorting_desc, - .sorting_asc { - background-color: #37a0d9; - } } +.react-grid-Main { + background-color: inherit; + + .react-grid-Grid { + background-color: inherit; + } + + .react-grid-Header { + .react-grid-HeaderCell { + background-color: #909088; + + color: #fff; + font-weight: normal; + vertical-align: bottom; + + &:first-child { + border-left: none; + } + } + } + + .react-grid-Canvas { + background-color: inherit; + } +} \ No newline at end of file From 39bb8ecdabd0325a14bdf19b7e6f87734d737c0a Mon Sep 17 00:00:00 2001 From: Luka Murn Date: Wed, 23 Aug 2017 10:54:54 +0200 Subject: [PATCH 4/5] Fix code --- app/javascript/packs/app/constants/colors.js | 4 ++ .../data_grid/{DataGrid.jsx => index.jsx} | 33 +++++++++- .../data_table/{DataTable.jsx => index.jsx} | 48 ++++++++++++++- app/javascript/packs/styles/main.scss | 61 ------------------- yarn.lock | 48 ++++++++++++++- 5 files changed, 126 insertions(+), 68 deletions(-) rename app/javascript/packs/shared/data_grid/{DataGrid.jsx => index.jsx} (84%) rename app/javascript/packs/shared/data_table/{DataTable.jsx => index.jsx} (63%) diff --git a/app/javascript/packs/app/constants/colors.js b/app/javascript/packs/app/constants/colors.js index 9b4ad3aa3..d08c98ede 100644 --- a/app/javascript/packs/app/constants/colors.js +++ b/app/javascript/packs/app/constants/colors.js @@ -3,3 +3,7 @@ export const WHITE_COLOR = "#fff"; export const BORDER_GRAY_COLOR = "#d2d2d2"; export const WILD_SAND_COLOR = "#f5f5f5"; export const MYSTIC_COLOR = "#eaeff2"; + +export const COLOR_ALTO = "#dddddd"; +export const COLOR_GRAY = "#909088"; +export const COLOR_ALABASTER = "#fcfcfc"; diff --git a/app/javascript/packs/shared/data_grid/DataGrid.jsx b/app/javascript/packs/shared/data_grid/index.jsx similarity index 84% rename from app/javascript/packs/shared/data_grid/DataGrid.jsx rename to app/javascript/packs/shared/data_grid/index.jsx index 00f6c6045..ef2709dce 100644 --- a/app/javascript/packs/shared/data_grid/DataGrid.jsx +++ b/app/javascript/packs/shared/data_grid/index.jsx @@ -1,6 +1,37 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; import ReactDataGrid from 'react-data-grid'; +import styled from "styled-components"; +import { + WHITE_COLOR, + COLOR_GRAY +} from "../../app/constants/colors"; + +const StyledReactDataGrid = styled(ReactDataGrid)` + background-color: inherit; + + .react-grid-Grid { + background-color: inherit; + } + + .react-grid-Header { + .react-grid-HeaderCell { + background-color: ${COLOR_GRAY}; + + color: ${WHITE_COLOR}; + font-weight: normal; + vertical-align: bottom; + + &:first-child { + border-left: none; + } + } + } + + .react-grid-Canvas { + background-color: inherit; + } +`; class DataGrid extends Component { constructor(props) { @@ -85,7 +116,7 @@ class DataGrid extends Component { render() { return ( - tr > th, + >tr > td { + padding: 6px; + padding-right: 30px; + } + + > tr > th { + border-bottom: 2px solid ${COLOR_ALTO}; + border-bottom-width: 0; + border-left: 2px solid ${COLOR_ALABASTER}; + color: ${WHITE_COLOR}; + font-weight: normal; + vertical-align: bottom; + + &:first-child { + border-left: none; + } + } + } + + td, th { + box-sizing: content-box; + } + + td { + overflow-wrap: break-word; + text-overflow: ellipsis; + word-break: break-word; + } +`; class DataTable extends Component { static cleanColumnAttributes(col) { @@ -26,7 +68,7 @@ class DataTable extends Component { displayHeader() { - const orderedCols = [...this.props.columns].sort((a, b) => a.position - b.position); + const orderedCols = this.props.columns.sort((a, b) => a.position - b.position); return orderedCols.map((col) => + {this.displayHeader()} - + ); } } diff --git a/app/javascript/packs/styles/main.scss b/app/javascript/packs/styles/main.scss index 886083ad8..772249944 100644 --- a/app/javascript/packs/styles/main.scss +++ b/app/javascript/packs/styles/main.scss @@ -7,64 +7,3 @@ body { font-family: "Open Sans",Arial,Helvetica,sans-serif; font-size: 13px; } - -.react-bs-table { - thead { - background-color: #909088; - - > tr > th, - >tr > td { - padding: 6px; - padding-right: 30px; - } - - > tr > th { - border-bottom: 2px solid #ddd; - border-bottom-width: 0; - border-left: 2px solid #fcfcfc; - color: #fff; - font-weight: normal; - vertical-align: bottom; - - &:first-child { - border-left: none; - } - } - } - - td, th { - box-sizing: content-box; - } - - td { - overflow-wrap: break-word; - text-overflow: ellipsis; - word-break: break-word; - } -} - -.react-grid-Main { - background-color: inherit; - - .react-grid-Grid { - background-color: inherit; - } - - .react-grid-Header { - .react-grid-HeaderCell { - background-color: #909088; - - color: #fff; - font-weight: normal; - vertical-align: bottom; - - &:first-child { - border-left: none; - } - } - } - - .react-grid-Canvas { - background-color: inherit; - } -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index b64ab2ea5..e7cc59fc8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1281,7 +1281,7 @@ clap@^1.0.9: dependencies: chalk "^1.1.3" -classnames@^2.2.5: +classnames@^2.1.2, classnames@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" @@ -1538,7 +1538,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -create-react-class@^15.5.3, create-react-class@^15.6.0: +create-react-class@^15.5.2, create-react-class@^15.5.3, create-react-class@^15.6.0: version "15.6.0" resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4" dependencies: @@ -1879,6 +1879,10 @@ electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.14: version "1.3.15" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.15.tgz#08397934891cbcfaebbd18b82a95b5a481138369" +element-class@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/element-class/-/element-class-0.2.2.tgz#9d3bbd0767f9013ef8e1c8ebe722c1402a60050e" + elliptic@^6.0.0: version "6.4.0" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" @@ -2211,6 +2215,10 @@ evp_bytestokey@^1.0.0: dependencies: create-hash "^1.1.1" +exenv@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.0.tgz#3835f127abf075bfe082d0aed4484057c78e3c89" + exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" @@ -4547,7 +4555,7 @@ prop-types-extra@^1.0.1: dependencies: warning "^3.0.0" -prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8: +prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8: version "15.5.10" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" dependencies: @@ -4651,6 +4659,15 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-bootstrap-table@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/react-bootstrap-table/-/react-bootstrap-table-4.0.2.tgz#7e504141c8662fb203f0bcddab365c331b0e7106" + dependencies: + classnames "^2.1.2" + prop-types "^15.5.10" + react-modal "^1.4.0" + react-s-alert "^1.3.0" + react-bootstrap@^0.31.1: version "0.31.1" resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-0.31.1.tgz#679c9f73ae77ff207867d536496207291f3a3ed7" @@ -4667,6 +4684,14 @@ react-bootstrap@^0.31.1: uncontrollable "^4.1.0" warning "^3.0.0" +react-data-grid@^2.0.2: + version "2.0.58" + resolved "https://registry.yarnpkg.com/react-data-grid/-/react-data-grid-2.0.58.tgz#83946bf9cc34d144552349c343e15888c2c6293c" + +react-dom-factories@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/react-dom-factories/-/react-dom-factories-1.0.1.tgz#c50692ac5ff1adb39d86dfe6dbe3485dacf58455" + react-dom@^15.6.1: version "15.6.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.6.1.tgz#2cb0ed4191038e53c209eb3a79a23e2a4cf99470" @@ -4692,6 +4717,17 @@ react-intl@^2.3.0: intl-relativeformat "^1.3.0" invariant "^2.1.1" +react-modal@^1.4.0: + version "1.9.7" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-1.9.7.tgz#07ef56790b953e3b98ef1e2989e347983c72871d" + dependencies: + create-react-class "^15.5.2" + element-class "^0.2.0" + exenv "1.2.0" + lodash.assign "^4.2.0" + prop-types "^15.5.7" + react-dom-factories "^1.0.0" + react-overlays@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.7.0.tgz#531898ff566c7e5c7226ead2863b8cf9fbb5a981" @@ -4747,6 +4783,12 @@ react-router@^4.1.1: prop-types "^15.5.4" warning "^3.0.0" +react-s-alert@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/react-s-alert/-/react-s-alert-1.3.0.tgz#d81224a474f15e89c35c0ea6c2a73f232a767128" + dependencies: + babel-runtime "^6.23.0" + react@^15.6.1: version "15.6.1" resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df" From 66ee2af132316005d1de4be1aa3e620a443b41b2 Mon Sep 17 00:00:00 2001 From: zmagod Date: Thu, 24 Aug 2017 09:20:44 +0200 Subject: [PATCH 5/5] fix eslint import/no-unresolved errors reports [fixes SCI-1570] --- .eslintrc.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 79a1fecc8..449df5b6f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -17,12 +17,7 @@ } }, "rules": { - "import/no-unresolved": [ - "error", - { - "ignore": ["app/javascript/"] - } - ], + "import/no-unresolved": [2, {"commonjs": true, "amd": true}], "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], "spaced-comment": [ "error",