diff --git a/.eslintrc-calypso.js b/.eslintrc-calypso.js new file mode 100644 index 0000000000000..5549c5e45041d --- /dev/null +++ b/.eslintrc-calypso.js @@ -0,0 +1,57 @@ +/** @format */ + +const reactVersion = require( './package.json' ).dependencies.react; + +module.exports = { + root: true, + extends: [ + 'wpcalypso/react', + 'plugin:jsx-a11y/recommended', + // 'prettier', + // 'prettier/react', + ], + parser: 'babel-eslint', + env: { + browser: true, + mocha: true, + node: true, + jquery: true + }, + plugins: [ 'jsx-a11y', 'lodash' ], + settings: { + react: { + version: reactVersion, + }, + }, + rules: { + // REST API objects include underscores + camelcase: 0, + + // TODO: shorten all long lines + 'max-len': 0, + + // i18n-calypso translate triggers false failures + 'jsx-a11y/anchor-has-content': 0, + + 'wpcalypso/jsx-classname-namespace': 0, + // enforce our classname namespacing rules + // 'wpcalypso/jsx-classname-namespace': [ + // 2, + // { + // rootFiles: [ 'index.js', 'index.jsx', 'main.js', 'main.jsx' ], + // }, + // ], + + // Force folks to use our custom combineReducers function instead of the plain redux one + // This allows us to control serialization for every reducer. + 'wpcalypso/import-no-redux-combine-reducers': 2, + + // No applicable in Jetpack + 'wpcalypso/import-no-redux-combine-reducers': 0, + + // TODO: migrate to ES6 Classes + 'react/prefer-es6-class': 0, + + 'jsx-a11y/no-static-element-interactions': 0, + }, +}; diff --git a/.eslintrc.js b/.eslintrc.js index 4d7c9282a0a47..23e2d87484f83 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -61,7 +61,7 @@ module.exports = { "react/no-did-mount-set-state": 2, "react/no-did-update-set-state": 2, "react/no-is-mounted": 2, - "react/prefer-es6-class": 1, + "react/prefer-es6-class": 0, "semi": 2, "semi-spacing": 2, "space-before-blocks": [ 2, "always" ], diff --git a/_inc/client/at-a-glance/index.jsx b/_inc/client/at-a-glance/index.jsx index c86fe89c74f78..dd79dd253c2da 100644 --- a/_inc/client/at-a-glance/index.jsx +++ b/_inc/client/at-a-glance/index.jsx @@ -47,6 +47,10 @@ const renderPairs = layout => layout.map( item => ( ) ); class AtAGlance extends Component { + trackSecurityClick() { + analytics.tracks.recordJetpackClick( 'aag_manage_security_wpcom' ); + } + render() { const settingsProps = { updateOptions: this.props.updateOptions, @@ -57,7 +61,6 @@ class AtAGlance extends Component { siteAdminUrl: this.props.siteAdminUrl, siteRawUrl: this.props.siteRawUrl }; - const trackSecurityClick = () => analytics.tracks.recordJetpackClick( 'aag_manage_security_wpcom' ); const securityHeader = ; const connections = (
diff --git a/_inc/client/at-a-glance/monitor.jsx b/_inc/client/at-a-glance/monitor.jsx index 710827f9c072e..c798a4ffaa63e 100644 --- a/_inc/client/at-a-glance/monitor.jsx +++ b/_inc/client/at-a-glance/monitor.jsx @@ -20,6 +20,18 @@ class DashMonitor extends Component { isModuleAvailable: PropTypes.bool.isRequired, }; + activateAndTrack() { + analytics.tracks.recordEvent( + 'jetpack_wpa_module_toggle', + { + module: 'monitor', + toggled: 'on' + } + ); + + this.props.updateOptions( { monitor: true } ); + } + getContent() { const labelName = __( 'Downtime monitoring' ); @@ -28,18 +40,6 @@ class DashMonitor extends Component { link: 'https://jetpack.com/support/monitor/', }; - const activateAndTrack = () => { - analytics.tracks.recordEvent( - 'jetpack_wpa_module_toggle', - { - module: 'monitor', - toggled: 'on' - } - ); - - this.props.updateOptions( { monitor: true } ); - }; - if ( this.props.getOptionValue( 'monitor' ) ) { return ( + a: } } ) diff --git a/_inc/client/at-a-glance/photon.jsx b/_inc/client/at-a-glance/photon.jsx index eab5a55a4cdd8..bbe318837817e 100644 --- a/_inc/client/at-a-glance/photon.jsx +++ b/_inc/client/at-a-glance/photon.jsx @@ -19,10 +19,12 @@ class DashPhoton extends Component { isModuleAvailable: PropTypes.bool.isRequired, }; - getContent() { - const labelName = __( 'Image Performance' ), - activatePhoton = () => this.props.updateOptions( { photon: true } ); + activatePhoton() { + this.props.updateOptions( { photon: true } ); + } + getContent() { + const labelName = __( 'Image Performance' ); const support = { text: __( 'Jetpack will optimize your images and serve them from the server location nearest to your visitors. Using our global content delivery network will boost the loading speed of your site.' ), link: 'https://jetpack.com/support/photon/', @@ -51,7 +53,7 @@ class DashPhoton extends Component { this.props.isDevMode ? __( 'Unavailable in Dev Mode' ) : __( '{{a}}Activate{{/a}} to enhance the performance and speed of your images.', { components: { - a: + a: } } ) diff --git a/_inc/client/at-a-glance/protect.jsx b/_inc/client/at-a-glance/protect.jsx index 6102c0347b5fa..3c352178c1cdb 100644 --- a/_inc/client/at-a-glance/protect.jsx +++ b/_inc/client/at-a-glance/protect.jsx @@ -22,12 +22,15 @@ class DashProtect extends Component { isModuleAvailable: PropTypes.bool.isRequired, }; + activateProtect() { + this.props.updateOptions( { protect: true } ); + } + getContent() { const support = { text: __( 'Protects your site from traditional and distributed brute force login attacks.' ), link: 'https://jetpack.com/support/protect/', }; - const activateProtect = () => this.props.updateOptions( { protect: true } ); if ( this.props.getOptionValue( 'protect' ) ) { const protectCount = this.props.protectCount; @@ -72,7 +75,7 @@ class DashProtect extends Component { this.props.isDevMode ? __( 'Unavailable in Dev Mode' ) : __( '{{a}}Activate Protect{{/a}} to keep your site protected from malicious sign in attempts.', { components: { - a: + a: } } ) diff --git a/_inc/client/at-a-glance/search.jsx b/_inc/client/at-a-glance/search.jsx index 7c679d4c23c85..2c57e9235be18 100644 --- a/_inc/client/at-a-glance/search.jsx +++ b/_inc/client/at-a-glance/search.jsx @@ -55,9 +55,12 @@ class DashSearch extends Component { isDevMode: false, }; + activateSearch() { + this.props.updateOptions( { search: true } ); + } + render() { - const hasPro = ( 'is-business-plan' === this.props.planClass ), - activateSearch = () => this.props.updateOptions( { search: true } ); + const hasPro = ( 'is-business-plan' === this.props.planClass ); if ( this.props.isDevMode ) { return renderCard( { @@ -111,7 +114,7 @@ class DashSearch extends Component { pro_inactive: false, content: __( '{{a}}Activate{{/a}} to replace the WordPress built-in search with Jetpack Search, an advanced search experience.', { components: { - a: + a: } } ) } ); diff --git a/_inc/client/at-a-glance/stats/dash-stats-bottom.jsx b/_inc/client/at-a-glance/stats/dash-stats-bottom.jsx index 06a103c72f499..b285bc28cbb37 100644 --- a/_inc/client/at-a-glance/stats/dash-stats-bottom.jsx +++ b/_inc/client/at-a-glance/stats/dash-stats-bottom.jsx @@ -41,10 +41,16 @@ class DashStatsBottom extends Component { ]; } + trackViewDetailedStats() { + analytics.tracks.recordJetpackClick( 'view_detailed_stats' ); + } + + trackViewWpcomStats() { + analytics.tracks.recordJetpackClick( 'view_wpcom_stats' ); + } + render() { const s = this.statsBottom()[ 0 ]; - const trackViewDetailedStats = () => analytics.tracks.recordJetpackClick( 'view_detailed_stats' ), - trackViewWpcomStats = () => analytics.tracks.recordJetpackClick( 'view_wpcom_stats' ); return (
@@ -102,7 +108,7 @@ class DashStatsBottom extends Component { components: { button: @@ -356,17 +357,17 @@ class PlanGrid extends React.Component { ); } + featureLinkclickHandler( featureID ) { + analytics.tracks.recordJetpackClick( { + target: featureID, + type: 'feature-discovery', + plan: this.props.sitePlan.product_slug, + page: 'Plans' + } ); + } renderFeatureLink( feature ) { - const clickHandler = () => { - analytics.tracks.recordJetpackClick( { - target: feature.id, - type: 'feature-discovery', - plan: this.props.sitePlan.product_slug, - page: 'Plans' - } ); - }; return ( - { feature.name } + { feature.name } ); } diff --git a/_inc/client/privacy/index.jsx b/_inc/client/privacy/index.jsx index 03f9cc2ab4948..0721940aee85f 100644 --- a/_inc/client/privacy/index.jsx +++ b/_inc/client/privacy/index.jsx @@ -79,7 +79,7 @@ class Privacy extends React.Component { this.props.setTrackingSettings( ! current ); }; - componentWillMount() { + UNSAFE_componentWillMount() { this.props.fetchTrackingSettings(); } diff --git a/_inc/client/security/antispam.jsx b/_inc/client/security/antispam.jsx index d15094c31f188..04c21b1a5cabd 100644 --- a/_inc/client/security/antispam.jsx +++ b/_inc/client/security/antispam.jsx @@ -36,7 +36,7 @@ export const Antispam = moduleSettingsForm( keyChanged = false; - componentWillMount() { + UNSAFE_componentWillMount() { this.debouncedCheckApiKeyTyped = debounce( this.checkApiKeyTyped, 500 ); } diff --git a/_inc/client/static-main.jsx b/_inc/client/static-main.jsx index dc57211d2dff9..e3f28a729b969 100644 --- a/_inc/client/static-main.jsx +++ b/_inc/client/static-main.jsx @@ -14,7 +14,7 @@ import { setInitialState } from 'state/initial-state'; import Footer from 'components/footer'; class StaticMain extends React.Component { - componentWillMount() { + UNSAFE_componentWillMount() { this.props.setInitialState(); } diff --git a/package.json b/package.json index 5ba836ce38fe1..7318cb4bbe1d3 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "eslint-loader": "2.1.1", "eslint-plugin-jsx-a11y": "4.0.0", "eslint-plugin-lodash": "5.1.0", - "eslint-plugin-react": "6.10.3", + "eslint-plugin-react": "7.11.1", "eslint-plugin-wpcalypso": "4.0.2", "extract-text-webpack-plugin": "3.0.2", "fancy-log": "1.3.3", diff --git a/yarn.lock b/yarn.lock index bf8168df30bc4..0cca092b57232 100644 --- a/yarn.lock +++ b/yarn.lock @@ -358,6 +358,13 @@ array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + array-initial@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/array-initial/-/array-initial-1.1.0.tgz#2fa74b26739371c3947bd7a7adc73be334b3d795" @@ -401,13 +408,6 @@ array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" -array.prototype.find@^2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.4.tgz#556a5c5362c08648323ddaeb9de9d14bc1864c90" - dependencies: - define-properties "^1.1.2" - es-abstract "^1.7.0" - array.prototype.flat@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz#812db8f02cad24d3fab65dd67eabe3b8903494a4" @@ -2356,14 +2356,7 @@ discontinuous-range@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" -doctrine@^1.2.2: - version "1.5.0" - resolved "http://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^2.0.0: +doctrine@^2.0.0, doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: @@ -2720,15 +2713,15 @@ eslint-plugin-lodash@5.1.0: dependencies: lodash "4.17.11" -eslint-plugin-react@6.10.3: - version "6.10.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz#c5435beb06774e12c7db2f6abaddcbf900cd3f78" +eslint-plugin-react@7.11.1: + version "7.11.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz#c01a7af6f17519457d6116aa94fc6d2ccad5443c" dependencies: - array.prototype.find "^2.0.1" - doctrine "^1.2.2" - has "^1.0.1" - jsx-ast-utils "^1.3.4" - object.assign "^4.0.4" + array-includes "^3.0.3" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.2" eslint-plugin-wpcalypso@4.0.2: version "4.0.2" @@ -4577,10 +4570,16 @@ jstimezonedetect@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/jstimezonedetect/-/jstimezonedetect-1.0.5.tgz#93d035cd20e8c7d64eb1375cf5aa7a10a024466a" -jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.3.4: +jsx-ast-utils@^1.0.0: version "1.4.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" +jsx-ast-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + dependencies: + array-includes "^3.0.3" + just-debounce@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea"