diff --git a/.eslintrc b/.eslintrc index dcf40fae..f50c9716 100644 --- a/.eslintrc +++ b/.eslintrc @@ -28,6 +28,12 @@ } }, "rules": { + "max-len": ["error", { + "code": 120, + "ignoreStrings": true, + "ignoreTemplateLiterals": true + }], + "no-mixed-operators": "off", "comma-dangle": ["error", "always-multiline"], "no-invalid-this": "off", "no-inline-comments": "off", @@ -55,6 +61,12 @@ "@shlinkio/js-coding-standard" ], "rules": { + "max-len": ["error", { + "code": 120, + "ignoreStrings": true, + "ignoreTemplateLiterals": true + }], + "no-mixed-operators": "off", "react/display-name": "off" } } diff --git a/jest.config.js b/jest.config.js index 3c0762c6..f698a928 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,7 @@ module.exports = { coverageDirectory: '/coverage', collectCoverageFrom: [ - 'src/**/*.js', + 'src/**/*.{js,jsx,ts,tsx}', '!src/registerServiceWorker.js', '!src/index.js', '!src/reducers/index.js', diff --git a/package-lock.json b/package-lock.json index 703cd958..31584ce3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2051,6 +2051,33 @@ "@types/node": "*" } }, + "@types/history": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.7.tgz", + "integrity": "sha512-2xtoL22/3Mv6a70i4+4RB7VgbDDORoWwjcqeNysojZA0R7NK17RbY5Gof/2QiFfJgX+KkWghbwJ+d/2SB8Ndzg==", + "dev": true + }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, + "requires": { + "react-is": "^16.7.0" + } + } + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", @@ -2225,12 +2252,81 @@ "integrity": "sha512-Otxmr2rrZLKRYIybtdG/sgeO+tHY20GxeDjcGmUnmmlCWyEnv2a2x1ZXBo3BTec4OiTXMQCiazB8NMBf0iRlFw==", "dev": true }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true + }, "@types/q": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", "dev": true }, + "@types/react": { + "version": "16.9.46", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.46.tgz", + "integrity": "sha512-dbHzO3aAq1lB3jRQuNpuZ/mnu+CdD3H0WVaaBQA8LTT3S33xhVBUj232T8M3tAhSWJs/D/UqORYUlJNl/8VQZg==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "16.9.8", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz", + "integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-redux": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.9.tgz", + "integrity": "sha512-mpC0jqxhP4mhmOl3P4ipRsgTgbNofMRXJb08Ms6gekViLj61v1hOZEKWDCyWsdONr6EjEA6ZHXC446wdywDe0w==", + "dev": true, + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, + "requires": { + "react-is": "^16.7.0" + } + } + } + }, + "@types/react-router": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.8.tgz", + "integrity": "sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*" + } + }, + "@types/react-router-dom": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.5.tgz", + "integrity": "sha512-ArBM4B1g3BWLGbaGvwBGO75GNFbLDUthrDojV2vHLih/Tq8M+tgvY1DSwkuNrPSwdp/GUL93WSEpTZs8nVyJLw==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*", + "@types/react-router": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -5673,6 +5769,12 @@ "cssom": "0.3.x" } }, + "csstype": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.2.tgz", + "integrity": "sha512-ofovWglpqoqbfLNOTBNZLSbMuGrblAf1efvvArGKOZMBrIoJeu5UsAipQolkijtyQx5MtAzT/J9IHj/CEY1mJw==", + "dev": true + }, "csvjson": { "version": "5.1.0", "resolved": "https://registry.yarnpkg.com/csvjson/-/csvjson-5.1.0.tgz", @@ -7298,7 +7400,7 @@ }, "load-json-file": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "resolved": "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { @@ -7362,7 +7464,7 @@ }, "parse-json": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "resolved": "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { @@ -7371,7 +7473,7 @@ }, "path-type": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "resolved": "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz", "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { @@ -7380,13 +7482,13 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "read-pkg": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "resolved": "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz", "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { @@ -7397,7 +7499,7 @@ }, "read-pkg-up": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "resolved": "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz", "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { diff --git a/package.json b/package.json index 46d11128..50cdcf77 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,10 @@ "@stryker-mutator/javascript-mutator": "^3.2.4", "@stryker-mutator/jest-runner": "^3.2.4", "@svgr/webpack": "^4.3.3", + "@types/react": "^16.9.46", + "@types/react-dom": "^16.9.8", + "@types/react-redux": "^7.1.9", + "@types/react-router-dom": "^5.1.5", "adm-zip": "^0.4.13", "autoprefixer": "^9.6.3", "babel-core": "7.0.0-bridge.0", diff --git a/shlink-web-client.d.ts b/shlink-web-client.d.ts new file mode 100644 index 00000000..bbe9db86 --- /dev/null +++ b/shlink-web-client.d.ts @@ -0,0 +1,5 @@ +export declare global { + interface Window { + __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: Function; + } +} diff --git a/src/container/store.js b/src/container/store.ts similarity index 59% rename from src/container/store.js rename to src/container/store.ts index 754f3569..70ea604e 100644 --- a/src/container/store.js +++ b/src/container/store.ts @@ -1,13 +1,12 @@ import ReduxThunk from 'redux-thunk'; import { applyMiddleware, compose, createStore } from 'redux'; -import { save, load } from 'redux-localstorage-simple'; +import { save, load, RLSOptions } from 'redux-localstorage-simple'; import reducers from '../reducers'; -const composeEnhancers = process.env.NODE_ENV !== 'production' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ - ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ - : compose; +const isProduction = process.env.NODE_ENV !== 'production'; +const composeEnhancers: Function = !isProduction && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; -const localStorageConfig = { +const localStorageConfig: RLSOptions = { states: [ 'settings', 'servers' ], namespace: 'shlink', namespaceSeparator: '.', diff --git a/src/index.js b/src/index.tsx similarity index 100% rename from src/index.js rename to src/index.tsx index 333d5115..822c2988 100644 --- a/src/index.js +++ b/src/index.tsx @@ -1,4 +1,3 @@ -import 'bootstrap/dist/css/bootstrap.min.css'; import React from 'react'; import { render } from 'react-dom'; import { Provider } from 'react-redux'; @@ -8,6 +7,7 @@ import registerServiceWorker from './registerServiceWorker'; import container from './container'; import store from './container/store'; import { fixLeafletIcons } from './utils/utils'; +import 'bootstrap/dist/css/bootstrap.min.css'; import 'react-datepicker/dist/react-datepicker.css'; import 'leaflet/dist/leaflet.css'; import './common/react-tagsinput.scss'; diff --git a/src/reducers/index.js b/src/reducers/index.ts similarity index 100% rename from src/reducers/index.js rename to src/reducers/index.ts