diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..4fed319ba --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +dist/ +ssr.js +node_modules/ +package-lock.json \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..8a03afb6d --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,30 @@ +/* eslint-disable */ + +module.exports = { + root: true, + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaFeatures: { jsx: true }, + }, + settings: { + react: { + version: "detect", + }, + }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:prettier/recommended", + ], + rules: { + // Include .prettierrc.js rules + "prettier/prettier": ["error", {}, { usePrettierrc: true }], + "react/react-in-jsx-scope": "off", + "react/prop-types": "off", + "react/jsx-no-target-blank": ["error", { "allowReferrer": true }], + "@typescript-eslint/no-explicit-any": "off", // TODO: turn this on in future + "@typescript-eslint/explicit-module-boundary-types": "off" // TODO: turn this on in future + }, +}; diff --git a/.prettierrc b/.prettierrc index 5f38c1702..b4278a70d 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,8 @@ { + "semi": false, "trailingComma": "es5", "singleQuote": false, - "printWidth": 200, + "printWidth": 160, "tabWidth": 2, "useTabs": false -} +} \ No newline at end of file diff --git a/Makefile b/Makefile index cb744aaa7..8b2e0312a 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ lint-server: ## Lint server code golangci-lint run lint-ui: ## Lint ui code - npx tslint -c tslint.json 'public/**/*.{ts,tsx}' 'tests/**/*.{ts,tsx}' + npx eslint . diff --git a/esbuild-shim.js b/esbuild-shim.js index 3369f910b..4007b848a 100644 --- a/esbuild-shim.js +++ b/esbuild-shim.js @@ -1,23 +1,23 @@ -const global = (1, eval)('this'); -global.global = global; -global.globalThis = global; -global.frames = global; -global.self = global; +const global = (1, eval)("this") +global.global = global +global.globalThis = global +global.frames = global +global.self = global const document = { documentElement: {}, - getElementById: () => undefined + getElementById: () => undefined, } const window = { document, location: { - href: '' - } + href: "", + }, } const navigator = {} -global.navigator = navigator; -global.window = window; -global.document = document; \ No newline at end of file +global.navigator = navigator +global.window = window +global.document = document diff --git a/esbuild.config.js b/esbuild.config.js index ed9a37689..67e0cfb6a 100644 --- a/esbuild.config.js +++ b/esbuild.config.js @@ -1,17 +1,21 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable no-undef */ let emptyCSS = { - name: 'empty-css-imports', + name: "empty-css-imports", setup(build) { - build.onLoad({ filter: /\.(css|scss)$/ }, () => ({ contents: '' })) + build.onLoad({ filter: /\.(css|scss)$/ }, () => ({ contents: "" })) }, } -require('esbuild').build({ - entryPoints: ['./public/ssr.tsx'], - bundle: true, - define: { - "process.env.NODE_ENV": `"${process.env.NODE_ENV || 'development'}"` - }, - inject: ['./esbuild-shim.js'], - outfile: 'ssr.js', - plugins: [emptyCSS], -}).catch(() => process.exit(1)) +require("esbuild") + .build({ + entryPoints: ["./public/ssr.tsx"], + bundle: true, + define: { + "process.env.NODE_ENV": `"${process.env.NODE_ENV || "development"}"`, + }, + inject: ["./esbuild-shim.js"], + outfile: "ssr.js", + plugins: [emptyCSS], + }) + .catch(() => process.exit(1)) diff --git a/package-lock.json b/package-lock.json index 3fc3099f7..de1aff44a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,11 +27,19 @@ "@types/react": "17.0.3", "@types/react-dom": "17.0.3", "@types/react-textarea-autosize": "4.3.5", + "@typescript-eslint/eslint-plugin": "4.18.0", + "@typescript-eslint/parser": "4.18.0", "@wojtekmaj/enzyme-adapter-react-17": "0.5.0", + "autoprefixer": "10.2.5", "css-loader": "5.1.1", "dotenv": "8.2.0", "enzyme": "3.11.0", "esbuild": "0.9.5", + "eslint": "7.22.0", + "eslint-config-prettier": "8.1.0", + "eslint-plugin-prettier": "3.3.1", + "eslint-plugin-react": "7.22.0", + "eslint-plugin-react-hooks": "4.2.0", "file-loader": "6.2.0", "fork-ts-checker-webpack-plugin": "6.1.1", "jest": "26.6.3", @@ -43,10 +51,6 @@ "sass-loader": "11.0.1", "ts-jest": "26.5.3", "ts-loader": "8.0.17", - "tslint": "6.1.3", - "tslint-config-prettier": "1.18.0", - "tslint-plugin-prettier": "2.3.0", - "tslint-react": "5.0.0", "typescript": "4.2.3", "webpack": "5.24.3", "webpack-bundle-analyzer": "4.4.0", @@ -58,12 +62,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.10.4" } }, "node_modules/@babel/compat-data": { @@ -103,6 +107,15 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -544,6 +557,15 @@ "@babel/types": "^7.12.13" } }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, "node_modules/@babel/traverse": { "version": "7.13.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", @@ -561,6 +583,24 @@ "lodash": "^4.17.19" } }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { "version": "7.13.12", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.12.tgz", @@ -603,6 +643,50 @@ "node": ">=10.0.0" } }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", + "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -773,6 +857,7 @@ "jest-resolve": "^26.6.2", "jest-util": "^26.6.2", "jest-worker": "^26.6.2", + "node-notifier": "^8.0.0", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -873,6 +958,41 @@ "node": ">= 10.14.2" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.11", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz", @@ -1181,6 +1301,163 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.18.0.tgz", + "integrity": "sha512-Lzkc/2+7EoH7+NjIWLS2lVuKKqbEmJhtXe3rmfA8cyiKnZm3IfLf51irnBcmow8Q/AptVV0XBZmBJKuUJTe6cQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "4.18.0", + "@typescript-eslint/scope-manager": "4.18.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.15", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.18.0.tgz", + "integrity": "sha512-92h723Kblt9JcT2RRY3QS2xefFKar4ZQFVs3GityOKWQYgtajxt/tuXIzL7sVCUlM1hgreiV5gkGYyBpdOwO6A==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.18.0", + "@typescript-eslint/types": "4.18.0", + "@typescript-eslint/typescript-estree": "4.18.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.18.0.tgz", + "integrity": "sha512-W3z5S0ZbecwX3PhJEAnq4mnjK5JJXvXUDBYIYGoweCyWyuvAKfGHvzmpUzgB5L4cRBb+cTu9U/ro66dx7dIimA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "4.18.0", + "@typescript-eslint/types": "4.18.0", + "@typescript-eslint/typescript-estree": "4.18.0", + "debug": "^4.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.18.0.tgz", + "integrity": "sha512-olX4yN6rvHR2eyFOcb6E4vmhDPsfdMyfQ3qR+oQNkAv8emKKlfxTWUXU5Mqxs2Fwe3Pf1BoPvrwZtwngxDzYzQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.18.0", + "@typescript-eslint/visitor-keys": "4.18.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.18.0.tgz", + "integrity": "sha512-/BRociARpj5E+9yQ7cwCF/SNOWwXJ3qhjurMuK2hIFUbr9vTuDeu476Zpu+ptxY2kSxUHDGLLKy+qGq2sOg37A==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.18.0.tgz", + "integrity": "sha512-wt4xvF6vvJI7epz+rEqxmoNQ4ZADArGQO9gDU+cM0U5fdVv7N+IAuVoVAoZSOZxzGHBfvE3XQMLdy+scsqFfeg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.18.0", + "@typescript-eslint/visitor-keys": "4.18.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.18.0.tgz", + "integrity": "sha512-Q9t90JCvfYaN0OfFUgaLqByOfz8yPeTAdotn/XYNm5q9eHax90gzdb+RJ6E9T5s97Kv/UHWKERTmqA0jTKAEHw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.18.0", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", @@ -1409,9 +1686,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", - "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1430,16 +1707,13 @@ "acorn-walk": "^7.1.1" } }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/acorn-walk": { @@ -1507,12 +1781,12 @@ } }, "node_modules/ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "dependencies": { - "type-fest": "^0.11.0" + "type-fest": "^0.21.3" }, "engines": { "node": ">=8" @@ -1521,6 +1795,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", @@ -1625,6 +1911,34 @@ "node": ">=0.10.0" } }, + "node_modules/array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -1664,6 +1978,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -1691,6 +2023,15 @@ "node": ">=0.10.0" } }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/async-foreach": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", @@ -1727,17 +2068,44 @@ "node": ">= 4.5.0" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "node_modules/autoprefixer": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.5.tgz", + "integrity": "sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA==", "dev": true, + "dependencies": { + "browserslist": "^4.16.3", + "caniuse-lite": "^1.0.30001196", + "colorette": "^1.2.2", + "fraction.js": "^4.0.13", + "normalize-range": "^0.1.2", + "postcss-value-parser": "^4.1.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "dev": true @@ -2059,15 +2427,6 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, - "node_modules/builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -2236,6 +2595,7 @@ "dependencies": { "anymatch": "~3.1.1", "braces": "~3.0.2", + "fsevents": "~2.3.1", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -2843,15 +3203,6 @@ "integrity": "sha512-xd4D8kHQtB0KtWW0c9xBZD5LVtm9chkMOfs/3Yn01RhT/sFIsVtzTtypfKoFfWBaL+7xCYLxjOLkhwPXaX/Kcg==", "dev": true }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/diff-sequences": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", @@ -2861,12 +3212,36 @@ "node": ">= 10.14.2" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/discontinuous-range": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", "dev": true }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dom-serializer": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", @@ -2974,9 +3349,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.3.695", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.695.tgz", - "integrity": "sha512-lz66RliUqLHU1Ojxx1A4QUxKydjiQ79Y4dZyPobs2Dmxj5aVL2TM3KoQ2Gs7HS703Bfny+ukI3KOxwAB0xceHQ==", + "version": "1.3.700", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.700.tgz", + "integrity": "sha512-wQtaxVZzpOeCjW1CGuC5W3bYjE2jglvk076LcTautBOB9UtHztty7wNzjVsndiMcSsdUsdMy5w76w5J1U7OPTQ==", "dev": true }, "node_modules/emittery": { @@ -3287,7 +3662,8 @@ "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1" + "optionator": "^0.8.1", + "source-map": "~0.6.1" }, "bin": { "escodegen": "bin/escodegen.js", @@ -3300,27 +3676,201 @@ "source-map": "~0.6.1" } }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.22.0.tgz", + "integrity": "sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.21", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz", + "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-plugin-prettier": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz", - "integrity": "sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", + "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", "dev": true, "dependencies": { - "fast-diff": "^1.1.1", - "jest-docblock": "^21.0.0" + "prettier-linter-helpers": "^1.0.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=6.0.0" }, "peerDependencies": { - "prettier": ">= 0.11.0" + "eslint": ">=5.0.0", + "prettier": ">=1.13.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } } }, - "node_modules/eslint-plugin-prettier/node_modules/jest-docblock": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz", - "integrity": "sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==", - "dev": true + "node_modules/eslint-plugin-react": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz", + "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.1", + "array.prototype.flatmap": "^1.2.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "object.entries": "^1.1.2", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.18.1", + "string.prototype.matchall": "^4.0.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", + "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } }, "node_modules/eslint-scope": { "version": "5.1.1", @@ -3335,13 +3885,60 @@ "node": ">=8.0.0" } }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, "engines": { - "node": ">=4.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" } }, "node_modules/esprima": { @@ -3357,6 +3954,27 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -3369,7 +3987,7 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { + "node_modules/esrecurse/node_modules/estraverse": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", @@ -3378,6 +3996,15 @@ "node": ">=4.0" } }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3397,9 +4024,9 @@ } }, "node_modules/exec-sh": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.5.tgz", - "integrity": "sha512-0hzpaUazv4mEccxdn3TXC+HWNeVXNKMCJRK6E7Xyg+LwGAYI3yFag6jTkd4injV+kChYDQS1ftqDhnDVWNhU8A==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", "dev": true }, "node_modules/execa": { @@ -3665,6 +4292,7 @@ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, "dependencies": { + "@types/yauzl": "^2.9.1", "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" @@ -3700,6 +4328,23 @@ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -3718,6 +4363,15 @@ "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", "dev": true }, + "node_modules/fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fb-watchman": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", @@ -3736,6 +4390,18 @@ "pend": "~1.2.0" } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/file-loader": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", @@ -3781,6 +4447,25 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, "node_modules/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -3855,6 +4540,15 @@ "node": ">= 0.12" } }, + "node_modules/fraction.js": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.13.tgz", + "integrity": "sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -3950,6 +4644,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "node_modules/functions-have-names": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", @@ -4108,34 +4808,69 @@ "node": "*" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz", + "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/globby": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" }, "engines": { - "node": ">= 6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "node_modules/globby/node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true, "engines": { - "node": ">=4" + "node": ">= 4" } }, "node_modules/globule": { @@ -4472,6 +5207,15 @@ } ] }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4547,6 +5291,20 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -5209,6 +5967,7 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -5627,6 +6386,18 @@ } } }, + "node_modules/jsdom/node_modules/acorn": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", + "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5663,6 +6434,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -5690,6 +6467,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -5711,6 +6489,19 @@ "verror": "1.10.0" } }, + "node_modules/jsx-ast-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", + "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.2", + "object.assign": "^4.1.2" + }, + "engines": { + "node": ">=4.0" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -5748,13 +6539,13 @@ } }, "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -5865,12 +6656,6 @@ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", "dev": true }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6105,6 +6890,15 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", @@ -6556,6 +7350,15 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -6870,17 +7673,17 @@ } }, "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" }, "engines": { "node": ">= 0.8.0" @@ -7225,9 +8028,9 @@ "dev": true }, "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -7245,6 +8048,18 @@ "node": ">=10.13.0" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -7386,6 +8201,26 @@ "node": ">=0.6" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", @@ -7650,6 +8485,34 @@ "node": ">=0.10.0" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -7795,6 +8658,15 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -7860,6 +8732,16 @@ "node": ">=0.12" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -7894,6 +8776,29 @@ "node": "6.* || >= 7.*" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -8609,6 +9514,20 @@ "dev": true, "optional": true }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -8644,6 +9563,32 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -9143,6 +10088,24 @@ "node": ">=0.10.0" } }, + "node_modules/string.prototype.matchall": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", + "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz", @@ -9240,37 +10203,109 @@ "node": ">=0.10.0" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", + "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/table": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", + "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", + "dev": true, + "dependencies": { + "ajv": "^7.0.2", + "lodash": "^4.17.20", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.3.tgz", + "integrity": "sha512-idv5WZvKVXDqKralOImQgPM9v6WOdLNa0IY3B3doOjw/YxRGT8I+allIJ6kd7Uaj+SF1xZUSU+nPM5aDNBVtnw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } }, - "node_modules/supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, "node_modules/tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -9452,6 +10487,12 @@ "node": ">=8" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "node_modules/throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", @@ -9662,94 +10703,7 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" }, - "node_modules/tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" - } - }, - "node_modules/tslint-config-prettier": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", - "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", - "dev": true, - "bin": { - "tslint-config-prettier-check": "bin/check.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/tslint-plugin-prettier": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslint-plugin-prettier/-/tslint-plugin-prettier-2.3.0.tgz", - "integrity": "sha512-F9e4K03yc9xuvv+A0v1EmjcnDwpz8SpCD8HzqSDe0eyg34cBinwn9JjmnnRrNAs4HdleRQj7qijp+P/JTxt4vA==", - "dev": true, - "dependencies": { - "eslint-plugin-prettier": "^2.2.0", - "lines-and-columns": "^1.1.6", - "tslib": "^1.7.1" - }, - "engines": { - "node": ">= 4" - }, - "peerDependencies": { - "prettier": "^1.9.0 || ^2.0.0", - "tslint": "^5.0.0 || ^6.0.0" - } - }, - "node_modules/tslint-plugin-prettier/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tslint-react": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tslint-react/-/tslint-react-5.0.0.tgz", - "integrity": "sha512-/IbcSmoBPlFic8kQaRfQ4knTY4mivwo5LVzvozvX6Dyu2ynEnrh1dIcR2ujjyp/IodXqY/H5GbxFxSMo/Kf2Hg==", - "deprecated": "tslint-react is deprecated along with TSLint", - "dev": true, - "dependencies": { - "tsutils": "^3.17.1" - }, - "peerDependencies": { - "tslint": "^6.0.0", - "typescript": ">=3.4.1" - } - }, - "node_modules/tslint-react/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tslint-react/node_modules/tsutils": { + "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", @@ -9764,104 +10718,6 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/tslint/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/tslint/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/tslint/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/tslint/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/tslint/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" - } - }, "node_modules/tsutils/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -9887,12 +10743,12 @@ "dev": true }, "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2" + "prelude-ls": "^1.2.1" }, "engines": { "node": ">= 0.8.0" @@ -9908,12 +10764,12 @@ } }, "node_modules/type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -10305,6 +11161,18 @@ "node": ">= 10.13.0" } }, + "node_modules/webpack-bundle-analyzer/node_modules/acorn": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", + "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.2.tgz", @@ -10447,6 +11315,18 @@ "source-map": "~0.6.1" } }, + "node_modules/webpack/node_modules/acorn": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", + "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/webpack/node_modules/enhanced-resolve": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz", @@ -10498,12 +11378,12 @@ "dev": true }, "node_modules/whatwg-url": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", + "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", "dev": true, "dependencies": { - "lodash.sortby": "^4.7.0", + "lodash": "^4.7.0", "tr46": "^2.0.2", "webidl-conversions": "^6.1.0" }, @@ -10782,12 +11662,12 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.10.4" } }, "@babel/compat-data": { @@ -10820,6 +11700,15 @@ "source-map": "^0.5.0" }, "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -11195,6 +12084,17 @@ "@babel/code-frame": "^7.12.13", "@babel/parser": "^7.12.13", "@babel/types": "^7.12.13" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + } } }, "@babel/traverse": { @@ -11212,6 +12112,23 @@ "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.12.13" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } } }, "@babel/types": { @@ -11247,6 +12164,40 @@ "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==", "dev": true }, + "@eslint/eslintrc": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", + "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -11472,6 +12423,32 @@ "chalk": "^4.0.0" } }, + "@nodelib/fs.scandir": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + } + }, "@polka/url": { "version": "1.0.0-next.11", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz", @@ -11780,6 +12757,89 @@ "@types/node": "*" } }, + "@typescript-eslint/eslint-plugin": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.18.0.tgz", + "integrity": "sha512-Lzkc/2+7EoH7+NjIWLS2lVuKKqbEmJhtXe3rmfA8cyiKnZm3IfLf51irnBcmow8Q/AptVV0XBZmBJKuUJTe6cQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.18.0", + "@typescript-eslint/scope-manager": "4.18.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.15", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.18.0.tgz", + "integrity": "sha512-92h723Kblt9JcT2RRY3QS2xefFKar4ZQFVs3GityOKWQYgtajxt/tuXIzL7sVCUlM1hgreiV5gkGYyBpdOwO6A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.18.0", + "@typescript-eslint/types": "4.18.0", + "@typescript-eslint/typescript-estree": "4.18.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.18.0.tgz", + "integrity": "sha512-W3z5S0ZbecwX3PhJEAnq4mnjK5JJXvXUDBYIYGoweCyWyuvAKfGHvzmpUzgB5L4cRBb+cTu9U/ro66dx7dIimA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.18.0", + "@typescript-eslint/types": "4.18.0", + "@typescript-eslint/typescript-estree": "4.18.0", + "debug": "^4.1.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.18.0.tgz", + "integrity": "sha512-olX4yN6rvHR2eyFOcb6E4vmhDPsfdMyfQ3qR+oQNkAv8emKKlfxTWUXU5Mqxs2Fwe3Pf1BoPvrwZtwngxDzYzQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.18.0", + "@typescript-eslint/visitor-keys": "4.18.0" + } + }, + "@typescript-eslint/types": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.18.0.tgz", + "integrity": "sha512-/BRociARpj5E+9yQ7cwCF/SNOWwXJ3qhjurMuK2hIFUbr9vTuDeu476Zpu+ptxY2kSxUHDGLLKy+qGq2sOg37A==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.18.0.tgz", + "integrity": "sha512-wt4xvF6vvJI7epz+rEqxmoNQ4ZADArGQO9gDU+cM0U5fdVv7N+IAuVoVAoZSOZxzGHBfvE3XQMLdy+scsqFfeg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.18.0", + "@typescript-eslint/visitor-keys": "4.18.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.18.0.tgz", + "integrity": "sha512-Q9t90JCvfYaN0OfFUgaLqByOfz8yPeTAdotn/XYNm5q9eHax90gzdb+RJ6E9T5s97Kv/UHWKERTmqA0jTKAEHw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.18.0", + "eslint-visitor-keys": "^2.0.0" + } + }, "@webassemblyjs/ast": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", @@ -11990,9 +13050,9 @@ "dev": true }, "acorn": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", - "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "acorn-globals": { @@ -12003,16 +13063,15 @@ "requires": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } } }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "requires": {} + }, "acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -12060,12 +13119,20 @@ "dev": true }, "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "type-fest": "^0.11.0" + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } } }, "ansi-regex": { @@ -12148,6 +13215,25 @@ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, + "array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -12175,6 +13261,18 @@ "es-abstract": "^1.18.0-next.1" } }, + "array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + } + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -12196,6 +13294,12 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, "async-foreach": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", @@ -12220,6 +13324,20 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "autoprefixer": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.5.tgz", + "integrity": "sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA==", + "dev": true, + "requires": { + "browserslist": "^4.16.3", + "caniuse-lite": "^1.0.30001196", + "colorette": "^1.2.2", + "fraction.js": "^4.0.13", + "normalize-range": "^0.1.2", + "postcss-value-parser": "^4.1.0" + } + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -12470,12 +13588,6 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -13087,24 +14199,36 @@ "integrity": "sha512-xd4D8kHQtB0KtWW0c9xBZD5LVtm9chkMOfs/3Yn01RhT/sFIsVtzTtypfKoFfWBaL+7xCYLxjOLkhwPXaX/Kcg==", "dev": true }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, "diff-sequences": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "discontinuous-range": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", "dev": true }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dom-serializer": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", @@ -13187,9 +14311,9 @@ } }, "electron-to-chromium": { - "version": "1.3.695", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.695.tgz", - "integrity": "sha512-lz66RliUqLHU1Ojxx1A4QUxKydjiQ79Y4dZyPobs2Dmxj5aVL2TM3KoQ2Gs7HS703Bfny+ukI3KOxwAB0xceHQ==", + "version": "1.3.700", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.700.tgz", + "integrity": "sha512-wQtaxVZzpOeCjW1CGuC5W3bYjE2jglvk076LcTautBOB9UtHztty7wNzjVsndiMcSsdUsdMy5w76w5J1U7OPTQ==", "dev": true }, "emittery": { @@ -13431,26 +14555,153 @@ "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, + "eslint": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.22.0.tgz", + "integrity": "sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.21", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" } }, + "eslint-config-prettier": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz", + "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==", + "dev": true, + "requires": {} + }, "eslint-plugin-prettier": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz", - "integrity": "sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", + "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-react": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz", + "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==", "dev": true, "requires": { - "fast-diff": "^1.1.1", - "jest-docblock": "^21.0.0" + "array-includes": "^3.1.1", + "array.prototype.flatmap": "^1.2.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "object.entries": "^1.1.2", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.18.1", + "string.prototype.matchall": "^4.0.2" }, "dependencies": { - "jest-docblock": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz", - "integrity": "sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==", - "dev": true + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } } } }, + "eslint-plugin-react-hooks": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", + "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", + "dev": true, + "requires": {} + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -13459,12 +14710,46 @@ "requires": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" }, "dependencies": { - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true } } @@ -13475,6 +14760,23 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, "esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -13482,12 +14784,20 @@ "dev": true, "requires": { "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { @@ -13503,9 +14813,9 @@ "dev": true }, "exec-sh": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.5.tgz", - "integrity": "sha512-0hzpaUazv4mEccxdn3TXC+HWNeVXNKMCJRK6E7Xyg+LwGAYI3yFag6jTkd4injV+kChYDQS1ftqDhnDVWNhU8A==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", "dev": true }, "execa": { @@ -13746,6 +15056,20 @@ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, + "fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -13764,6 +15088,15 @@ "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", "dev": true }, + "fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, "fb-watchman": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", @@ -13782,6 +15115,15 @@ "pend": "~1.2.0" } }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "file-loader": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", @@ -13811,6 +15153,22 @@ "path-exists": "^4.0.0" } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -13867,6 +15225,12 @@ "mime-types": "^2.1.12" } }, + "fraction.js": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.13.tgz", + "integrity": "sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA==", + "dev": true + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -13940,6 +15304,12 @@ "functions-have-names": "^1.2.2" } }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "functions-have-names": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", @@ -14077,10 +15447,35 @@ "dev": true }, "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz", + "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + } + } }, "globule": { "version": "1.3.2", @@ -14325,6 +15720,12 @@ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "dev": true }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -14382,6 +15783,17 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, "interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -15200,6 +16612,14 @@ "whatwg-url": "^8.0.0", "ws": "^7.4.4", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", + "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "dev": true + } } }, "jsesc": { @@ -15232,6 +16652,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -15269,6 +16695,16 @@ "verror": "1.10.0" } }, + "jsx-ast-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", + "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", + "dev": true, + "requires": { + "array-includes": "^3.1.2", + "object.assign": "^4.1.2" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -15294,13 +16730,13 @@ "dev": true }, "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, "lines-and-columns": { @@ -15392,12 +16828,6 @@ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -15579,6 +17009,12 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", @@ -15923,6 +17359,12 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, "npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -16157,17 +17599,17 @@ "dev": true }, "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" } }, "p-each-series": { @@ -16407,9 +17849,9 @@ "dev": true }, "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, "prettier": { @@ -16418,6 +17860,15 @@ "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", "dev": true }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -16542,6 +17993,12 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", @@ -16756,6 +18213,22 @@ "safe-regex": "^1.1.0" } }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -16867,6 +18340,12 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -16918,6 +18397,12 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -16943,6 +18428,15 @@ "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", "dev": true }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -17509,6 +19003,17 @@ "dev": true, "optional": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -17538,6 +19043,25 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + } + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -17954,6 +19478,21 @@ } } }, + "string.prototype.matchall": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", + "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + } + }, "string.prototype.trim": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz", @@ -18021,6 +19560,12 @@ "get-stdin": "^4.0.1" } }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -18046,6 +19591,55 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "table": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", + "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", + "dev": true, + "requires": { + "ajv": "^7.0.2", + "lodash": "^4.17.20", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "ajv": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.3.tgz", + "integrity": "sha512-idv5WZvKVXDqKralOImQgPM9v6WOdLNa0IY3B3doOjw/YxRGT8I+allIJ6kd7Uaj+SF1xZUSU+nPM5aDNBVtnw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + } + } + }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -18185,6 +19779,12 @@ "minimatch": "^3.0.4" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", @@ -18348,152 +19948,10 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" }, - "tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "tslint-config-prettier": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", - "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", - "dev": true - }, - "tslint-plugin-prettier": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslint-plugin-prettier/-/tslint-plugin-prettier-2.3.0.tgz", - "integrity": "sha512-F9e4K03yc9xuvv+A0v1EmjcnDwpz8SpCD8HzqSDe0eyg34cBinwn9JjmnnRrNAs4HdleRQj7qijp+P/JTxt4vA==", - "dev": true, - "requires": { - "eslint-plugin-prettier": "^2.2.0", - "lines-and-columns": "^1.1.6", - "tslib": "^1.7.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "tslint-react": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tslint-react/-/tslint-react-5.0.0.tgz", - "integrity": "sha512-/IbcSmoBPlFic8kQaRfQ4knTY4mivwo5LVzvozvX6Dyu2ynEnrh1dIcR2ujjyp/IodXqY/H5GbxFxSMo/Kf2Hg==", - "dev": true, - "requires": { - "tsutils": "^3.17.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - } - } - }, "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "requires": { "tslib": "^1.8.1" @@ -18523,12 +19981,12 @@ "dev": true }, "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "^1.2.1" } }, "type-detect": { @@ -18538,9 +19996,9 @@ "dev": true }, "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, "typedarray-to-buffer": { @@ -18828,6 +20286,12 @@ "webpack-sources": "^2.1.1" }, "dependencies": { + "acorn": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", + "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "dev": true + }, "enhanced-resolve": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz", @@ -18873,6 +20337,12 @@ "ws": "^7.3.1" }, "dependencies": { + "acorn": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", + "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "dev": true + }, "acorn-walk": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.2.tgz", @@ -18982,12 +20452,12 @@ "dev": true }, "whatwg-url": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", + "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", + "lodash": "^4.7.0", "tr46": "^2.0.2", "webidl-conversions": "^6.1.0" } diff --git a/package.json b/package.json index 7743c9bde..0704ec789 100644 --- a/package.json +++ b/package.json @@ -24,11 +24,19 @@ "@types/react": "17.0.3", "@types/react-dom": "17.0.3", "@types/react-textarea-autosize": "4.3.5", + "@typescript-eslint/eslint-plugin": "4.18.0", + "@typescript-eslint/parser": "4.18.0", "@wojtekmaj/enzyme-adapter-react-17": "0.5.0", + "autoprefixer": "10.2.5", "css-loader": "5.1.1", "dotenv": "8.2.0", "enzyme": "3.11.0", "esbuild": "0.9.5", + "eslint": "7.22.0", + "eslint-config-prettier": "8.1.0", + "eslint-plugin-prettier": "3.3.1", + "eslint-plugin-react": "7.22.0", + "eslint-plugin-react-hooks": "4.2.0", "file-loader": "6.2.0", "fork-ts-checker-webpack-plugin": "6.1.1", "jest": "26.6.3", @@ -40,10 +48,6 @@ "sass-loader": "11.0.1", "ts-jest": "26.5.3", "ts-loader": "8.0.17", - "tslint": "6.1.3", - "tslint-config-prettier": "1.18.0", - "tslint-plugin-prettier": "2.3.0", - "tslint-react": "5.0.0", "typescript": "4.2.3", "webpack": "5.24.3", "webpack-bundle-analyzer": "4.4.0", diff --git a/public/AsyncPages.tsx b/public/AsyncPages.tsx index a235d9515..4811dca5a 100644 --- a/public/AsyncPages.tsx +++ b/public/AsyncPages.tsx @@ -1,9 +1,9 @@ -import { lazy, ComponentType } from "react"; +import { lazy, ComponentType } from "react" -type LazyImport = () => Promise<{ default: ComponentType }>; +type LazyImport = () => Promise<{ default: ComponentType }> -const MAX_RETRIES = 10; -const INTERVAL = 500; +const MAX_RETRIES = 10 +const INTERVAL = 500 const retry = (fn: LazyImport, retriesLeft = MAX_RETRIES): Promise<{ default: ComponentType }> => { return new Promise((resolve, reject) => { @@ -12,16 +12,16 @@ const retry = (fn: LazyImport, retriesLeft = MAX_RETRIES): Promise<{ default: Co .catch((err) => { setTimeout(() => { if (retriesLeft === 1) { - reject(new Error(`${err} after ${MAX_RETRIES} retries`)); - return; + reject(new Error(`${err} after ${MAX_RETRIES} retries`)) + return } - retry(fn, retriesLeft - 1).then(resolve, reject); - }, INTERVAL); - }); - }); -}; + retry(fn, retriesLeft - 1).then(resolve, reject) + }, INTERVAL) + }) + }) +} -const load = (fn: LazyImport) => lazy(() => retry(() => fn())); +const load = (fn: LazyImport) => lazy(() => retry(() => fn())) export const AsyncHomePage = load( () => @@ -29,7 +29,7 @@ export const AsyncHomePage = load( /* webpackChunkName: "Home.page" */ "@fider/pages/Home/Home.page" ) -); +) export const AsyncShowPostPage = load( () => @@ -37,7 +37,7 @@ export const AsyncShowPostPage = load( /* webpackChunkName: "ShowPost.page" */ "@fider/pages/ShowPost/ShowPost.page" ) -); +) export const AsyncManageMembersPage = load( () => @@ -45,7 +45,7 @@ export const AsyncManageMembersPage = load( /* webpackChunkName: "ManageMembers.page" */ "@fider/pages/Administration/pages/ManageMembers.page" ) -); +) export const AsyncManageTagsPage = load( () => @@ -53,7 +53,7 @@ export const AsyncManageTagsPage = load( /* webpackChunkName: "ManageTags.page" */ "@fider/pages/Administration/pages/ManageTags.page" ) -); +) export const AsyncPrivacySettingsPage = load( () => @@ -61,7 +61,7 @@ export const AsyncPrivacySettingsPage = load( /* webpackChunkName: "PrivacySettings.page" */ "@fider/pages/Administration/pages/PrivacySettings.page" ) -); +) export const AsyncExportPage = load( () => @@ -69,7 +69,7 @@ export const AsyncExportPage = load( /* webpackChunkName: "Export.page" */ "@fider/pages/Administration/pages/Export.page" ) -); +) export const AsyncInvitationsPage = load( () => @@ -77,7 +77,7 @@ export const AsyncInvitationsPage = load( /* webpackChunkName: "Invitations.page" */ "@fider/pages/Administration/pages/Invitations.page" ) -); +) export const AsyncManageAuthenticationPage = load( () => @@ -85,7 +85,7 @@ export const AsyncManageAuthenticationPage = load( /* webpackChunkName: "ManageAuthentication.page" */ "@fider/pages/Administration/pages/ManageAuthentication.page" ) -); +) export const AsyncAdvancedSettingsPage = load( () => @@ -93,7 +93,7 @@ export const AsyncAdvancedSettingsPage = load( /* webpackChunkName: "AdvancedSettings.page" */ "@fider/pages/Administration/pages/AdvancedSettings.page" ) -); +) export const AsyncGeneralSettingsPage = load( () => @@ -101,7 +101,7 @@ export const AsyncGeneralSettingsPage = load( /* webpackChunkName: "GeneralSettings.page" */ "@fider/pages/Administration/pages/GeneralSettings.page" ) -); +) export const AsyncSignInPage = load( () => @@ -109,7 +109,7 @@ export const AsyncSignInPage = load( /* webpackChunkName: "SignIn.page" */ "@fider/pages/SignIn/SignIn.page" ) -); +) export const AsyncSignUpPage = load( () => @@ -117,7 +117,7 @@ export const AsyncSignUpPage = load( /* webpackChunkName: "SignUp.page" */ "@fider/pages/SignUp/SignUp.page" ) -); +) export const AsyncCompleteSignInProfilePage = load( () => @@ -125,7 +125,7 @@ export const AsyncCompleteSignInProfilePage = load( /* webpackChunkName: "CompleteSignInProfile.page" */ "@fider/pages/CompleteSignInProfile/CompleteSignInProfile.page" ) -); +) export const AsyncMyNotificationsPage = load( () => @@ -133,7 +133,7 @@ export const AsyncMyNotificationsPage = load( /* webpackChunkName: "MyNotifications.page" */ "@fider/pages/MyNotifications/MyNotifications.page" ) -); +) export const AsyncMySettingsPage = load( () => @@ -141,7 +141,7 @@ export const AsyncMySettingsPage = load( /* webpackChunkName: "MySettings.page" */ "@fider/pages/MySettings/MySettings.page" ) -); +) export const AsyncOAuthEchoPage = load( () => @@ -149,7 +149,7 @@ export const AsyncOAuthEchoPage = load( /* webpackChunkName: "OAuthEcho.page" */ "@fider/pages/OAuthEcho/OAuthEcho.page" ) -); +) export const AsyncUIToolkitPage = load( () => @@ -157,4 +157,4 @@ export const AsyncUIToolkitPage = load( /* webpackChunkName: "UIToolkit.page" */ "@fider/pages/UI/UIToolkit.page" ) -); +) diff --git a/public/components/ErrorBoundary.spec.tsx b/public/components/ErrorBoundary.spec.tsx index 57f4df247..c4c3f7a5c 100644 --- a/public/components/ErrorBoundary.spec.tsx +++ b/public/components/ErrorBoundary.spec.tsx @@ -1,43 +1,43 @@ -import React from "react"; -import { shallow } from "enzyme"; -import { ErrorBoundary } from "@fider/components"; +import React from "react" +import { shallow } from "enzyme" +import { ErrorBoundary } from "@fider/components" describe("", () => { - let errorMethod: () => void; + let errorMethod: () => void // Stub out console.error to hide noisy Virtual DOM exceptions. beforeAll(() => { - errorMethod = console.error; // tslint:disable-line - console.error = () => null; // tslint:disable-line - }); + errorMethod = console.error + console.error = () => null + }) afterAll(() => { - console.error = errorMethod; // tslint:disable-line - }); + console.error = errorMethod + }) test("when no error caught", () => { - const errorSpy = jest.fn(); + const errorSpy = jest.fn() shallow(
No Error!
- ); + ) - expect(errorSpy).not.toHaveBeenCalled(); - }); + expect(errorSpy).not.toHaveBeenCalled() + }) describe("when error caught", () => { test("error should be passed to onError", () => { - const error = new Error("Whoops!"); - const errorSpy = jest.fn(); - const wrapper = shallow(); + const error = new Error("Whoops!") + const errorSpy = jest.fn() + const wrapper = shallow() - const componentDidCatch = wrapper.instance().componentDidCatch; + const componentDidCatch = wrapper.instance().componentDidCatch if (componentDidCatch) { - componentDidCatch.bind(wrapper.instance())(error, {} as React.ErrorInfo); + componentDidCatch.bind(wrapper.instance())(error, {} as React.ErrorInfo) } - expect(errorSpy).toHaveBeenCalledWith(error); - }); - }); -}); + expect(errorSpy).toHaveBeenCalledWith(error) + }) + }) +}) diff --git a/public/components/ErrorBoundary.tsx b/public/components/ErrorBoundary.tsx index 31330f5c0..7418da426 100644 --- a/public/components/ErrorBoundary.tsx +++ b/public/components/ErrorBoundary.tsx @@ -1,45 +1,45 @@ -import React from "react"; -import { ErrorPage } from "@fider/pages/Error/Error.page"; -import { FiderContext } from "@fider/services"; +import React from "react" +import { ErrorPage } from "@fider/pages/Error/Error.page" +import { FiderContext } from "@fider/services" interface ErrorBoundaryProps { - onError?: (err: Error) => void; + onError?: (err: Error) => void } interface ErrorBoundaryState { - error?: Error; - errorInfo?: React.ErrorInfo; + error?: Error + errorInfo?: React.ErrorInfo } export class ErrorBoundary extends React.Component { constructor(props: any) { - super(props); + super(props) this.state = { error: undefined, errorInfo: undefined, - }; + } } public componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { - const onError = this.props.onError; + const onError = this.props.onError if (onError) { - onError(error); + onError(error) } this.setState({ error, errorInfo, - }); + }) } public render() { - const { error, errorInfo } = this.state; + const { error, errorInfo } = this.state if (error && errorInfo) { - return {(fider) => }; + return {(fider) => } } else { - return this.props.children; + return this.props.children } } } diff --git a/public/components/ShowPostResponse.tsx b/public/components/ShowPostResponse.tsx index 9c5985923..e90674c51 100644 --- a/public/components/ShowPostResponse.tsx +++ b/public/components/ShowPostResponse.tsx @@ -1,54 +1,54 @@ -import "./ShowPostResponse.scss"; +import "./ShowPostResponse.scss" -import React from "react"; -import { PostResponse, PostStatus } from "@fider/models"; -import { Avatar, MultiLineText, UserName, Segment } from "@fider/components/common"; +import React from "react" +import { PostResponse, PostStatus } from "@fider/models" +import { Avatar, MultiLineText, UserName, Segment } from "@fider/components/common" interface ShowPostStatusProps { - status: PostStatus; + status: PostStatus } export const ShowPostStatus = (props: ShowPostStatusProps) => { - return {props.status.title}; -}; + return {props.status.title} +} const DuplicateDetails = (props: PostResponseProps): JSX.Element | null => { if (!props.response) { - return null; + return null } - const original = props.response.original; + const original = props.response.original if (!original) { - return null; + return null } return ( - ); -}; + ) +} interface PostResponseProps { - status: string; - response: PostResponse | null; - showUser: boolean; + status: string + response: PostResponse | null + showUser: boolean } const StatusDetails = (props: PostResponseProps): JSX.Element | null => { if (!props.response || !props.response.text) { - return null; + return null } return (
- ); -}; + ) +} export const ShowPostResponse = (props: PostResponseProps): JSX.Element => { - const status = PostStatus.Get(props.status); + const status = PostStatus.Get(props.status) if (props.response && (status.show || props.response.text)) { return ( @@ -61,8 +61,8 @@ export const ShowPostResponse = (props: PostResponseProps): JSX.Element => { )} {status === PostStatus.Duplicate ? DuplicateDetails(props) : StatusDetails(props)} - ); + ) } - return
; -}; + return
+} diff --git a/public/components/ShowTag.tsx b/public/components/ShowTag.tsx index 2328af6ea..e909042a8 100644 --- a/public/components/ShowTag.tsx +++ b/public/components/ShowTag.tsx @@ -1,40 +1,40 @@ -import "./ShowTag.scss"; +import "./ShowTag.scss" -import React from "react"; -import { Tag } from "@fider/models"; -import { classSet } from "@fider/services"; -import { FaLock } from "react-icons/fa"; +import React from "react" +import { Tag } from "@fider/models" +import { classSet } from "@fider/services" +import { FaLock } from "react-icons/fa" interface TagProps { - tag: Tag; - size?: "mini" | "tiny" | "small" | "normal"; - circular?: boolean; + tag: Tag + size?: "mini" | "tiny" | "small" | "normal" + circular?: boolean } const getRGB = (color: string) => { - const r = color.substring(0, 2); - const g = color.substring(2, 4); - const b = color.substring(4, 6); + const r = color.substring(0, 2) + const g = color.substring(2, 4) + const b = color.substring(4, 6) return { R: parseInt(r, 16), G: parseInt(g, 16), B: parseInt(b, 16), - }; -}; + } +} const textColor = (color: string) => { - const components = getRGB(color); - const bgDelta = components.R * 0.299 + components.G * 0.587 + components.B * 0.114; - return bgDelta > 140 ? "#333" : "#fff"; -}; + const components = getRGB(color) + const bgDelta = components.R * 0.299 + components.G * 0.587 + components.B * 0.114 + return bgDelta > 140 ? "#333" : "#fff" +} export const ShowTag = (props: TagProps) => { const className = classSet({ "c-tag": true, [`m-${props.size || "normal"}`]: true, "m-circular": props.circular === true, - }); + }) return (
{ {!props.tag.isPublic && !props.circular && } {props.circular ? "" : props.tag.name || "Tag"}
- ); -}; + ) +} diff --git a/public/components/SignInModal.tsx b/public/components/SignInModal.tsx index 195d5da55..f91fbb2ed 100644 --- a/public/components/SignInModal.tsx +++ b/public/components/SignInModal.tsx @@ -1,28 +1,28 @@ -import React, { useState, useEffect } from "react"; -import { Modal, SignInControl, LegalFooter } from "@fider/components/common"; +import React, { useState, useEffect } from "react" +import { Modal, SignInControl, LegalFooter } from "@fider/components/common" interface SignInModalProps { - isOpen: boolean; - onClose: () => void; + isOpen: boolean + onClose: () => void } export const SignInModal: React.StatelessComponent = (props) => { - const [confirmationAddress, setConfirmationAddress] = useState(""); + const [confirmationAddress, setConfirmationAddress] = useState("") useEffect(() => { if (confirmationAddress) { - setTimeout(() => setConfirmationAddress(""), 5000); + setTimeout(() => setConfirmationAddress(""), 5000) } - }, [confirmationAddress]); + }, [confirmationAddress]) const onEmailSent = (email: string): void => { - setConfirmationAddress(email); - }; + setConfirmationAddress(email) + } const closeModal = () => { - setConfirmationAddress(""); - props.onClose(); - }; + setConfirmationAddress("") + props.onClose() + } const content = confirmationAddress ? ( <> @@ -37,7 +37,7 @@ export const SignInModal: React.StatelessComponent = (props) = ) : ( - ); + ) return ( @@ -45,5 +45,5 @@ export const SignInModal: React.StatelessComponent = (props) = {content} - ); -}; + ) +} diff --git a/public/components/VoteCounter.spec.tsx b/public/components/VoteCounter.spec.tsx index 90ba5ef5e..88b888a69 100644 --- a/public/components/VoteCounter.spec.tsx +++ b/public/components/VoteCounter.spec.tsx @@ -1,10 +1,10 @@ -import React from "react"; -import { shallow } from "enzyme"; -import { Post, UserRole, PostStatus, UserStatus } from "@fider/models"; -import { VoteCounter, SignInModal } from "@fider/components"; -import { httpMock, fiderMock, rerender } from "@fider/services/testing"; +import React from "react" +import { shallow } from "enzyme" +import { Post, UserRole, PostStatus, UserStatus } from "@fider/models" +import { VoteCounter, SignInModal } from "@fider/components" +import { httpMock, fiderMock, rerender } from "@fider/services/testing" -let post: Post; +let post: Post beforeEach(() => { post = { @@ -27,78 +27,78 @@ beforeEach(() => { votesCount: 5, commentsCount: 2, tags: [], - }; -}); + } +}) describe("", () => { test("when hasVoted === true", () => { - post.hasVoted = true; - post.votesCount = 9; - const wrapper = shallow(); - const button = wrapper.find("button"); - expect(button.text()).toBe("9"); - expect(button.hasClass("m-voted")).toBe(true); - expect(button.hasClass("m-disabled")).toBe(false); - }); + post.hasVoted = true + post.votesCount = 9 + const wrapper = shallow() + const button = wrapper.find("button") + expect(button.text()).toBe("9") + expect(button.hasClass("m-voted")).toBe(true) + expect(button.hasClass("m-disabled")).toBe(false) + }) test("when hasVoted === false", () => { - post.hasVoted = false; - post.votesCount = 2; - const wrapper = shallow(); - const button = wrapper.find("button"); - expect(button.text()).toBe("2"); - expect(button.hasClass("m-voted")).toBe(false); - expect(button.hasClass("m-disabled")).toBe(false); - }); + post.hasVoted = false + post.votesCount = 2 + const wrapper = shallow() + const button = wrapper.find("button") + expect(button.text()).toBe("2") + expect(button.hasClass("m-voted")).toBe(false) + expect(button.hasClass("m-disabled")).toBe(false) + }) test("when post is closed", () => { - post.status = PostStatus.Completed.value; - const wrapper = shallow(); - const button = wrapper.find("button"); - expect(button.text()).toBe("5"); - expect(button.hasClass("m-voted")).toBe(false); - expect(button.hasClass("m-disabled")).toBe(true); - }); + post.status = PostStatus.Completed.value + const wrapper = shallow() + const button = wrapper.find("button") + expect(button.text()).toBe("5") + expect(button.hasClass("m-voted")).toBe(false) + expect(button.hasClass("m-disabled")).toBe(true) + }) test("click when unauthenticated", async () => { - fiderMock.notAuthenticated(); + fiderMock.notAuthenticated() - const mock = httpMock.alwaysOk(); + const mock = httpMock.alwaysOk() - const wrapper = shallow(); - wrapper.find("button").simulate("click"); - await rerender(wrapper); - expect(wrapper.find(SignInModal).length).toBe(1); - expect(mock.post).toHaveBeenCalledTimes(0); - expect(mock.delete).toHaveBeenCalledTimes(0); - }); + const wrapper = shallow() + wrapper.find("button").simulate("click") + await rerender(wrapper) + expect(wrapper.find(SignInModal).length).toBe(1) + expect(mock.post).toHaveBeenCalledTimes(0) + expect(mock.delete).toHaveBeenCalledTimes(0) + }) test("click when authenticated and hasVoted === false", async () => { - fiderMock.authenticated(); + fiderMock.authenticated() - const mock = httpMock.alwaysOk(); + const mock = httpMock.alwaysOk() - const wrapper = shallow(); - wrapper.find("button").simulate("click"); - expect(mock.post).toHaveBeenCalledWith("/api/v1/posts/10/votes"); - expect(mock.post).toHaveBeenCalledTimes(1); + const wrapper = shallow() + wrapper.find("button").simulate("click") + expect(mock.post).toHaveBeenCalledWith("/api/v1/posts/10/votes") + expect(mock.post).toHaveBeenCalledTimes(1) - await rerender(wrapper); - expect(wrapper.find("button").text()).toBe("6"); - }); + await rerender(wrapper) + expect(wrapper.find("button").text()).toBe("6") + }) test("click when authenticated and hasVoted === true", async () => { - post.hasVoted = true; - fiderMock.authenticated(); + post.hasVoted = true + fiderMock.authenticated() - const mock = httpMock.alwaysOk(); + const mock = httpMock.alwaysOk() - const wrapper = shallow(); - wrapper.find("button").simulate("click"); - expect(mock.delete).toHaveBeenCalledWith("/api/v1/posts/10/votes"); - expect(mock.delete).toHaveBeenCalledTimes(1); + const wrapper = shallow() + wrapper.find("button").simulate("click") + expect(mock.delete).toHaveBeenCalledWith("/api/v1/posts/10/votes") + expect(mock.delete).toHaveBeenCalledTimes(1) - await rerender(wrapper); - expect(wrapper.find("button").text()).toBe("4"); - }); -}); + await rerender(wrapper) + expect(wrapper.find("button").text()).toBe("4") + }) +}) diff --git a/public/components/VoteCounter.tsx b/public/components/VoteCounter.tsx index e432364da..5b702b993 100644 --- a/public/components/VoteCounter.tsx +++ b/public/components/VoteCounter.tsx @@ -1,65 +1,65 @@ -import "./VoteCounter.scss"; +import "./VoteCounter.scss" -import React, { useState } from "react"; -import { Post, PostStatus } from "@fider/models"; -import { actions, device, classSet } from "@fider/services"; -import { SignInModal } from "@fider/components"; -import { FaCaretUp } from "react-icons/fa"; -import { useFider } from "@fider/hooks"; +import React, { useState } from "react" +import { Post, PostStatus } from "@fider/models" +import { actions, device, classSet } from "@fider/services" +import { SignInModal } from "@fider/components" +import { FaCaretUp } from "react-icons/fa" +import { useFider } from "@fider/hooks" interface VoteCounterProps { - post: Post; + post: Post } export const VoteCounter = (props: VoteCounterProps) => { - const fider = useFider(); - const [hasVoted, setHasVoted] = useState(props.post.hasVoted); - const [votesCount, setVotesCount] = useState(props.post.votesCount); - const [isSignInModalOpen, setIsSignInModalOpen] = useState(false); + const fider = useFider() + const [hasVoted, setHasVoted] = useState(props.post.hasVoted) + const [votesCount, setVotesCount] = useState(props.post.votesCount) + const [isSignInModalOpen, setIsSignInModalOpen] = useState(false) const voteOrUndo = async () => { if (!fider.session.isAuthenticated) { - setIsSignInModalOpen(true); - return; + setIsSignInModalOpen(true) + return } - const action = hasVoted ? actions.removeVote : actions.addVote; + const action = hasVoted ? actions.removeVote : actions.addVote - const response = await action(props.post.number); + const response = await action(props.post.number) if (response.ok) { - setVotesCount(votesCount + (hasVoted ? -1 : 1)); - setHasVoted(!hasVoted); + setVotesCount(votesCount + (hasVoted ? -1 : 1)) + setHasVoted(!hasVoted) } - }; + } - const hideModal = () => setIsSignInModalOpen(false); + const hideModal = () => setIsSignInModalOpen(false) - const status = PostStatus.Get(props.post.status); + const status = PostStatus.Get(props.post.status) const className = classSet({ "m-voted": !status.closed && hasVoted, "m-disabled": status.closed, "no-touch": !device.isTouch(), - }); + }) const vote = ( - ); + ) const disabled = ( - ); + ) return ( <>
{status.closed ? disabled : vote}
- ); -}; + ) +} diff --git a/public/components/common/Avatar.tsx b/public/components/common/Avatar.tsx index d226bee72..8f832578d 100644 --- a/public/components/common/Avatar.tsx +++ b/public/components/common/Avatar.tsx @@ -1,26 +1,26 @@ -import "./Avatar.scss"; +import "./Avatar.scss" -import React from "react"; -import { classSet } from "@fider/services"; -import { isCollaborator, UserRole } from "@fider/models"; +import React from "react" +import { classSet } from "@fider/services" +import { isCollaborator, UserRole } from "@fider/models" interface AvatarProps { user: { - role?: UserRole; - avatarURL: string; - name: string; - }; - size?: "small" | "normal" | "large"; + role?: UserRole + avatarURL: string + name: string + } + size?: "small" | "normal" | "large" } export const Avatar = (props: AvatarProps) => { - const size = props.size || "normal"; + const size = props.size || "normal" const className = classSet({ "c-avatar": true, [`m-${size}`]: true, "m-staff": props.user.role && isCollaborator(props.user.role), - }); + }) - return ; -}; + return {props.user.name} +} diff --git a/public/components/common/Button.tsx b/public/components/common/Button.tsx index d329be0c0..66da5964d 100644 --- a/public/components/common/Button.tsx +++ b/public/components/common/Button.tsx @@ -1,74 +1,74 @@ -import React from "react"; -import { classSet } from "@fider/services"; +import React from "react" +import { classSet } from "@fider/services" interface ButtonProps { - className?: string; - disabled?: boolean; - href?: string; - rel?: "nofollow"; - type?: "button" | "submit"; - color?: "positive" | "danger" | "default" | "cancel"; - fluid?: boolean; - size?: "mini" | "tiny" | "small" | "normal" | "large"; - onClick?: (event: ButtonClickEvent) => Promise; + className?: string + disabled?: boolean + href?: string + rel?: "nofollow" + type?: "button" | "submit" + color?: "positive" | "danger" | "default" | "cancel" + fluid?: boolean + size?: "mini" | "tiny" | "small" | "normal" | "large" + onClick?: (event: ButtonClickEvent) => Promise } interface ButtonState { - clicked: boolean; + clicked: boolean } -import "./Button.scss"; +import "./Button.scss" export class ButtonClickEvent { - private shouldEnable = true; + private shouldEnable = true public preventEnable(): void { - this.shouldEnable = false; + this.shouldEnable = false } public canEnable(): boolean { - return this.shouldEnable; + return this.shouldEnable } } export class Button extends React.Component { - private unmounted: boolean = false; + private unmounted = false public static defaultProps: Partial = { size: "small", fluid: false, color: "default", type: "button", - }; + } public constructor(props: ButtonProps) { - super(props); + super(props) this.state = { clicked: false, - }; + } } public componentWillUnmount() { - this.unmounted = true; + this.unmounted = true } public click = async (e?: React.SyntheticEvent) => { if (e) { - e.preventDefault(); - e.stopPropagation(); + e.preventDefault() + e.stopPropagation() } if (this.state.clicked) { - return; + return } - const event = new ButtonClickEvent(); - this.setState({ clicked: true }); + const event = new ButtonClickEvent() + this.setState({ clicked: true }) if (this.props.onClick) { - await this.props.onClick(event); + await this.props.onClick(event) if (!this.unmounted && event.canEnable()) { - this.setState({ clicked: false }); + this.setState({ clicked: false }) } } - }; + } public render() { const className = classSet({ @@ -78,27 +78,27 @@ export class Button extends React.Component { [`m-${this.props.color}`]: this.props.color, "m-loading": this.state.clicked, "m-disabled": this.state.clicked || this.props.disabled, - [this.props.className!]: this.props.className, - }); + [this.props.className || ""]: this.props.className, + }) if (this.props.href) { return ( {this.props.children} - ); + ) } else if (this.props.onClick) { return ( - ); + ) } else { return ( - ); + ) } } } diff --git a/public/components/common/DropDown.tsx b/public/components/common/DropDown.tsx index f5f2e14e6..707ba9c8f 100644 --- a/public/components/common/DropDown.tsx +++ b/public/components/common/DropDown.tsx @@ -1,147 +1,147 @@ -import React from "react"; -import { classSet } from "@fider/services"; +import React from "react" +import { classSet } from "@fider/services" -import "./DropDown.scss"; +import "./DropDown.scss" export interface DropDownItem { - value: any; - label: string; - render?: JSX.Element; + value: any + label: string + render?: JSX.Element } export interface DropDownProps { - className?: string; - defaultValue?: any; - items: (DropDownItem | undefined | false)[]; - placeholder?: string; - searchable?: boolean; - inline?: boolean; - style: "normal" | "simple"; - highlightSelected?: boolean; - header?: string; - direction?: "left" | "right"; - onChange?: (item: DropDownItem) => void; - onSearchChange?: (e: React.FormEvent) => void; - renderText?: (item?: DropDownItem) => JSX.Element | string | undefined; - renderControl?: (item?: DropDownItem) => JSX.Element | string | undefined; + className?: string + defaultValue?: any + items: (DropDownItem | undefined | false)[] + placeholder?: string + searchable?: boolean + inline?: boolean + style: "normal" | "simple" + highlightSelected?: boolean + header?: string + direction?: "left" | "right" + onChange?: (item: DropDownItem) => void + onSearchChange?: (e: React.FormEvent) => void + renderText?: (item?: DropDownItem) => JSX.Element | string | undefined + renderControl?: (item?: DropDownItem) => JSX.Element | string | undefined } export interface DropDownState { - isOpen: boolean; - selected?: DropDownItem; + isOpen: boolean + selected?: DropDownItem } export class DropDown extends React.Component { - private rootElementRef: React.RefObject; - private mounted = false; + private rootElementRef: React.RefObject + private mounted = false public static defaultProps: Partial = { direction: "right", style: "normal", highlightSelected: true, - }; + } constructor(props: DropDownProps) { - super(props); - this.rootElementRef = React.createRef(); + super(props) + this.rootElementRef = React.createRef() this.state = { selected: this.findItem(props.defaultValue, props.items), isOpen: false, - }; + } } public componentDidMount() { - this.mounted = true; + this.mounted = true } public componentWillUnmount() { - this.mounted = false; - this.removeListeners(); + this.mounted = false + this.removeListeners() } private addListeners() { - document.addEventListener("click", this.handleDocumentClick, false); - document.addEventListener("touchend", this.handleDocumentClick, false); + document.addEventListener("click", this.handleDocumentClick, false) + document.addEventListener("touchend", this.handleDocumentClick, false) } private removeListeners() { - document.removeEventListener("click", this.handleDocumentClick, false); - document.removeEventListener("touchend", this.handleDocumentClick, false); + document.removeEventListener("click", this.handleDocumentClick, false) + document.removeEventListener("touchend", this.handleDocumentClick, false) } public handleMouseDown = (event: any) => { if (event.type === "mousedown" && event.button !== 0) { - return; + return } - event.stopPropagation(); - event.preventDefault(); + event.stopPropagation() + event.preventDefault() this.setState( { isOpen: true, }, this.addListeners - ); - }; + ) + } public findItem(value: any, items: (DropDownItem | undefined | false)[]): DropDownItem | undefined { for (const item of items) { if (item && item.value === value) { - return item; + return item } } - return undefined; + return undefined } public setSelected(selected: DropDownItem) { const newState = { selected, isOpen: false, - }; - this.fireChangeEvent(newState); - this.setState(newState, this.removeListeners); + } + this.fireChangeEvent(newState) + this.setState(newState, this.removeListeners) } public fireChangeEvent(newState: DropDownState) { if (newState.selected && newState.selected !== this.state.selected && this.props.onChange) { - this.props.onChange(newState.selected); + this.props.onChange(newState.selected) } } public renderItem = (item: DropDownItem | undefined | false) => { if (!item) { - return; + return } - const { label, value } = item; - const isSelected = this.props.highlightSelected && this.state.selected && value === this.state.selected.value; + const { label, value } = item + const isSelected = this.props.highlightSelected && this.state.selected && value === this.state.selected.value const className = classSet({ "c-dropdown-item": true, "is-selected": isSelected, - }); + }) return (
{item.render ? item.render : label}
- ); - }; + ) + } public buildItemList() { - const items = this.props.items.map(this.renderItem); + const items = this.props.items.map(this.renderItem) return (
{this.props.header &&
{this.props.header}
}
{items.length ? items :
No results found
}
- ); + ) } public handleDocumentClick = (event: any) => { if (this.mounted) { - const node = this.rootElementRef.current; + const node = this.rootElementRef.current if (node && !node.contains(event.target)) { if (this.state.isOpen) { this.setState( @@ -149,16 +149,16 @@ export class DropDown extends React.Component { isOpen: false, }, this.removeListeners - ); + ) } } } - }; + } public render() { - const text = this.state.selected ? this.state.selected.label : {this.props.placeholder}; + const text = this.state.selected ? this.state.selected.label : {this.props.placeholder} - const search = ; + const search = const dropdownClass = classSet({ "c-dropdown": true, @@ -168,7 +168,7 @@ export class DropDown extends React.Component { "is-inline": this.props.inline, "m-right": this.props.direction === "right", "m-left": this.props.direction === "left", - }); + }) return (
@@ -184,6 +184,6 @@ export class DropDown extends React.Component {
{this.state.isOpen && this.buildItemList()}
- ); + ) } } diff --git a/public/components/common/EnvironmentInfo.tsx b/public/components/common/EnvironmentInfo.tsx index 3945d0ce0..e33661f76 100644 --- a/public/components/common/EnvironmentInfo.tsx +++ b/public/components/common/EnvironmentInfo.tsx @@ -1,17 +1,18 @@ -import React from "react"; -import { useFider } from "@fider/hooks"; +import React from "react" +import { useFider } from "@fider/hooks" export const EnvironmentInfo = () => { - const fider = useFider(); + const fider = useFider() if (fider.isProduction()) { - return null; + return null } return (
- Env: {fider.settings.environment} | Compiler: {fider.settings.compiler} | Version: {fider.settings.version} | BuildTime: {fider.settings.buildTime || "N/A"} | - {!fider.isSingleHostMode() && `TenantID: ${fider.session.tenant.id}`} | {fider.session.isAuthenticated && `UserID: ${fider.session.user.id}`} + Env: {fider.settings.environment} | Compiler: {fider.settings.compiler} | Version: {fider.settings.version} | BuildTime:{" "} + {fider.settings.buildTime || "N/A"} |{!fider.isSingleHostMode() && `TenantID: ${fider.session.tenant.id}`} |{" "} + {fider.session.isAuthenticated && `UserID: ${fider.session.user.id}`}
- ); -}; + ) +} diff --git a/public/components/common/FiderVersion.tsx b/public/components/common/FiderVersion.tsx index 6aa3c2d96..b8c5d00e7 100644 --- a/public/components/common/FiderVersion.tsx +++ b/public/components/common/FiderVersion.tsx @@ -1,17 +1,17 @@ -import React from "react"; -import { useFider } from "@fider/hooks"; +import React from "react" +import { useFider } from "@fider/hooks" export const FiderVersion = () => { - const fider = useFider(); + const fider = useFider() return (

Support our{" "} - + OpenCollective
Fider v{fider.settings.version}

- ); -}; + ) +} diff --git a/public/components/common/Footer.tsx b/public/components/common/Footer.tsx index 513b0dc0a..a9ef06c0f 100644 --- a/public/components/common/Footer.tsx +++ b/public/components/common/Footer.tsx @@ -1,27 +1,16 @@ -import "./Footer.scss"; +import "./Footer.scss" -import React from "react"; -import { PrivacyPolicy, TermsOfService } from "@fider/components"; -import { useFider } from "@fider/hooks"; +import React from "react" export const Footer = () => { - const fider = useFider(); - return ( - ); -}; + ) +} diff --git a/public/components/common/Header.tsx b/public/components/common/Header.tsx index ed73ed6bf..1d5b9e780 100644 --- a/public/components/common/Header.tsx +++ b/public/components/common/Header.tsx @@ -1,33 +1,33 @@ -import "./Header.scss"; +import "./Header.scss" -import React, { useState, useEffect } from "react"; -import { SignInModal, EnvironmentInfo, Avatar, TenantLogo } from "@fider/components"; -import { actions } from "@fider/services"; -import { FaUser, FaCog, FaCaretDown } from "react-icons/fa"; -import { useFider } from "@fider/hooks"; +import React, { useState, useEffect } from "react" +import { SignInModal, EnvironmentInfo, Avatar, TenantLogo } from "@fider/components" +import { actions } from "@fider/services" +import { FaUser, FaCog, FaCaretDown } from "react-icons/fa" +import { useFider } from "@fider/hooks" export const Header = () => { - const fider = useFider(); - const [isSignInModalOpen, setIsSignInModalOpen] = useState(false); - const [unreadNotifications, setUnreadNotifications] = useState(0); + const fider = useFider() + const [isSignInModalOpen, setIsSignInModalOpen] = useState(false) + const [unreadNotifications, setUnreadNotifications] = useState(0) useEffect(() => { if (fider.session.isAuthenticated) { actions.getTotalUnreadNotifications().then((result) => { if (result.ok && result.data > 0) { - setUnreadNotifications(result.data); + setUnreadNotifications(result.data) } - }); + }) } - }, [fider.session.isAuthenticated]); + }, [fider.session.isAuthenticated]) const showModal = () => { if (!fider.session.isAuthenticated) { - setIsSignInModalOpen(true); + setIsSignInModalOpen(true) } - }; + } - const hideModal = () => setIsSignInModalOpen(false); + const hideModal = () => setIsSignInModalOpen(false) const items = fider.session.isAuthenticated && (
@@ -55,9 +55,9 @@ export const Header = () => { Sign out
- ); + ) - const showRightMenu = fider.session.isAuthenticated || !fider.session.tenant.isPrivate; + const showRightMenu = fider.session.isAuthenticated || !fider.session.tenant.isPrivate return (
@@ -80,5 +80,5 @@ export const Header = () => {
- ); -}; + ) +} diff --git a/public/components/common/Heading.tsx b/public/components/common/Heading.tsx index 621fefb68..2985013c6 100644 --- a/public/components/common/Heading.tsx +++ b/public/components/common/Heading.tsx @@ -1,36 +1,37 @@ -import "./Heading.scss"; +import "./Heading.scss" -import React from "react"; -import { classSet } from "@fider/services"; -import { IconType } from "react-icons"; +import React from "react" +import { classSet } from "@fider/services" +import { IconType } from "react-icons" interface HeadingLogo { - title: string; - dividing?: boolean; - size?: "normal" | "small"; - icon?: IconType; - subtitle?: string; - className?: string; + title: string + dividing?: boolean + size?: "normal" | "small" + icon?: IconType + subtitle?: string + className?: string } -const Header: React.FunctionComponent<{ level: number; className: string }> = (props) => React.createElement(`h${props.level}`, { className: props.className }, props.children); +const Header: React.FunctionComponent<{ level: number; className: string }> = (props) => + React.createElement(`h${props.level}`, { className: props.className }, props.children) export const Heading = (props: HeadingLogo) => { - const size = props.size || "normal"; - const level = size === "normal" ? 2 : 3; + const size = props.size || "normal" + const level = size === "normal" ? 2 : 3 const className = classSet({ "c-heading": true, "m-dividing": props.dividing || false, [`m-${size}`]: true, [`${props.className}`]: props.className, - }); + }) const iconClassName = classSet({ "c-heading-icon": true, circular: level <= 2, - }); + }) - const icon = props.icon &&
{React.createElement(props.icon)}
; + const icon = props.icon &&
{React.createElement(props.icon)}
return (
@@ -40,5 +41,5 @@ export const Heading = (props: HeadingLogo) => {
{props.subtitle}
- ); -}; + ) +} diff --git a/public/components/common/Hint.tsx b/public/components/common/Hint.tsx index 43b96bca6..cf5692537 100644 --- a/public/components/common/Hint.tsx +++ b/public/components/common/Hint.tsx @@ -1,33 +1,33 @@ -import "./Hint.scss"; +import "./Hint.scss" -import React, { useState } from "react"; -import { FaTimes } from "react-icons/fa"; +import React, { useState } from "react" +import { FaTimes } from "react-icons/fa" -import { cache } from "@fider/services"; +import { cache } from "@fider/services" interface HintProps { - permanentCloseKey?: string; - condition?: boolean; + permanentCloseKey?: string + condition?: boolean } export const Hint: React.FC = (props) => { - const cacheKey: string | undefined = props.permanentCloseKey ? `Hint-Closed-${props.permanentCloseKey}` : undefined; - const [isClosed, setIsClosed] = useState(cacheKey ? cache.local.has(cacheKey) : false); + const cacheKey: string | undefined = props.permanentCloseKey ? `Hint-Closed-${props.permanentCloseKey}` : undefined + const [isClosed, setIsClosed] = useState(cacheKey ? cache.local.has(cacheKey) : false) const close = () => { if (cacheKey) { - cache.local.set(cacheKey, "true"); + cache.local.set(cacheKey, "true") } - setIsClosed(true); - }; + setIsClosed(true) + } if (props.condition === false || isClosed) { - return null; + return null } return (

HINT: {props.children} {cacheKey && }

- ); -}; + ) +} diff --git a/public/components/common/Legal.tsx b/public/components/common/Legal.tsx index 9285dd70c..dababcb98 100644 --- a/public/components/common/Legal.tsx +++ b/public/components/common/Legal.tsx @@ -1,72 +1,72 @@ -import React from "react"; -import { Modal, Checkbox } from "@fider/components/common"; -import { useFider } from "@fider/hooks"; +import React from "react" +import { Modal, Checkbox } from "@fider/components/common" +import { useFider } from "@fider/hooks" interface LegalAgreementProps { - onChange: (agreed: boolean) => void; + onChange: (agreed: boolean) => void } -export const TermsOfService: React.FunctionComponent<{}> = () => { - const fider = useFider(); +export const TermsOfService: React.FunctionComponent = () => { + const fider = useFider() if (fider.settings.hasLegal) { return ( Terms of Service - ); + ) } - return null; -}; + return null +} -export const PrivacyPolicy: React.FunctionComponent<{}> = () => { - const fider = useFider(); +export const PrivacyPolicy: React.FunctionComponent = () => { + const fider = useFider() if (fider.settings.hasLegal) { return ( Privacy Policy - ); + ) } - return null; -}; + return null +} -export const LegalNotice: React.FunctionComponent<{}> = () => { - const fider = useFider(); +export const LegalNotice: React.FunctionComponent = () => { + const fider = useFider() if (fider.settings.hasLegal) { return (

By signing in, you agree to the and .

- ); + ) } - return null; -}; + return null +} -export const LegalFooter: React.FunctionComponent<{}> = () => { - const fider = useFider(); +export const LegalFooter: React.FunctionComponent = () => { + const fider = useFider() if (fider.settings.hasLegal) { return ( - ); + ) } - return null; -}; + return null +} export const LegalAgreement: React.FunctionComponent = (props) => { - const fider = useFider(); + const fider = useFider() if (fider.settings.hasLegal) { return ( I have read and agree to the and . - ); + ) } - return null; -}; + return null +} diff --git a/public/components/common/List.tsx b/public/components/common/List.tsx index d3f6e7c6c..0e5e0ab07 100644 --- a/public/components/common/List.tsx +++ b/public/components/common/List.tsx @@ -1,17 +1,17 @@ -import "./List.scss"; +import "./List.scss" -import React from "react"; -import { classSet } from "@fider/services"; +import React from "react" +import { classSet } from "@fider/services" interface ListProps { - className?: string; - divided?: boolean; - hover?: boolean; + className?: string + divided?: boolean + hover?: boolean } interface ListItemProps { - className?: string; - onClick?: () => void; + className?: string + onClick?: () => void } export const List: React.FunctionComponent = (props) => { @@ -20,24 +20,24 @@ export const List: React.FunctionComponent = (props) => { [props.className || ""]: true, "m-divided": props.divided, "m-hover": props.hover, - }); + }) - return
{props.children}
; -}; + return
{props.children}
+} export const ListItem: React.FunctionComponent = (props) => { const className = classSet({ "c-list-item": true, [props.className || ""]: true, "m-selectable": props.onClick, - }); + }) if (props.onClick) { return (
{props.children}
- ); + ) } - return
{props.children}
; -}; + return
{props.children}
+} diff --git a/public/components/common/Loader.tsx b/public/components/common/Loader.tsx index ce0beb2dd..a5b7ac3f4 100644 --- a/public/components/common/Loader.tsx +++ b/public/components/common/Loader.tsx @@ -1,14 +1,14 @@ -import "./Loader.scss"; +import "./Loader.scss" -import React, { useState } from "react"; -import { useTimeout } from "@fider/hooks"; +import React, { useState } from "react" +import { useTimeout } from "@fider/hooks" export function Loader() { - const [show, setShow] = useState(false); + const [show, setShow] = useState(false) useTimeout(() => { - setShow(true); - }, 500); + setShow(true) + }, 500) - return show ?
: null; + return show ?
: null } diff --git a/public/components/common/Logo.tsx b/public/components/common/Logo.tsx index 38f46a81c..980ae1265 100644 --- a/public/components/common/Logo.tsx +++ b/public/components/common/Logo.tsx @@ -1,44 +1,44 @@ -import React from "react"; -import { uploadedImageURL } from "@fider/services"; -import { useFider } from "@fider/hooks"; -import { Tenant } from "@fider/models"; +import React from "react" +import { uploadedImageURL } from "@fider/services" +import { useFider } from "@fider/hooks" +import { Tenant } from "@fider/models" -type Size = 24 | 50 | 100 | 200; +type Size = 24 | 50 | 100 | 200 interface TenantLogoProps { - size: Size; - useFiderIfEmpty?: boolean; + size: Size + useFiderIfEmpty?: boolean } export const TenantLogoURL = (tenant: Tenant, size: Size): string | undefined => { if (tenant && tenant.logoBlobKey) { - return uploadedImageURL(tenant.logoBlobKey, size); + return uploadedImageURL(tenant.logoBlobKey, size) } - return undefined; -}; + return undefined +} export const TenantLogo = (props: TenantLogoProps) => { - const fider = useFider(); + const fider = useFider() - const tenant = fider.session.tenant; + const tenant = fider.session.tenant if (tenant && tenant.logoBlobKey) { - return {tenant.name}; + return {tenant.name} } else if (props.useFiderIfEmpty) { - return Fider; + return Fider } - return null; -}; + return null +} TenantLogo.defaultProps = { useFiderIfEmpty: false, -}; +} interface OAuthProviderLogoProps { option: { - provider?: string; - displayName: string; - logoBlobKey?: string; - }; + provider?: string + displayName: string + logoBlobKey?: string + } } const systemProvidersLogo: { [key: string]: string } = { @@ -46,23 +46,23 @@ const systemProvidersLogo: { [key: string]: string } = { facebook: `data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMC8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvVFIvMjAwMS9SRUMtU1ZHLTIwMDEwOTA0L0RURC9zdmcxMC5kdGQnPjxzdmcgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMzIgMzIiIGhlaWdodD0iMzJweCIgaWQ9IkxheWVyXzEiIHZlcnNpb249IjEuMCIgdmlld0JveD0iMCAwIDMyIDMyIiB3aWR0aD0iMzJweCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGc+PHBhdGggZD0iTTMyLDMwYzAsMS4xMDQtMC44OTYsMi0yLDJIMmMtMS4xMDQsMC0yLTAuODk2LTItMlYyYzAtMS4xMDQsMC44OTYtMiwyLTJoMjhjMS4xMDQsMCwyLDAuODk2LDIsMlYzMHoiIGZpbGw9IiMzQjU5OTgiLz48cGF0aCBkPSJNMjIsMzJWMjBoNGwxLTVoLTV2LTJjMC0yLDEuMDAyLTMsMy0zaDJWNWMtMSwwLTIuMjQsMC00LDBjLTMuNjc1LDAtNiwyLjg4MS02LDd2M2gtNHY1aDR2MTJIMjJ6IiBmaWxsPSIjRkZGRkZGIiBpZD0iZiIvPjwvZz48Zy8+PGcvPjxnLz48Zy8+PGcvPjxnLz48L3N2Zz4=`, github: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMC8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvVFIvMjAwMS9SRUMtU1ZHLTIwMDEwOTA0L0RURC9zdmcxMC5kdGQnPjxzdmcgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMzIgMzIiIGhlaWdodD0iMzJweCIgaWQ9IkxheWVyXzEiIHZlcnNpb249IjEuMCIgdmlld0JveD0iMCAwIDMyIDMyIiB3aWR0aD0iMzJweCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PHBhdGggY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTYuMDAzLDBDNy4xNywwLDAuMDA4LDcuMTYyLDAuMDA4LDE1Ljk5NyAgYzAsNy4wNjcsNC41ODIsMTMuMDYzLDEwLjk0LDE1LjE3OWMwLjgsMC4xNDYsMS4wNTItMC4zMjgsMS4wNTItMC43NTJjMC0wLjM4LDAuMDA4LTEuNDQyLDAtMi43NzcgIGMtNC40NDksMC45NjctNS4zNzEtMi4xMDctNS4zNzEtMi4xMDdjLTAuNzI3LTEuODQ4LTEuNzc1LTIuMzQtMS43NzUtMi4zNGMtMS40NTItMC45OTIsMC4xMDktMC45NzMsMC4xMDktMC45NzMgIGMxLjYwNSwwLjExMywyLjQ1MSwxLjY0OSwyLjQ1MSwxLjY0OWMxLjQyNywyLjQ0MywzLjc0MywxLjczNyw0LjY1NCwxLjMyOWMwLjE0Ni0xLjAzNCwwLjU2LTEuNzM5LDEuMDE3LTIuMTM5ICBjLTMuNTUyLTAuNDA0LTcuMjg2LTEuNzc2LTcuMjg2LTcuOTA2YzAtMS43NDcsMC42MjMtMy4xNzQsMS42NDYtNC4yOTJDNy4yOCwxMC40NjQsNi43Myw4LjgzNyw3LjYwMiw2LjYzNCAgYzAsMCwxLjM0My0wLjQzLDQuMzk4LDEuNjQxYzEuMjc2LTAuMzU1LDIuNjQ1LTAuNTMyLDQuMDA1LTAuNTM4YzEuMzU5LDAuMDA2LDIuNzI3LDAuMTgzLDQuMDA1LDAuNTM4ICBjMy4wNTUtMi4wNyw0LjM5Ni0xLjY0MSw0LjM5Ni0xLjY0MWMwLjg3MiwyLjIwMywwLjMyMywzLjgzLDAuMTU5LDQuMjM0YzEuMDIzLDEuMTE4LDEuNjQ0LDIuNTQ1LDEuNjQ0LDQuMjkyICBjMCw2LjE0Ni0zLjc0LDcuNDk4LTcuMzA0LDcuODkzQzE5LjQ3OSwyMy41NDgsMjAsMjQuNTA4LDIwLDI2YzAsMiwwLDMuOTAyLDAsNC40MjhjMCwwLjQyOCwwLjI1OCwwLjkwMSwxLjA3LDAuNzQ2ICBDMjcuNDIyLDI5LjA1NSwzMiwyMy4wNjIsMzIsMTUuOTk3QzMyLDcuMTYyLDI0LjgzOCwwLDE2LjAwMywweiIgZmlsbD0iIzE4MTYxNiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PGcvPjxnLz48Zy8+PGcvPjxnLz48Zy8+PC9zdmc+", -}; +} export const OAuthProviderLogoURL = (logoBlobKey?: string): string | undefined => { if (logoBlobKey) { - return uploadedImageURL(logoBlobKey, 100); + return uploadedImageURL(logoBlobKey, 100) } - return undefined; -}; + return undefined +} export const OAuthProviderLogo = (props: OAuthProviderLogoProps) => { if (props.option.logoBlobKey) { - return {props.option.displayName}; + return {props.option.displayName} } if (props.option.provider && props.option.provider in systemProvidersLogo) { - return {props.option.displayName}; + return {props.option.displayName} } - return null; -}; + return null +} diff --git a/public/components/common/Message.tsx b/public/components/common/Message.tsx index 82d4477b8..0e28e5f46 100644 --- a/public/components/common/Message.tsx +++ b/public/components/common/Message.tsx @@ -1,26 +1,26 @@ -import "./Message.scss"; +import "./Message.scss" -import React from "react"; -import { classSet } from "@fider/services"; -import { FaBan, FaRegCheckCircle, FaExclamationTriangle } from "react-icons/fa"; +import React from "react" +import { classSet } from "@fider/services" +import { FaBan, FaRegCheckCircle, FaExclamationTriangle } from "react-icons/fa" interface MessageProps { - type: "success" | "warning" | "error"; - showIcon?: boolean; + type: "success" | "warning" | "error" + showIcon?: boolean } export const Message: React.FunctionComponent = (props) => { const className = classSet({ "c-message": true, [`m-${props.type}`]: true, - }); + }) - const icon = props.type === "error" ? : props.type === "warning" ? : ; + const icon = props.type === "error" ? : props.type === "warning" ? : return (

{props.showIcon === true && icon} {props.children}

- ); -}; + ) +} diff --git a/public/components/common/Modal.tsx b/public/components/common/Modal.tsx index 0cafa7504..fe359b5bc 100644 --- a/public/components/common/Modal.tsx +++ b/public/components/common/Modal.tsx @@ -1,55 +1,55 @@ -import "./Modal.scss"; +import "./Modal.scss" -import React, { useEffect, useRef } from "react"; -import ReactDOM from "react-dom"; -import { classSet } from "@fider/services"; +import React, { useEffect, useRef } from "react" +import ReactDOM from "react-dom" +import { classSet } from "@fider/services" interface ModalWindowProps { - className?: string; - isOpen: boolean; - size?: "small" | "large" | "fluid"; - canClose?: boolean; - center?: boolean; - onClose: () => void; + className?: string + isOpen: boolean + size?: "small" | "large" | "fluid" + canClose?: boolean + center?: boolean + onClose: () => void } interface ModalFooterProps { - align?: "left" | "center" | "right"; - children?: React.ReactNode; + align?: "left" | "center" | "right" + children?: React.ReactNode } const ModalWindow: React.FunctionComponent = (props) => { - const root = useRef(document.getElementById("root-modal")); + const root = useRef(document.getElementById("root-modal")) useEffect(() => { if (props.isOpen) { - document.body.style.overflow = "hidden"; - document.addEventListener("keydown", keyDown, false); + document.body.style.overflow = "hidden" + document.addEventListener("keydown", keyDown, false) } else { - document.body.style.overflow = ""; - document.removeEventListener("keydown", keyDown, false); + document.body.style.overflow = "" + document.removeEventListener("keydown", keyDown, false) } - }, [props.isOpen]); + }, [props.isOpen]) const swallow = (evt: React.MouseEvent) => { - evt.stopPropagation(); - }; + evt.stopPropagation() + } const keyDown = (event: KeyboardEvent) => { if (event.keyCode === 27) { // ESC - close(); + close() } - }; + } const close = () => { if (props.canClose) { - props.onClose(); + props.onClose() } - }; + } - if (!props.isOpen) { - return null; + if (!props.isOpen || !root.current) { + return null } const className = classSet({ @@ -57,7 +57,7 @@ const ModalWindow: React.FunctionComponent = (props) => { [`${props.className}`]: !!props.className, "m-center": props.center, [`m-${props.size}`]: true, - }); + }) return ReactDOM.createPortal(
@@ -65,30 +65,30 @@ const ModalWindow: React.FunctionComponent = (props) => { {props.children}
, - root.current! - ); -}; + root.current + ) +} ModalWindow.defaultProps = { size: "small", canClose: true, center: true, -}; +} + +const Header = (props: { children: React.ReactNode }) =>
{props.children}
+const Content = (props: { children: React.ReactNode }) =>
{props.children}
+const Footer = (props: ModalFooterProps) => { + const align = props.align || "right" + const className = classSet({ + "c-modal-footer": true, + [`m-${align}`]: true, + }) + return
{props.children}
+} export const Modal = { Window: ModalWindow, - Header: (props: { children: React.ReactNode }) => { - return
{props.children}
; - }, - Content: (props: { children: React.ReactNode }) => { - return
{props.children}
; - }, - Footer: (props: ModalFooterProps) => { - const align = props.align || "right"; - const className = classSet({ - "c-modal-footer": true, - [`m-${align}`]: true, - }); - return
{props.children}
; - }, -}; + Header, + Content, + Footer, +} diff --git a/public/components/common/Moment.tsx b/public/components/common/Moment.tsx index f7654d787..be5cdef23 100644 --- a/public/components/common/Moment.tsx +++ b/public/components/common/Moment.tsx @@ -1,29 +1,29 @@ -import React from "react"; -import { formatDate, timeSince } from "@fider/services"; +import React from "react" +import { formatDate, timeSince } from "@fider/services" interface MomentText { - date: Date | string; - useRelative?: boolean; - format?: "full" | "short"; + date: Date | string + useRelative?: boolean + format?: "full" | "short" } export const Moment = (props: MomentText) => { if (!props.date) { - return ; + return } - const format = props.format || "full"; - const useRelative = typeof props.useRelative !== "undefined" ? props.useRelative : true; + const format = props.format || "full" + const useRelative = typeof props.useRelative !== "undefined" ? props.useRelative : true - const now = new Date(); - const date = props.date instanceof Date ? props.date : new Date(props.date); + const now = new Date() + const date = props.date instanceof Date ? props.date : new Date(props.date) - const diff = (now.getTime() - date.getTime()) / (60 * 60 * 24 * 1000); - const display = !useRelative || diff >= 365 ? formatDate(props.date, format) : timeSince(now, date); + const diff = (now.getTime() - date.getTime()) / (60 * 60 * 24 * 1000) + const display = !useRelative || diff >= 365 ? formatDate(props.date, format) : timeSince(now, date) return ( {display} - ); -}; + ) +} diff --git a/public/components/common/MultiLineText.tsx b/public/components/common/MultiLineText.tsx index a5edca3f3..de0d23825 100644 --- a/public/components/common/MultiLineText.tsx +++ b/public/components/common/MultiLineText.tsx @@ -1,17 +1,17 @@ -import React from "react"; -import { markdown } from "@fider/services"; +import React from "react" +import { markdown } from "@fider/services" -interface MultiLineText { - className?: string; - text?: string; - style: "full" | "simple"; +interface MultiLineTextProps { + className?: string + text?: string + style: "full" | "simple" } -export const MultiLineText = (props: MultiLineText) => { +export const MultiLineText = (props: MultiLineTextProps) => { if (!props.text) { - return

; + return

} - const func = props.style === "full" ? markdown.full : markdown.simple; - return

; -}; + const func = props.style === "full" ? markdown.full : markdown.simple + return
+} diff --git a/public/components/common/Segment.tsx b/public/components/common/Segment.tsx index 83b5174dd..b9f23235a 100644 --- a/public/components/common/Segment.tsx +++ b/public/components/common/Segment.tsx @@ -1,15 +1,15 @@ -import "./Segment.scss"; +import "./Segment.scss" -import React from "react"; +import React from "react" interface SegmentProps { - className?: string; + className?: string } export const Segments: React.FunctionComponent = (props) => { - return
{props.children}
; -}; + return
{props.children}
+} export const Segment: React.FunctionComponent = (props) => { - return
{props.children}
; -}; + return
{props.children}
+} diff --git a/public/components/common/SignInControl.tsx b/public/components/common/SignInControl.tsx index c4d1c873b..d19b0b215 100644 --- a/public/components/common/SignInControl.tsx +++ b/public/components/common/SignInControl.tsx @@ -1,35 +1,35 @@ -import "./SignInControl.scss"; +import "./SignInControl.scss" -import React, { useState } from "react"; -import { SocialSignInButton, Form, Button, Input, Message } from "@fider/components"; -import { device, actions, Failure, isCookieEnabled } from "@fider/services"; -import { useFider } from "@fider/hooks"; +import React, { useState } from "react" +import { SocialSignInButton, Form, Button, Input, Message } from "@fider/components" +import { device, actions, Failure, isCookieEnabled } from "@fider/services" +import { useFider } from "@fider/hooks" interface SignInControlProps { - useEmail: boolean; - redirectTo?: string; - onEmailSent?: (email: string) => void; + useEmail: boolean + redirectTo?: string + onEmailSent?: (email: string) => void } export const SignInControl: React.FunctionComponent = (props) => { - const fider = useFider(); - const [email, setEmail] = useState(""); - const [error, setError] = useState(undefined); + const fider = useFider() + const [email, setEmail] = useState("") + const [error, setError] = useState(undefined) const signIn = async () => { - const result = await actions.signIn(email); + const result = await actions.signIn(email) if (result.ok) { - setEmail(""); - setError(undefined); + setEmail("") + setError(undefined) if (props.onEmailSent) { - props.onEmailSent(email); + props.onEmailSent(email) } } else if (result.error) { - setError(result.error); + setError(result.error) } - }; + } - const providersLen = fider.settings.oauth.length; + const providersLen = fider.settings.oauth.length if (!isCookieEnabled()) { return ( @@ -37,7 +37,7 @@ export const SignInControl: React.FunctionComponent = (props

Cookies Required

Cookies are not enabled on your browser. Please enable cookies in your browser preferences to continue.

- ); + ) } return ( @@ -80,5 +80,5 @@ export const SignInControl: React.FunctionComponent = (props
)}
- ); -}; + ) +} diff --git a/public/components/common/SocialSignInButton.tsx b/public/components/common/SocialSignInButton.tsx index 70d55acf4..286abb878 100644 --- a/public/components/common/SocialSignInButton.tsx +++ b/public/components/common/SocialSignInButton.tsx @@ -1,30 +1,30 @@ -import React from "react"; -import { Button, OAuthProviderLogo } from "@fider/components/common"; -import { classSet } from "@fider/services"; +import React from "react" +import { Button, OAuthProviderLogo } from "@fider/components/common" +import { classSet } from "@fider/services" interface SocialSignInButtonProps { option: { - displayName: string; - provider?: string; - url?: string; - logoBlobKey?: string; - logoURL?: string; - }; - redirectTo?: string; + displayName: string + provider?: string + url?: string + logoBlobKey?: string + logoURL?: string + } + redirectTo?: string } export const SocialSignInButton = (props: SocialSignInButtonProps) => { - const redirectTo = props.redirectTo || window.location.href; - const href = props.option.url ? `${props.option.url}?redirect=${redirectTo}` : undefined; + const redirectTo = props.redirectTo || window.location.href + const href = props.option.url ? `${props.option.url}?redirect=${redirectTo}` : undefined const className = classSet({ "m-social": true, [`m-${props.option.provider}`]: props.option.provider, - }); + }) return ( - ); -}; + ) +} diff --git a/public/components/common/Toggle.tsx b/public/components/common/Toggle.tsx index c9b572bd3..1f8f0dde4 100644 --- a/public/components/common/Toggle.tsx +++ b/public/components/common/Toggle.tsx @@ -1,34 +1,34 @@ -import "./Toggle.scss"; +import "./Toggle.scss" -import React, { useState } from "react"; -import { classSet } from "@fider/services"; +import React, { useState } from "react" +import { classSet } from "@fider/services" interface ToggleProps { - label?: string; - active: boolean; - disabled?: boolean; - onToggle?: (active: boolean) => void; + label?: string + active: boolean + disabled?: boolean + onToggle?: (active: boolean) => void } export const Toggle: React.StatelessComponent = (props) => { - const [active, setActive] = useState(props.active); + const [active, setActive] = useState(props.active) const toggle = () => { if (props.disabled) { - return; + return } - const newActive = !active; - setActive(newActive); + const newActive = !active + setActive(newActive) if (props.onToggle) { - props.onToggle(newActive); + props.onToggle(newActive) } - }; + } const className = classSet({ "c-toggle": true, "m-disabled": !!props.disabled, - }); + }) return ( @@ -38,5 +38,5 @@ export const Toggle: React.StatelessComponent = (props) => { {!!props.label && props.label} - ); -}; + ) +} diff --git a/public/components/common/UserName.tsx b/public/components/common/UserName.tsx index fd38ab405..debbdf633 100644 --- a/public/components/common/UserName.tsx +++ b/public/components/common/UserName.tsx @@ -1,22 +1,22 @@ -import "./UserName.scss"; +import "./UserName.scss" -import React from "react"; -import { isCollaborator, UserRole } from "@fider/models"; -import { classSet } from "@fider/services"; +import React from "react" +import { isCollaborator, UserRole } from "@fider/models" +import { classSet } from "@fider/services" interface UserNameProps { user: { - id: number; - name: string; - role?: UserRole; - }; + id: number + name: string + role?: UserRole + } } export const UserName = (props: UserNameProps) => { const className = classSet({ "c-username": true, "m-staff": props.user.role && isCollaborator(props.user.role), - }); + }) - return {props.user.name || "Anonymous"}; -}; + return {props.user.name || "Anonymous"} +} diff --git a/public/components/common/form/Checkbox.tsx b/public/components/common/form/Checkbox.tsx index 7127085d9..4fea69a14 100644 --- a/public/components/common/form/Checkbox.tsx +++ b/public/components/common/form/Checkbox.tsx @@ -1,22 +1,22 @@ -import React, { useState } from "react"; -import { classSet } from "@fider/services"; -import { DisplayError, ValidationContext, hasError } from "../"; +import React, { useState } from "react" +import { classSet } from "@fider/services" +import { DisplayError, ValidationContext, hasError } from "../" interface CheckboxProps { - field: string; - checked?: boolean; - onChange: (checked: boolean) => void; + field: string + checked?: boolean + onChange: (checked: boolean) => void } export const Checkbox: React.FC = (props) => { - const [checked, setChecked] = useState(props.checked || false); + const [checked, setChecked] = useState(props.checked || false) const onChange = (e: React.ChangeEvent) => { - const isChecked: boolean = e.currentTarget.checked; + const isChecked: boolean = e.currentTarget.checked - setChecked(isChecked); - props.onChange(isChecked); - }; + setChecked(isChecked) + props.onChange(isChecked) + } return ( @@ -35,5 +35,5 @@ export const Checkbox: React.FC = (props) => {
)} - ); -}; + ) +} diff --git a/public/components/common/form/DisplayError.spec.tsx b/public/components/common/form/DisplayError.spec.tsx index c53ea2338..39dfe35d8 100644 --- a/public/components/common/form/DisplayError.spec.tsx +++ b/public/components/common/form/DisplayError.spec.tsx @@ -1,39 +1,39 @@ -import React from "react"; -import { shallow } from "enzyme"; -import { DisplayError } from "./DisplayError"; -import { Failure } from "@fider/services"; +import React from "react" +import { shallow } from "enzyme" +import { DisplayError } from "./DisplayError" +import { Failure } from "@fider/services" describe("", () => { test("when error is undefined", () => { - const wrapper = shallow(); - expect(wrapper.getElement()).toBeNull(); + const wrapper = shallow() + expect(wrapper.getElement()).toBeNull() - const wrapper1 = shallow(); - expect(wrapper1.getElement()).toBeNull(); - }); + const wrapper1 = shallow() + expect(wrapper1.getElement()).toBeNull() + }) test("when error has only top level messages and fields is empty", () => { const error: Failure = { errors: [{ message: "Something went wrong." }], - }; + } - const wrapper = shallow(); - const root = wrapper.find("div"); - expect(root.hasClass("c-form-field-error")).toBe(true); - const items = root.find("ul li"); - expect(items).toHaveLength(1); - expect(items.at(0).key()).toBe("Something went wrong."); - expect(items.at(0).text()).toBe("Something went wrong."); - }); + const wrapper = shallow() + const root = wrapper.find("div") + expect(root.hasClass("c-form-field-error")).toBe(true) + const items = root.find("ul li") + expect(items).toHaveLength(1) + expect(items.at(0).key()).toBe("Something went wrong.") + expect(items.at(0).text()).toBe("Something went wrong.") + }) test("when error has only top level messages and fields is given", () => { const error: Failure = { errors: [{ message: "Something went wrong." }], - }; + } - const wrapper = shallow(); - expect(wrapper.getElement()).toBeNull(); - }); + const wrapper = shallow() + expect(wrapper.getElement()).toBeNull() + }) test("when error has both field and top level messages and fields are given", () => { const error: Failure = { @@ -43,36 +43,36 @@ describe("", () => { { field: "name", message: "Name must have between 0 and 10 chars" }, { field: "age", message: "Age must be >= 18" }, ], - }; + } - const wrapper1 = shallow(); - const root1 = wrapper1.find("div"); - expect(root1.hasClass("c-form-field-error")).toBe(true); - const items1 = root1.find("ul li"); - expect(items1).toHaveLength(2); - expect(items1.at(0).key()).toBe("Name is required"); - expect(items1.at(0).text()).toBe("Name is required"); - expect(items1.at(1).key()).toBe("Name must have between 0 and 10 chars"); - expect(items1.at(1).text()).toBe("Name must have between 0 and 10 chars"); + const wrapper1 = shallow() + const root1 = wrapper1.find("div") + expect(root1.hasClass("c-form-field-error")).toBe(true) + const items1 = root1.find("ul li") + expect(items1).toHaveLength(2) + expect(items1.at(0).key()).toBe("Name is required") + expect(items1.at(0).text()).toBe("Name is required") + expect(items1.at(1).key()).toBe("Name must have between 0 and 10 chars") + expect(items1.at(1).text()).toBe("Name must have between 0 and 10 chars") - const wrapper2 = shallow(); - const root2 = wrapper2.find("div"); - expect(root2.hasClass("c-form-field-error")).toBe(true); - const items2 = root2.find("ul li"); - expect(items2).toHaveLength(1); - expect(items2.at(0).key()).toBe("Age must be >= 18"); - expect(items2.at(0).text()).toBe("Age must be >= 18"); + const wrapper2 = shallow() + const root2 = wrapper2.find("div") + expect(root2.hasClass("c-form-field-error")).toBe(true) + const items2 = root2.find("ul li") + expect(items2).toHaveLength(1) + expect(items2.at(0).key()).toBe("Age must be >= 18") + expect(items2.at(0).text()).toBe("Age must be >= 18") - const wrapper3 = shallow(); - const root3 = wrapper3.find("div"); - expect(root3.hasClass("c-form-field-error")).toBe(true); - const items3 = root3.find("ul li"); - expect(items3).toHaveLength(3); - expect(items3.at(0).key()).toBe("Name is required"); - expect(items3.at(0).text()).toBe("Name is required"); - expect(items3.at(1).key()).toBe("Name must have between 0 and 10 chars"); - expect(items3.at(1).text()).toBe("Name must have between 0 and 10 chars"); - expect(items3.at(2).key()).toBe("Age must be >= 18"); - expect(items3.at(2).text()).toBe("Age must be >= 18"); - }); -}); + const wrapper3 = shallow() + const root3 = wrapper3.find("div") + expect(root3.hasClass("c-form-field-error")).toBe(true) + const items3 = root3.find("ul li") + expect(items3).toHaveLength(3) + expect(items3.at(0).key()).toBe("Name is required") + expect(items3.at(0).text()).toBe("Name is required") + expect(items3.at(1).key()).toBe("Name must have between 0 and 10 chars") + expect(items3.at(1).text()).toBe("Name must have between 0 and 10 chars") + expect(items3.at(2).key()).toBe("Age must be >= 18") + expect(items3.at(2).text()).toBe("Age must be >= 18") + }) +}) diff --git a/public/components/common/form/DisplayError.tsx b/public/components/common/form/DisplayError.tsx index 6cb66bb2e..cc18297c0 100644 --- a/public/components/common/form/DisplayError.tsx +++ b/public/components/common/form/DisplayError.tsx @@ -1,46 +1,46 @@ -import React from "react"; -import { Failure } from "@fider/services"; +import React from "react" +import { Failure } from "@fider/services" const arrayToTag = (items: string[]) => { - return items.map((m) =>
  • {m}
  • ); -}; + return items.map((m) =>
  • {m}
  • ) +} interface DisplayErrorProps { - error?: Failure; - fields?: string[]; + error?: Failure + fields?: string[] } export const hasError = (field?: string, error?: Failure): boolean => { if (field && error && error.errors) { for (const err of error.errors) { if (err.field === field) { - return true; + return true } } } - return false; -}; + return false +} export const DisplayError = (props: DisplayErrorProps) => { if (!props.error || !props.error.errors) { - return null; + return null } const dict = props.error.errors.reduce((result, err) => { - result[err.field || ""] = result[err.field || ""] || []; - result[err.field || ""].push(err.message); - return result; - }, {} as { [key: string]: string[] }); + result[err.field || ""] = result[err.field || ""] || [] + result[err.field || ""].push(err.message) + return result + }, {} as { [key: string]: string[] }) - let items: JSX.Element[] = []; + let items: JSX.Element[] = [] if (dict[""] && !props.fields) { - items = arrayToTag(dict[""]); + items = arrayToTag(dict[""]) } else if (props.fields) { for (const field of props.fields || Object.keys(dict)) { - if (dict.hasOwnProperty(field)) { - const tags = arrayToTag(dict[field]); - tags.forEach((t) => items.push(t)); + if (Object.prototype.hasOwnProperty.call(dict, field)) { + const tags = arrayToTag(dict[field]) + tags.forEach((t) => items.push(t)) } } } @@ -49,5 +49,5 @@ export const DisplayError = (props: DisplayErrorProps) => {
      {items}
    - ) : null; -}; + ) : null +} diff --git a/public/components/common/form/Field.tsx b/public/components/common/form/Field.tsx index 9bcf2b9b1..805f14023 100644 --- a/public/components/common/form/Field.tsx +++ b/public/components/common/form/Field.tsx @@ -1,17 +1,17 @@ -import React from "react"; -import { classSet } from "@fider/services"; -import { ValidationContext } from "./Form"; -import { DisplayError, hasError } from "./DisplayError"; +import React from "react" +import { classSet } from "@fider/services" +import { ValidationContext } from "./Form" +import { DisplayError, hasError } from "./DisplayError" interface FieldProps { - className?: string; - label?: string; - field?: string; - afterLabel?: JSX.Element; + className?: string + label?: string + field?: string + afterLabel?: JSX.Element } export const Field: React.FunctionComponent = (props) => { - const fields = props.field ? [props.field] : undefined; + const fields = props.field ? [props.field] : undefined return ( {(ctx) => ( @@ -19,7 +19,7 @@ export const Field: React.FunctionComponent = (props) => { className={classSet({ "c-form-field": true, "m-error": hasError(props.field, ctx.error), - [props.className!]: props.className, + [props.className || ""]: props.className, })} > {!!props.label && ( @@ -33,5 +33,5 @@ export const Field: React.FunctionComponent = (props) => { )} - ); -}; + ) +} diff --git a/public/components/common/form/Form.tsx b/public/components/common/form/Form.tsx index 2ee58d875..b2a397a9b 100644 --- a/public/components/common/form/Form.tsx +++ b/public/components/common/form/Form.tsx @@ -1,32 +1,32 @@ -import "./Form.scss"; +import "./Form.scss" -import React from "react"; -import { Failure, classSet } from "@fider/services"; -import { DisplayError } from "@fider/components"; +import React from "react" +import { Failure, classSet } from "@fider/services" +import { DisplayError } from "@fider/components" interface ValidationContext { - error?: Failure; + error?: Failure } interface FormProps { - className?: string; - size?: "mini" | "normal"; - error?: Failure; + className?: string + size?: "mini" | "normal" + error?: Failure } -export const ValidationContext = React.createContext({}); +export const ValidationContext = React.createContext({}) export const Form: React.FunctionComponent = (props) => { const className = classSet({ "c-form": true, - [props.className!]: props.className, + [props.className || ""]: props.className, [`m-${props.size}`]: props.size, - }); + }) return (
    {props.children} - ); -}; + ) +} diff --git a/public/components/common/form/ImageUploader.tsx b/public/components/common/form/ImageUploader.tsx index 4080a109a..8d4019875 100644 --- a/public/components/common/form/ImageUploader.tsx +++ b/public/components/common/form/ImageUploader.tsx @@ -1,52 +1,52 @@ -import "./ImageUploader.scss"; +import "./ImageUploader.scss" -import React from "react"; -import { ValidationContext } from "./Form"; -import { DisplayError, hasError } from "./DisplayError"; -import { classSet, fileToBase64, uploadedImageURL } from "@fider/services"; -import { Button, ButtonClickEvent, Modal } from "@fider/components"; -import { FaRegImage } from "react-icons/fa"; -import { ImageUpload } from "@fider/models"; +import React from "react" +import { ValidationContext } from "./Form" +import { DisplayError, hasError } from "./DisplayError" +import { classSet, fileToBase64, uploadedImageURL } from "@fider/services" +import { Button, Modal } from "@fider/components" +import { FaRegImage } from "react-icons/fa" +import { ImageUpload } from "@fider/models" -const hardFileSizeLimit = 5 * 1024 * 1024; +const hardFileSizeLimit = 5 * 1024 * 1024 interface ImageUploaderProps { - instanceID?: string; - field: string; - label?: string; - bkey?: string; - disabled?: boolean; - previewMaxWidth: number; - onChange(state: ImageUpload, instanceID?: string, previewURL?: string): void; + instanceID?: string + field: string + label?: string + bkey?: string + disabled?: boolean + previewMaxWidth: number + onChange(state: ImageUpload, instanceID?: string, previewURL?: string): void } interface ImageUploaderState extends ImageUpload { - previewURL?: string; - showModal: boolean; + previewURL?: string + showModal: boolean } export class ImageUploader extends React.Component { - private fileSelector?: HTMLInputElement | null; + private fileSelector?: HTMLInputElement | null constructor(props: ImageUploaderProps) { - super(props); + super(props) this.state = { upload: undefined, remove: false, showModal: false, previewURL: uploadedImageURL(this.props.bkey, this.props.previewMaxWidth), - }; + } } public fileChanged = async (e: React.ChangeEvent) => { if (e.target.files && e.target.files[0]) { - const file = e.target.files[0]; + const file = e.target.files[0] if (file.size > hardFileSizeLimit) { - alert("The image size must be smaller than 5MB."); - return; + alert("The image size must be smaller than 5MB.") + return } - const base64 = await fileToBase64(file); + const base64 = await fileToBase64(file) this.setState( { bkey: this.props.bkey, @@ -59,15 +59,15 @@ export class ImageUploader extends React.Component { - this.props.onChange(this.state, this.props.instanceID, this.state.previewURL); + this.props.onChange(this.state, this.props.instanceID, this.state.previewURL) } - ); + ) } - }; + } - public removeFile = async (e: ButtonClickEvent) => { + public removeFile = async () => { if (this.fileSelector) { - this.fileSelector.value = ""; + this.fileSelector.value = "" } this.setState( @@ -86,29 +86,29 @@ export class ImageUploader extends React.Component { + public selectFile = async () => { if (this.fileSelector) { - this.fileSelector.click(); + this.fileSelector.click() } - }; + } private openModal = () => { - this.setState({ showModal: true }); - }; + this.setState({ showModal: true }) + } private closeModal = async () => { - this.setState({ showModal: false }); - }; + this.setState({ showModal: false }) + } private modal() { return ( - {this.props.bkey ? : } + {this.props.bkey ? : } - ); + ) } } diff --git a/public/pages/Administration/components/TagListItem.tsx b/public/pages/Administration/components/TagListItem.tsx index 8a063be3e..3db71f8e7 100644 --- a/public/pages/Administration/components/TagListItem.tsx +++ b/public/pages/Administration/components/TagListItem.tsx @@ -1,48 +1,48 @@ -import React, { useState } from "react"; -import { Tag } from "@fider/models"; -import { ListItem, ShowTag, Button } from "@fider/components"; -import { TagFormState, TagForm } from "./TagForm"; -import { actions, Failure } from "@fider/services"; -import { FaTimes, FaEdit } from "react-icons/fa"; -import { useFider } from "@fider/hooks"; +import React, { useState } from "react" +import { Tag } from "@fider/models" +import { ListItem, ShowTag, Button } from "@fider/components" +import { TagFormState, TagForm } from "./TagForm" +import { actions, Failure } from "@fider/services" +import { FaTimes, FaEdit } from "react-icons/fa" +import { useFider } from "@fider/hooks" interface TagListItemProps { - tag: Tag; - onTagEdited: (tag: Tag) => void; - onTagDeleted: (tag: Tag) => void; + tag: Tag + onTagEdited: (tag: Tag) => void + onTagDeleted: (tag: Tag) => void } export const TagListItem = (props: TagListItemProps) => { - const fider = useFider(); - const [tag] = useState(props.tag); - const [state, setState] = useState<"view" | "edit" | "delete">("view"); + const fider = useFider() + const [tag] = useState(props.tag) + const [state, setState] = useState<"view" | "edit" | "delete">("view") - const startDelete = async () => setState("delete"); - const startEdit = async () => setState("edit"); - const resetState = async () => setState("view"); + const startDelete = async () => setState("delete") + const startEdit = async () => setState("edit") + const resetState = async () => setState("view") const deleteTag = async () => { - const result = await actions.deleteTag(tag.slug); + const result = await actions.deleteTag(tag.slug) if (result.ok) { - resetState(); - props.onTagDeleted(tag); + resetState() + props.onTagDeleted(tag) } - }; + } const updateTag = async (data: TagFormState): Promise => { - const result = await actions.updateTag(tag.slug, data.name, data.color, data.isPublic); + const result = await actions.updateTag(tag.slug, data.name, data.color, data.isPublic) if (result.ok) { - tag.name = result.data.name; - tag.slug = result.data.slug; - tag.color = result.data.color; - tag.isPublic = result.data.isPublic; + tag.name = result.data.name + tag.slug = result.data.slug + tag.color = result.data.color + tag.isPublic = result.data.isPublic - resetState(); - props.onTagEdited(tag); + resetState() + props.onTagEdited(tag) } else { - return result.error; + return result.error } - }; + } const renderDeleteMode = () => { return ( @@ -60,8 +60,8 @@ export const TagListItem = (props: TagListItemProps) => { Delete tag - ); - }; + ) + } const renderViewMode = () => { const buttons = fider.session.user.isAdministrator && [ @@ -73,21 +73,21 @@ export const TagListItem = (props: TagListItemProps) => { Edit , - ]; + ] return ( <> {buttons} - ); - }; + ) + } const renderEditMode = () => { - return ; - }; + return + } - const view = state === "delete" ? renderDeleteMode() : state === "edit" ? renderEditMode() : renderViewMode(); + const view = state === "delete" ? renderDeleteMode() : state === "edit" ? renderEditMode() : renderViewMode() - return {view}; -}; + return {view} +} diff --git a/public/pages/Administration/pages/AdvancedSettings.page.tsx b/public/pages/Administration/pages/AdvancedSettings.page.tsx index 4cce71608..75a3d9961 100644 --- a/public/pages/Administration/pages/AdvancedSettings.page.tsx +++ b/public/pages/Administration/pages/AdvancedSettings.page.tsx @@ -1,65 +1,73 @@ -import "./AdvancedSettings.page.scss"; +import "./AdvancedSettings.page.scss" -import React from "react"; +import React from "react" -import { TextArea, Form, Button, ButtonClickEvent } from "@fider/components"; -import { Failure, actions, Fider } from "@fider/services"; -import { FaStar } from "react-icons/fa"; -import { AdminBasePage } from "../components/AdminBasePage"; +import { TextArea, Form, Button } from "@fider/components" +import { Failure, actions, Fider } from "@fider/services" +import { FaStar } from "react-icons/fa" +import { AdminBasePage } from "../components/AdminBasePage" interface AdvancedSettingsPageProps { - customCSS: string; + customCSS: string } interface AdvancedSettingsPageState { - customCSS: string; - error?: Failure; + customCSS: string + error?: Failure } export default class AdvancedSettingsPage extends AdminBasePage { - public id = "p-admin-advanced"; - public name = "advanced"; - public icon = FaStar; - public title = "Advanced"; - public subtitle = "Manage your site settings"; + public id = "p-admin-advanced" + public name = "advanced" + public icon = FaStar + public title = "Advanced" + public subtitle = "Manage your site settings" constructor(props: AdvancedSettingsPageProps) { - super(props); + super(props) this.state = { customCSS: this.props.customCSS, - }; + } } private setCustomCSS = (customCSS: string): void => { - this.setState({ customCSS }); - }; + this.setState({ customCSS }) + } - private handleSave = async (e: ButtonClickEvent): Promise => { - const result = await actions.updateTenantAdvancedSettings(this.state.customCSS); + private handleSave = async (): Promise => { + const result = await actions.updateTenantAdvancedSettings(this.state.customCSS) if (result.ok) { - location.reload(); + location.reload() } else { - this.setState({ error: result.error }); + this.setState({ error: result.error }) } - }; + } public content() { return (
    - @@ -102,12 +112,22 @@ export default class GeneralSettingsPage extends AdminBasePage<{}, GeneralSettin onChange={this.setInvitation} >

    - This text is used as a placeholder for the suggestion's text box. Use it to invite your visitors into sharing their suggestions and feedback. Leave it empty for a default message. + This text is used as a placeholder for the suggestion's text box. Use it to invite your visitors into sharing their suggestions and feedback. + Leave it empty for a default message.

    - -

    We accept JPG, GIF and PNG images, smaller than 100KB and with an aspect ratio of 1:1 with minimum dimensions of 200x200 pixels.

    + +

    + We accept JPG, GIF and PNG images, smaller than 100KB and with an aspect ratio of 1:1 with minimum dimensions of 200x200 pixels. +

    {!Fider.isSingleHostMode() && ( @@ -143,6 +163,6 @@ export default class GeneralSettingsPage extends AdminBasePage<{}, GeneralSettin - ); + ) } } diff --git a/public/pages/Administration/pages/Invitations.page.tsx b/public/pages/Administration/pages/Invitations.page.tsx index b0587bee5..e1eb229d8 100644 --- a/public/pages/Administration/pages/Invitations.page.tsx +++ b/public/pages/Administration/pages/Invitations.page.tsx @@ -1,28 +1,28 @@ -import React from "react"; +import React from "react" -import { Button, ButtonClickEvent, TextArea, Form, Input, Field } from "@fider/components"; -import { actions, notify, Failure, Fider } from "@fider/services"; -import { AdminBasePage } from "../components/AdminBasePage"; -import { FaEnvelope } from "react-icons/fa"; +import { Button, TextArea, Form, Input, Field } from "@fider/components" +import { actions, notify, Failure, Fider } from "@fider/services" +import { AdminBasePage } from "../components/AdminBasePage" +import { FaEnvelope } from "react-icons/fa" interface InvitationsPageState { - subject: string; - message: string; - recipients: string[]; - numOfRecipients: number; - rawRecipients: string; - error?: Failure; + subject: string + message: string + recipients: string[] + numOfRecipients: number + rawRecipients: string + error?: Failure } -export default class InvitationsPage extends AdminBasePage<{}, InvitationsPageState> { - public id = "p-admin-invitations"; - public name = "invitations"; - public icon = FaEnvelope; - public title = "Invitations"; - public subtitle = "Invite people to share their feedback"; +export default class InvitationsPage extends AdminBasePage { + public id = "p-admin-invitations" + public name = "invitations" + public icon = FaEnvelope + public title = "Invitations" + public subtitle = "Invite people to share their feedback" - constructor(props: {}) { - super(props); + constructor(props: any) { + super(props) this.state = { subject: `Share your ideas and thoughts about ${Fider.session.tenant.name}`, @@ -41,52 +41,59 @@ ${Fider.session.user.name} (${Fider.session.tenant.name})`, recipients: [], numOfRecipients: 0, rawRecipients: "", - }; + } } private setRecipients = (rawRecipients: string) => { - const recipients = rawRecipients.split(/\n|;|,|\s/gm).filter((x) => !!x); - this.setState({ rawRecipients, recipients, numOfRecipients: recipients.length }); - }; + const recipients = rawRecipients.split(/\n|;|,|\s/gm).filter((x) => !!x) + this.setState({ rawRecipients, recipients, numOfRecipients: recipients.length }) + } - private sendSample = async (e: ButtonClickEvent) => { - const result = await actions.sendSampleInvite(this.state.subject, this.state.message); + private sendSample = async () => { + const result = await actions.sendSampleInvite(this.state.subject, this.state.message) if (result.ok) { notify.success( An email message was sent to {Fider.session.user.email} - ); + ) } - this.setState({ error: result.error }); - }; + this.setState({ error: result.error }) + } - private sendInvites = async (e: ButtonClickEvent) => { - const result = await actions.sendInvites(this.state.subject, this.state.message, this.state.recipients); + private sendInvites = async () => { + const result = await actions.sendInvites(this.state.subject, this.state.message, this.state.recipients) if (result.ok) { - notify.success("Your invites have been sent."); - this.setState({ rawRecipients: "", numOfRecipients: 0, recipients: [], error: undefined }); + notify.success("Your invites have been sent.") + this.setState({ rawRecipients: "", numOfRecipients: 0, recipients: [], error: undefined }) } else { - this.setState({ error: result.error }); + this.setState({ error: result.error }) } - }; + } private setSubject = (subject: string): void => { - this.setState({ subject }); - }; + this.setState({ subject }) + } private setMessage = (message: string): void => { - this.setState({ message }); - }; + this.setState({ message }) + } public content() { return (
    - -

    We highly recommend to send yourself a sample email for you to verify if everything is correct before inviting your list of contacts.

    +

    + We highly recommend to send yourself a sample email for you to verify if everything is correct before inviting your list of contacts. +

    {Fider.session.user.email ? ( ) : ( - + )}
    -

    Whenever you're ready, click the following button to send out these invites.

    +

    Whenever you're ready, click the following button to send out these invites.

    - ); + ) } } diff --git a/public/pages/Administration/pages/ManageAuthentication.page.tsx b/public/pages/Administration/pages/ManageAuthentication.page.tsx index 875b5019b..13537aec3 100644 --- a/public/pages/Administration/pages/ManageAuthentication.page.tsx +++ b/public/pages/Administration/pages/ManageAuthentication.page.tsx @@ -1,77 +1,81 @@ -import React from "react"; +import React from "react" -import { Segment, List, ListItem, Button, Heading, OAuthProviderLogo } from "@fider/components"; -import { OAuthConfig, OAuthProviderOption } from "@fider/models"; -import { OAuthForm } from "../components/OAuthForm"; -import { actions, notify, Fider } from "@fider/services"; -import { FaEdit, FaPlay, FaSignInAlt } from "react-icons/fa"; -import { AdminBasePage } from "../components/AdminBasePage"; +import { Segment, List, ListItem, Button, Heading, OAuthProviderLogo } from "@fider/components" +import { OAuthConfig, OAuthProviderOption } from "@fider/models" +import { OAuthForm } from "../components/OAuthForm" +import { actions, notify, Fider } from "@fider/services" +import { FaEdit, FaPlay, FaSignInAlt } from "react-icons/fa" +import { AdminBasePage } from "../components/AdminBasePage" -import "./ManageAuthentication.page.scss"; +import "./ManageAuthentication.page.scss" interface ManageAuthenticationPageProps { - providers: OAuthProviderOption[]; + providers: OAuthProviderOption[] } interface ManageAuthenticationPageState { - isAdding: boolean; - editing?: OAuthConfig; + isAdding: boolean + editing?: OAuthConfig } export default class ManageAuthenticationPage extends AdminBasePage { - public id = "p-admin-authentication"; - public name = "authentication"; - public icon = FaSignInAlt; - public title = "Authentication"; - public subtitle = "Manage your site authentication"; + public id = "p-admin-authentication" + public name = "authentication" + public icon = FaSignInAlt + public title = "Authentication" + public subtitle = "Manage your site authentication" constructor(props: ManageAuthenticationPageProps) { - super(props); + super(props) this.state = { isAdding: false, - }; + } } private addNew = async () => { - this.setState({ isAdding: true, editing: undefined }); - }; + this.setState({ isAdding: true, editing: undefined }) + } private edit = async (provider: string) => { - const result = await actions.getOAuthConfig(provider); + const result = await actions.getOAuthConfig(provider) if (result.ok) { - this.setState({ editing: result.data, isAdding: false }); + this.setState({ editing: result.data, isAdding: false }) } else { - notify.error("Failed to retrieve OAuth configuration. Try again later"); + notify.error("Failed to retrieve OAuth configuration. Try again later") } - }; + } private startTest = async (provider: string) => { - const redirect = `${Fider.settings.baseURL}/oauth/${provider}/echo`; - window.open(`/oauth/${provider}?redirect=${redirect}`, "oauth-test", "width=1100,height=600,status=no,menubar=no"); - }; + const redirect = `${Fider.settings.baseURL}/oauth/${provider}/echo` + window.open(`/oauth/${provider}?redirect=${redirect}`, "oauth-test", "width=1100,height=600,status=no,menubar=no") + } private cancel = async () => { - this.setState({ isAdding: false, editing: undefined }); - }; + this.setState({ isAdding: false, editing: undefined }) + } public content() { if (this.state.isAdding) { - return ; + return } if (this.state.editing) { - return ; + return } - const enabled =

    Enabled

    ; - const disabled =

    Disabled

    ; + const enabled =

    Enabled

    + const disabled =

    Disabled

    return ( <> - +

    Additional information is available in our{" "} - + OAuth Documentation . @@ -115,6 +119,6 @@ export default class ManageAuthenticationPage extends AdminBasePage )} - ); + ) } } diff --git a/public/pages/Administration/pages/ManageMembers.page.tsx b/public/pages/Administration/pages/ManageMembers.page.tsx index be3c837a7..48e87dc2a 100644 --- a/public/pages/Administration/pages/ManageMembers.page.tsx +++ b/public/pages/Administration/pages/ManageMembers.page.tsx @@ -1,40 +1,40 @@ -import "./ManageMembers.page.scss"; +import "./ManageMembers.page.scss" -import React from "react"; -import { Segment, List, Input, ListItem, Avatar, UserName, DropDown, DropDownItem } from "@fider/components/common"; -import { User, UserRole, UserStatus } from "@fider/models"; -import { AdminBasePage } from "../components/AdminBasePage"; -import { FaUsers, FaEllipsisH, FaTimes, FaSearch } from "react-icons/fa"; -import { actions, Fider } from "@fider/services"; +import React from "react" +import { Segment, List, Input, ListItem, Avatar, UserName, DropDown, DropDownItem } from "@fider/components/common" +import { User, UserRole, UserStatus } from "@fider/models" +import { AdminBasePage } from "../components/AdminBasePage" +import { FaUsers, FaEllipsisH, FaTimes, FaSearch } from "react-icons/fa" +import { actions, Fider } from "@fider/services" interface ManageMembersPageState { - query: string; - users: User[]; - visibleUsers: User[]; + query: string + users: User[] + visibleUsers: User[] } interface ManageMembersPageProps { - users: User[]; + users: User[] } interface UserListItemProps { - user: User; - onAction: (actionName: string, user: User) => Promise; + user: User + onAction: (actionName: string, user: User) => Promise } const UserListItem = (props: UserListItemProps) => { - const admin = props.user.role === UserRole.Administrator && administrator; - const collaborator = props.user.role === UserRole.Collaborator && collaborator; - const blocked = props.user.status === UserStatus.Blocked && blocked; - const isVisitor = props.user.role === UserRole.Visitor; + const admin = props.user.role === UserRole.Administrator && administrator + const collaborator = props.user.role === UserRole.Collaborator && collaborator + const blocked = props.user.status === UserStatus.Blocked && blocked + const isVisitor = props.user.role === UserRole.Visitor const renderEllipsis = () => { - return ; - }; + return + } const actionSelected = (item: DropDownItem) => { - props.onAction(item.value, props.user); - }; + props.onAction(item.value, props.user) + } return ( @@ -63,89 +63,89 @@ const UserListItem = (props: UserListItemProps) => { /> )} - ); -}; + ) +} export default class ManageMembersPage extends AdminBasePage { - public id = "p-admin-members"; - public name = "members"; - public icon = FaUsers; - public title = "Members"; - public subtitle = "Manage your site administrators and collaborators"; + public id = "p-admin-members" + public name = "members" + public icon = FaUsers + public title = "Members" + public subtitle = "Manage your site administrators and collaborators" constructor(props: ManageMembersPageProps) { - super(props); + super(props) - const users = this.props.users.sort(this.sortByStaff); + const users = this.props.users.sort(this.sortByStaff) this.state = { query: "", users, visibleUsers: users.slice(0, 10), - }; + } } private showMore = (event: React.MouseEvent | React.TouchEvent): void => { - event.preventDefault(); + event.preventDefault() this.setState({ visibleUsers: this.state.users.slice(0, this.state.visibleUsers.length + 10), - }); - }; + }) + } private clearSearch = () => { - this.handleSearchFilterChanged(""); - }; + this.handleSearchFilterChanged("") + } private handleSearchFilterChanged = (query: string) => { - const users = this.props.users.filter((x) => x.name.toLowerCase().indexOf(query.toLowerCase()) >= 0).sort(this.sortByStaff); - this.setState({ query, users, visibleUsers: users.slice(0, 10) }); - }; + const users = this.props.users.filter((x) => x.name.toLowerCase().indexOf(query.toLowerCase()) >= 0).sort(this.sortByStaff) + this.setState({ query, users, visibleUsers: users.slice(0, 10) }) + } private handleAction = async (actionName: string, user: User) => { const changeRole = async (role: UserRole) => { - const result = await actions.changeUserRole(user.id, role); + const result = await actions.changeUserRole(user.id, role) if (result.ok) { - user.role = role; + user.role = role } - this.handleSearchFilterChanged(this.state.query); - }; + this.handleSearchFilterChanged(this.state.query) + } const changeStatus = async (status: UserStatus) => { - const action = status === UserStatus.Blocked ? actions.blockUser : actions.unblockUser; - const result = await action(user.id); + const action = status === UserStatus.Blocked ? actions.blockUser : actions.unblockUser + const result = await action(user.id) if (result.ok) { - user.status = status; + user.status = status } - this.forceUpdate(); - }; + this.forceUpdate() + } if (actionName === "to-collaborator") { - await changeRole(UserRole.Collaborator); + await changeRole(UserRole.Collaborator) } else if (actionName === "to-visitor") { - await changeRole(UserRole.Visitor); + await changeRole(UserRole.Visitor) } else if (actionName === "to-administrator") { - await changeRole(UserRole.Administrator); + await changeRole(UserRole.Administrator) } else if (actionName === "block") { - await changeStatus(UserStatus.Blocked); + await changeStatus(UserStatus.Blocked) } else if (actionName === "unblock") { - await changeStatus(UserStatus.Active); + await changeStatus(UserStatus.Active) } - }; + } private sortByStaff = (left: User, right: User) => { if (right.role === left.role) { if (left.name < right.name) { - return -1; + return -1 } else if (left.name > right.name) { - return 1; + return 1 } - return 0; + return 0 } if (right.role !== UserRole.Visitor) { - return 1; + return 1 } - return -1; - }; + return -1 + } public content() { return ( @@ -174,7 +174,7 @@ export default class ManageMembersPage extends AdminBasePage - Showing {this.state.visibleUsers.length} of {this.state.users.length} users matching '{this.state.query}' + Showing {this.state.visibleUsers.length} of {this.state.users.length} users matching '{this.state.query}' )} {this.state.visibleUsers.length < this.state.users.length && ( @@ -195,6 +195,6 @@ export default class ManageMembersPage extends AdminBasePage - ); + ) } } diff --git a/public/pages/Administration/pages/ManageTags.page.tsx b/public/pages/Administration/pages/ManageTags.page.tsx index a4d93001f..fa86d9365 100644 --- a/public/pages/Administration/pages/ManageTags.page.tsx +++ b/public/pages/Administration/pages/ManageTags.page.tsx @@ -1,48 +1,48 @@ -import "./ManageTags.page.scss"; +import "./ManageTags.page.scss" -import React from "react"; -import { Button, Segment, List, ListItem, Heading } from "@fider/components"; +import React from "react" +import { Button, Segment, List, ListItem, Heading } from "@fider/components" -import { Tag } from "@fider/models"; -import { actions, Failure, Fider } from "@fider/services"; -import { FaTags } from "react-icons/fa"; -import { AdminBasePage } from "../components/AdminBasePage"; -import { TagFormState, TagForm } from "../components/TagForm"; -import { TagListItem } from "../components/TagListItem"; +import { Tag } from "@fider/models" +import { actions, Failure, Fider } from "@fider/services" +import { FaTags } from "react-icons/fa" +import { AdminBasePage } from "../components/AdminBasePage" +import { TagFormState, TagForm } from "../components/TagForm" +import { TagListItem } from "../components/TagListItem" interface ManageTagsPageProps { - tags: Tag[]; + tags: Tag[] } interface ManageTagsPageState { - isAdding: boolean; - allTags: Tag[]; - deleting?: number; - editing?: number; + isAdding: boolean + allTags: Tag[] + deleting?: number + editing?: number } const tagSorter = (t1: Tag, t2: Tag) => { if (t1.name < t2.name) { - return -1; + return -1 } else if (t1.name > t2.name) { - return 1; + return 1 } - return 0; -}; + return 0 +} export default class ManageTagsPage extends AdminBasePage { - public id = "p-admin-tags"; - public name = "tags"; - public icon = FaTags; - public title = "Tags"; - public subtitle = "Manage your site tags"; + public id = "p-admin-tags" + public name = "tags" + public icon = FaTags + public title = "Tags" + public subtitle = "Manage your site tags" constructor(props: ManageTagsPageProps) { - super(props); + super(props) this.state = { isAdding: false, allTags: this.props.tags, - }; + } } private addNew = async () => { @@ -50,47 +50,47 @@ export default class ManageTagsPage extends AdminBasePage { - this.setState({ isAdding: false }); - }; + this.setState({ isAdding: false }) + } private saveNewTag = async (data: TagFormState): Promise => { - const result = await actions.createTag(data.name, data.color, data.isPublic); + const result = await actions.createTag(data.name, data.color, data.isPublic) if (result.ok) { this.setState({ isAdding: false, allTags: this.state.allTags.concat(result.data).sort(tagSorter), - }); + }) } else { - return result.error; + return result.error } - }; + } private handleTagDeleted = (tag: Tag) => { - const idx = this.state.allTags.indexOf(tag); + const idx = this.state.allTags.indexOf(tag) this.setState({ allTags: this.state.allTags.splice(idx, 1) && this.state.allTags, - }); - }; + }) + } - private handleTagEdited = (tag: Tag) => { + private handleTagEdited = () => { this.setState({ allTags: this.state.allTags.sort(tagSorter), - }); - }; + }) + } private getTagList(filter: (tag: Tag) => boolean) { return this.state.allTags.filter(filter).map((t) => { - return ; - }); + return + }) } public content() { - const publicTaglist = this.getTagList((t) => t.isPublic); - const privateTagList = this.getTagList((t) => !t.isPublic); + const publicTaglist = this.getTagList((t) => t.isPublic) + const privateTagList = this.getTagList((t) => !t.isPublic) const form = Fider.session.user.isAdministrator && @@ -102,7 +102,7 @@ export default class ManageTagsPage extends AdminBasePage Add new - )); + )) return ( <> @@ -125,6 +125,6 @@ export default class ManageTagsPage extends AdminBasePage {form} - ); + ) } } diff --git a/public/pages/Administration/pages/PrivacySettings.page.tsx b/public/pages/Administration/pages/PrivacySettings.page.tsx index 7e21e795d..0fba8e72e 100644 --- a/public/pages/Administration/pages/PrivacySettings.page.tsx +++ b/public/pages/Administration/pages/PrivacySettings.page.tsx @@ -1,43 +1,43 @@ -import "./PrivacySettings.page.scss"; +import "./PrivacySettings.page.scss" -import React from "react"; -import { Toggle, Form } from "@fider/components/common"; -import { actions, notify, Fider } from "@fider/services"; -import { AdminBasePage } from "@fider/pages/Administration/components/AdminBasePage"; -import { FaKey } from "react-icons/fa"; +import React from "react" +import { Toggle, Form } from "@fider/components/common" +import { actions, notify, Fider } from "@fider/services" +import { AdminBasePage } from "@fider/pages/Administration/components/AdminBasePage" +import { FaKey } from "react-icons/fa" interface PrivacySettingsPageState { - isPrivate: boolean; + isPrivate: boolean } -export default class PrivacySettingsPage extends AdminBasePage<{}, PrivacySettingsPageState> { - public id = "p-admin-privacy"; - public name = "privacy"; - public icon = FaKey; - public title = "Privacy"; - public subtitle = "Manage your site privacy"; +export default class PrivacySettingsPage extends AdminBasePage { + public id = "p-admin-privacy" + public name = "privacy" + public icon = FaKey + public title = "Privacy" + public subtitle = "Manage your site privacy" - constructor(props: {}) { - super(props); + constructor(props: any) { + super(props) this.state = { isPrivate: Fider.session.tenant.isPrivate, - }; + } } private toggle = async (active: boolean) => { this.setState( - (state) => ({ + () => ({ isPrivate: active, }), async () => { - const response = await actions.updateTenantPrivacy(this.state.isPrivate); + const response = await actions.updateTenantPrivacy(this.state.isPrivate) if (response.ok) { - notify.success("Your privacy settings have been saved."); + notify.success("Your privacy settings have been saved.") } } - ); - }; + ) + } public content() { return ( @@ -46,11 +46,11 @@ export default class PrivacySettingsPage extends AdminBasePage<{}, PrivacySettin

    - A private site prevents unauthenticated users from viewing or interacting with its content.
    If enabled, only already registered and invited users will be able to sign in to this - site. + A private site prevents unauthenticated users from viewing or interacting with its content.
    If enabled, only already registered and invited + users will be able to sign in to this site.

    - ); + ) } } diff --git a/public/pages/CompleteSignInProfile/CompleteSignInProfile.page.tsx b/public/pages/CompleteSignInProfile/CompleteSignInProfile.page.tsx index b6ca53a45..fc838493e 100644 --- a/public/pages/CompleteSignInProfile/CompleteSignInProfile.page.tsx +++ b/public/pages/CompleteSignInProfile/CompleteSignInProfile.page.tsx @@ -1,42 +1,42 @@ -import React from "react"; +import React from "react" -import HomePage, { HomePageProps } from "../Home/Home.page"; -import SignInPage from "../SignIn/SignIn.page"; -import { Modal, Button, Form, Input, LegalFooter } from "@fider/components"; -import { actions, Failure, querystring, Fider } from "@fider/services"; +import HomePage, { HomePageProps } from "../Home/Home.page" +import SignInPage from "../SignIn/SignIn.page" +import { Modal, Button, Form, Input, LegalFooter } from "@fider/components" +import { actions, Failure, querystring, Fider } from "@fider/services" interface CompleteSignInProfilePageState { - name: string; - error?: Failure; + name: string + error?: Failure } export default class CompleteSignInProfilePage extends React.Component { - private key: string; + private key: string constructor(props: HomePageProps) { - super(props); - this.key = querystring.get("k"); + super(props) + this.key = querystring.get("k") this.state = { name: "", - }; + } } private submit = async () => { - const result = await actions.completeProfile(this.key, this.state.name); + const result = await actions.completeProfile(this.key, this.state.name) if (result.ok) { - location.href = "/"; + location.href = "/" } else if (result.error) { - this.setState({ error: result.error }); + this.setState({ error: result.error }) } - }; + } private setName = (name: string) => { - this.setState({ name }); - }; + this.setState({ name }) + } private noop = () => { // do nothing - }; + } public render() { return ( @@ -63,6 +63,6 @@ export default class CompleteSignInProfilePage extends React.Component {Fider.session.tenant.isPrivate ? React.createElement(SignInPage, this.props) : React.createElement(HomePage, this.props)} - ); + ) } } diff --git a/public/pages/CompleteSignInProfile/index.ts b/public/pages/CompleteSignInProfile/index.ts index c202aa12a..140ec0c8a 100644 --- a/public/pages/CompleteSignInProfile/index.ts +++ b/public/pages/CompleteSignInProfile/index.ts @@ -1 +1 @@ -export * from "./CompleteSignInProfile.page"; +export * from "./CompleteSignInProfile.page" diff --git a/public/pages/Error/Error.page.spec.tsx b/public/pages/Error/Error.page.spec.tsx index e00067387..a6e9fec84 100644 --- a/public/pages/Error/Error.page.spec.tsx +++ b/public/pages/Error/Error.page.spec.tsx @@ -1,24 +1,24 @@ -import React from "react"; -import { shallow } from "enzyme"; -import { ErrorPage } from "./Error.page"; +import React from "react" +import { shallow } from "enzyme" +import { ErrorPage } from "./Error.page" describe("", () => { - const createFakeErrorInfo = () => ({ componentStack: "" } as React.ErrorInfo); + const createFakeErrorInfo = () => ({ componentStack: "" } as React.ErrorInfo) test("it should show the error when showError returns true", () => { - const error = new Error("Hello"); - const errorInfo = createFakeErrorInfo(); + const error = new Error("Hello") + const errorInfo = createFakeErrorInfo() - const wrapper = shallow(); - expect(wrapper.find("pre")).toHaveLength(1); - }); + const wrapper = shallow() + expect(wrapper.find("pre")).toHaveLength(1) + }) test("it should not show the error when showError returns false", () => { - const error = new Error("Hello"); - const errorInfo = createFakeErrorInfo(); + const error = new Error("Hello") + const errorInfo = createFakeErrorInfo() - const wrapper = shallow(); + const wrapper = shallow() - expect(wrapper.find("pre")).toHaveLength(0); - }); -}); + expect(wrapper.find("pre")).toHaveLength(0) + }) +}) diff --git a/public/pages/Error/Error.page.tsx b/public/pages/Error/Error.page.tsx index 3858ef062..0720e94c0 100644 --- a/public/pages/Error/Error.page.tsx +++ b/public/pages/Error/Error.page.tsx @@ -1,23 +1,23 @@ -import "./Error.page.scss"; +import "./Error.page.scss" -import React from "react"; -import { TenantLogo } from "@fider/components"; -import { useFider } from "@fider/hooks"; +import React from "react" +import { TenantLogo } from "@fider/components" +import { useFider } from "@fider/hooks" interface ErrorPageProps { - error: Error; - errorInfo: React.ErrorInfo; - showDetails?: boolean; + error: Error + errorInfo: React.ErrorInfo + showDetails?: boolean } export const ErrorPage = (props: ErrorPageProps) => { - const fider = useFider(); + const fider = useFider() return (

    Shoot! Well, this is unexpected…

    -

    An error has occurred and we're working to fix the problem!

    +

    An error has occurred and we're working to fix the problem!

    {fider.settings && ( Take me back to {fider.settings.baseURL} home page. @@ -30,5 +30,5 @@ export const ErrorPage = (props: ErrorPageProps) => { )}
    - ); -}; + ) +} diff --git a/public/pages/Error/index.ts b/public/pages/Error/index.ts index 3b465175c..a034829a2 100644 --- a/public/pages/Error/index.ts +++ b/public/pages/Error/index.ts @@ -1 +1 @@ -export * from "./Error.page"; +export * from "./Error.page" diff --git a/public/pages/Home/Home.page.tsx b/public/pages/Home/Home.page.tsx index 383aacc27..adb0ca1a7 100644 --- a/public/pages/Home/Home.page.tsx +++ b/public/pages/Home/Home.page.tsx @@ -1,60 +1,61 @@ -import "./Home.page.scss"; +import "./Home.page.scss" -import React, { useState } from "react"; -import { Post, Tag, PostStatus } from "@fider/models"; -import { MultiLineText, Hint } from "@fider/components"; -import { SimilarPosts } from "./components/SimilarPosts"; -import { FaRegLightbulb } from "react-icons/fa"; -import { PostInput } from "./components/PostInput"; -import { PostsContainer } from "./components/PostsContainer"; -import { useFider } from "@fider/hooks"; +import React, { useState } from "react" +import { Post, Tag, PostStatus } from "@fider/models" +import { MultiLineText, Hint } from "@fider/components" +import { SimilarPosts } from "./components/SimilarPosts" +import { FaRegLightbulb } from "react-icons/fa" +import { PostInput } from "./components/PostInput" +import { PostsContainer } from "./components/PostsContainer" +import { useFider } from "@fider/hooks" export interface HomePageProps { - posts: Post[]; - tags: Tag[]; - countPerStatus: { [key: string]: number }; + posts: Post[] + tags: Tag[] + countPerStatus: { [key: string]: number } } export interface HomePageState { - title: string; + title: string } const Lonely = () => { - const fider = useFider(); + const fider = useFider() return (
    - It's recommended that you post at least 3 suggestions here before sharing this site. The initial content is key to start the interactions with your audience. + It's recommended that you post at least 3 suggestions here before sharing this site. The initial content is key to start the + interactions with your audience.

    -

    It's lonely out here. Start by sharing a suggestion!

    +

    It's lonely out here. Start by sharing a suggestion!

    - ); -}; + ) +} const defaultWelcomeMessage = `We'd love to hear what you're thinking about. -What can we do better? This is the place for you to vote, discuss and share ideas.`; +What can we do better? This is the place for you to vote, discuss and share ideas.` const HomePage = (props: HomePageProps) => { - const fider = useFider(); - const [title, setTitle] = useState(""); + const fider = useFider() + const [title, setTitle] = useState("") const isLonely = () => { - const len = Object.keys(props.countPerStatus).length; + const len = Object.keys(props.countPerStatus).length if (len === 0) { - return true; + return true } if (len === 1 && PostStatus.Deleted.value in props.countPerStatus) { - return true; + return true } - return false; - }; + return false + } return (
    @@ -64,11 +65,17 @@ const HomePage = (props: HomePageProps) => {
    - {isLonely() ? : title ? : } + {isLonely() ? ( + + ) : title ? ( + + ) : ( + + )}
    - ); -}; + ) +} -export default HomePage; +export default HomePage diff --git a/public/pages/Home/components/ListPosts.tsx b/public/pages/Home/components/ListPosts.tsx index ec6451262..1129ae638 100644 --- a/public/pages/Home/components/ListPosts.tsx +++ b/public/pages/Home/components/ListPosts.tsx @@ -1,14 +1,14 @@ -import "./ListPosts.scss"; +import "./ListPosts.scss" -import React from "react"; -import { Post, Tag, CurrentUser } from "@fider/models"; -import { ShowTag, ShowPostResponse, VoteCounter, MultiLineText, ListItem, List } from "@fider/components"; -import { FaRegComments } from "react-icons/fa"; +import React from "react" +import { Post, Tag, CurrentUser } from "@fider/models" +import { ShowTag, ShowPostResponse, VoteCounter, MultiLineText, ListItem, List } from "@fider/components" +import { FaRegComments } from "react-icons/fa" interface ListPostsProps { - posts?: Post[]; - tags: Tag[]; - emptyText: string; + posts?: Post[] + tags: Tag[] + emptyText: string } const ListPostItem = (props: { post: Post; user?: CurrentUser; tags: Tag[] }) => { @@ -31,16 +31,16 @@ const ListPostItem = (props: { post: Post; user?: CurrentUser; tags: Tag[] }) => ))} - ); -}; + ) +} export const ListPosts = (props: ListPostsProps) => { if (!props.posts) { - return null; + return null } if (props.posts.length === 0) { - return

    {props.emptyText}

    ; + return

    {props.emptyText}

    } return ( @@ -49,5 +49,5 @@ export const ListPosts = (props: ListPostsProps) => { post.tags.indexOf(tag.slug) >= 0)} /> ))} - ); -}; + ) +} diff --git a/public/pages/Home/components/PostFilter.tsx b/public/pages/Home/components/PostFilter.tsx index 8c4e20b09..658afb585 100644 --- a/public/pages/Home/components/PostFilter.tsx +++ b/public/pages/Home/components/PostFilter.tsx @@ -1,32 +1,32 @@ -import "./PostFilter.scss"; +import "./PostFilter.scss" -import React from "react"; -import { PostStatus } from "@fider/models"; -import { DropDown, DropDownItem } from "@fider/components"; -import { useFider } from "@fider/hooks"; +import React from "react" +import { PostStatus } from "@fider/models" +import { DropDown, DropDownItem } from "@fider/components" +import { useFider } from "@fider/hooks" interface PostFilterProps { - activeView: string; - countPerStatus: { [key: string]: number }; - viewChanged: (name: string) => void; + activeView: string + countPerStatus: { [key: string]: number } + viewChanged: (name: string) => void } export const PostFilter = (props: PostFilterProps) => { - const fider = useFider(); + const fider = useFider() const handleChangeView = (item: DropDownItem) => { - props.viewChanged(item.value as string); - }; + props.viewChanged(item.value as string) + } const options: DropDownItem[] = [ { value: "trending", label: "Trending" }, { value: "recent", label: "Recent" }, { value: "most-wanted", label: "Most Wanted" }, { value: "most-discussed", label: "Most Discussed" }, - ]; + ] if (fider.session.isAuthenticated) { - options.push({ value: "my-votes", label: "My Votes" }); + options.push({ value: "my-votes", label: "My Votes" }) } PostStatus.All.filter((s) => s.filterable && props.countPerStatus[s.value]).forEach((s) => { @@ -38,16 +38,24 @@ export const PostFilter = (props: PostFilterProps) => { {s.title} {props.countPerStatus[s.value]} ), - }); - }); + }) + }) - const viewExists = options.filter((x) => x.value === props.activeView).length > 0; - const activeView = viewExists ? props.activeView : "trending"; + const viewExists = options.filter((x) => x.value === props.activeView).length > 0 + const activeView = viewExists ? props.activeView : "trending" return (
    View - +
    - ); -}; + ) +} diff --git a/public/pages/Home/components/PostInput.tsx b/public/pages/Home/components/PostInput.tsx index a2e4cec2a..7f830ff65 100644 --- a/public/pages/Home/components/PostInput.tsx +++ b/public/pages/Home/components/PostInput.tsx @@ -1,72 +1,72 @@ -import React, { useState, useEffect, useRef } from "react"; -import { Button, ButtonClickEvent, Input, Form, TextArea, MultiImageUploader } from "@fider/components"; -import { SignInModal } from "@fider/components"; -import { cache, actions, Failure } from "@fider/services"; -import { ImageUpload } from "@fider/models"; -import { useFider } from "@fider/hooks"; +import React, { useState, useEffect, useRef } from "react" +import { Button, ButtonClickEvent, Input, Form, TextArea, MultiImageUploader } from "@fider/components" +import { SignInModal } from "@fider/components" +import { cache, actions, Failure } from "@fider/services" +import { ImageUpload } from "@fider/models" +import { useFider } from "@fider/hooks" interface PostInputProps { - placeholder: string; - onTitleChanged: (title: string) => void; + placeholder: string + onTitleChanged: (title: string) => void } -const CACHE_TITLE_KEY = "PostInput-Title"; -const CACHE_DESCRIPTION_KEY = "PostInput-Description"; +const CACHE_TITLE_KEY = "PostInput-Title" +const CACHE_DESCRIPTION_KEY = "PostInput-Description" export const PostInput = (props: PostInputProps) => { const getCachedValue = (key: string): string => { if (fider.session.isAuthenticated) { - return cache.session.get(key) || ""; + return cache.session.get(key) || "" } - return ""; - }; + return "" + } - const fider = useFider(); - const titleRef = useRef(); - const [title, setTitle] = useState(getCachedValue(CACHE_TITLE_KEY)); - const [description, setDescription] = useState(getCachedValue(CACHE_DESCRIPTION_KEY)); - const [isSignInModalOpen, setIsSignInModalOpen] = useState(false); - const [attachments, setAttachments] = useState([]); - const [error, setError] = useState(undefined); + const fider = useFider() + const titleRef = useRef() + const [title, setTitle] = useState(getCachedValue(CACHE_TITLE_KEY)) + const [description, setDescription] = useState(getCachedValue(CACHE_DESCRIPTION_KEY)) + const [isSignInModalOpen, setIsSignInModalOpen] = useState(false) + const [attachments, setAttachments] = useState([]) + const [error, setError] = useState(undefined) useEffect(() => { - props.onTitleChanged(title); - }, [title]); + props.onTitleChanged(title) + }, [title]) const handleTitleFocus = () => { if (!fider.session.isAuthenticated && titleRef.current) { - titleRef.current.blur(); - setIsSignInModalOpen(true); + titleRef.current.blur() + setIsSignInModalOpen(true) } - }; + } const handleTitleChange = (value: string) => { - cache.session.set(CACHE_TITLE_KEY, value); - setTitle(value); - props.onTitleChanged(value); - }; + cache.session.set(CACHE_TITLE_KEY, value) + setTitle(value) + props.onTitleChanged(value) + } - const hideModal = () => setIsSignInModalOpen(false); - const clearError = () => setError(undefined); + const hideModal = () => setIsSignInModalOpen(false) + const clearError = () => setError(undefined) const handleDescriptionChange = (value: string) => { - cache.session.set(CACHE_DESCRIPTION_KEY, value); - setDescription(value); - }; + cache.session.set(CACHE_DESCRIPTION_KEY, value) + setDescription(value) + } const submit = async (event: ButtonClickEvent) => { if (title) { - const result = await actions.createPost(title, description, attachments); + const result = await actions.createPost(title, description, attachments) if (result.ok) { - clearError(); - cache.session.remove(CACHE_TITLE_KEY, CACHE_DESCRIPTION_KEY); - location.href = `/posts/${result.data.number}/${result.data.slug}`; - event.preventEnable(); + clearError() + cache.session.remove(CACHE_TITLE_KEY, CACHE_DESCRIPTION_KEY) + location.href = `/posts/${result.data.number}/${result.data.slug}` + event.preventEnable() } else if (result.error) { - setError(result.error); + setError(result.error) } } - }; + } const details = () => ( <> @@ -76,7 +76,7 @@ export const PostInput = (props: PostInputProps) => { Submit - ); + ) return ( <> @@ -95,5 +95,5 @@ export const PostInput = (props: PostInputProps) => { {title && details()} - ); -}; + ) +} diff --git a/public/pages/Home/components/PostsContainer.tsx b/public/pages/Home/components/PostsContainer.tsx index b15f34832..cf349a223 100644 --- a/public/pages/Home/components/PostsContainer.tsx +++ b/public/pages/Home/components/PostsContainer.tsx @@ -1,32 +1,32 @@ -import React from "react"; +import React from "react" -import { Post, Tag, CurrentUser } from "@fider/models"; -import { Loader, Field, Input } from "@fider/components"; -import { actions, navigator, querystring } from "@fider/services"; -import { FaTimes, FaSearch } from "react-icons/fa"; -import { PostFilter } from "./PostFilter"; -import { ListPosts } from "./ListPosts"; -import { TagsFilter } from "./TagsFilter"; +import { Post, Tag, CurrentUser } from "@fider/models" +import { Loader, Field, Input } from "@fider/components" +import { actions, navigator, querystring } from "@fider/services" +import { FaTimes, FaSearch } from "react-icons/fa" +import { PostFilter } from "./PostFilter" +import { ListPosts } from "./ListPosts" +import { TagsFilter } from "./TagsFilter" interface PostsContainerProps { - user?: CurrentUser; - posts: Post[]; - tags: Tag[]; - countPerStatus: { [key: string]: number }; + user?: CurrentUser + posts: Post[] + tags: Tag[] + countPerStatus: { [key: string]: number } } interface PostsContainerState { - loading: boolean; - posts?: Post[]; - view: string; - tags: string[]; - query: string; - limit?: number; + loading: boolean + posts?: Post[] + view: string + tags: string[] + query: string + limit?: number } export class PostsContainer extends React.Component { constructor(props: PostsContainerProps) { - super(props); + super(props) this.state = { posts: this.props.posts, @@ -35,12 +35,12 @@ export class PostsContainer extends React.Component(obj: Pick, reset: boolean): void { this.setState(obj, () => { - const query = this.state.query.trim().toLowerCase(); + const query = this.state.query.trim().toLowerCase() navigator.replaceState( querystring.stringify({ tags: this.state.tags, @@ -48,54 +48,54 @@ export class PostsContainer extends React.Component { actions.searchPosts({ query, view, limit, tags }).then((response) => { if (response.ok && this.state.loading) { - this.setState({ loading: false, posts: response.data }); + this.setState({ loading: false, posts: response.data }) } - }); - }, 500); + }) + }, 500) } private handleViewChanged = (view: string) => { - this.changeFilterCriteria({ view }, true); - }; + this.changeFilterCriteria({ view }, true) + } private handleTagsFilterChanged = (tags: string[]) => { - this.changeFilterCriteria({ tags }, true); - }; + this.changeFilterCriteria({ tags }, true) + } private handleSearchFilterChanged = (query: string) => { - this.changeFilterCriteria({ query }, true); - }; + this.changeFilterCriteria({ query }, true) + } private clearSearch = () => { - this.changeFilterCriteria({ query: "" }, true); - }; + this.changeFilterCriteria({ query: "" }, true) + } private showMore = (event: React.MouseEvent | React.TouchEvent): void => { - event.preventDefault(); - this.changeFilterCriteria({ limit: (this.state.limit || 30) + 10 }, false); - }; + event.preventDefault() + this.changeFilterCriteria({ limit: (this.state.limit || 30) + 10 }, false) + } private getShowMoreLink = (): string | undefined => { if (this.state.posts && this.state.posts.length >= (this.state.limit || 30)) { - return querystring.set("limit", (this.state.limit || 30) + 10); + return querystring.set("limit", (this.state.limit || 30) + 10) } - }; + } public render() { - const showMoreLink = this.getShowMoreLink(); + const showMoreLink = this.getShowMoreLink() return ( <>
    @@ -126,6 +126,6 @@ export class PostsContainer extends React.Component )} - ); + ) } } diff --git a/public/pages/Home/components/SimilarPosts.tsx b/public/pages/Home/components/SimilarPosts.tsx index e6e0d33cb..13c49c681 100644 --- a/public/pages/Home/components/SimilarPosts.tsx +++ b/public/pages/Home/components/SimilarPosts.tsx @@ -1,30 +1,30 @@ -import React from "react"; -import { Post, Tag, CurrentUser } from "@fider/models"; -import { Heading, Loader } from "@fider/components"; -import { ListPosts } from "./ListPosts"; -import { actions } from "@fider/services"; -import { FaRegLightbulb } from "react-icons/fa"; +import React from "react" +import { Post, Tag, CurrentUser } from "@fider/models" +import { Heading, Loader } from "@fider/components" +import { ListPosts } from "./ListPosts" +import { actions } from "@fider/services" +import { FaRegLightbulb } from "react-icons/fa" interface SimilarPostsProps { - title: string; - tags: Tag[]; - user?: CurrentUser; + title: string + tags: Tag[] + user?: CurrentUser } interface SimilarPostsState { - title: string; - posts: Post[]; - loading: boolean; + title: string + posts: Post[] + loading: boolean } export class SimilarPosts extends React.Component { constructor(props: SimilarPostsProps) { - super(props); + super(props) this.state = { title: props.title, loading: !!props.title, posts: [], - }; + } } public static getDerivedStateFromProps(nextProps: SimilarPostsProps, prevState: SimilarPostsState) { @@ -32,36 +32,40 @@ export class SimilarPosts extends React.Component { if (this.state.loading) { actions.searchPosts({ query: this.state.title }).then((x) => { if (x.ok) { - this.setState({ loading: false, posts: x.data }); + this.setState({ loading: false, posts: x.data }) } - }); + }) } - }; + } public render() { return ( <> - {this.state.loading ? : } + {this.state.loading ? ( + + ) : ( + + )} - ); + ) } } diff --git a/public/pages/Home/components/TagsFilter.tsx b/public/pages/Home/components/TagsFilter.tsx index a55c3209f..e6f406cb2 100644 --- a/public/pages/Home/components/TagsFilter.tsx +++ b/public/pages/Home/components/TagsFilter.tsx @@ -1,49 +1,49 @@ -import "./TagsFilter.scss"; +import "./TagsFilter.scss" -import React from "react"; -import { Tag } from "@fider/models"; -import { ShowTag } from "@fider/components/ShowTag"; -import { DropDown, DropDownItem } from "@fider/components"; -import { FaCheck } from "react-icons/fa"; +import React from "react" +import { Tag } from "@fider/models" +import { ShowTag } from "@fider/components/ShowTag" +import { DropDown, DropDownItem } from "@fider/components" +import { FaCheck } from "react-icons/fa" interface TagsFilterProps { - tags: Tag[]; - defaultSelection: string[]; - selectionChanged: (selected: string[]) => void; + tags: Tag[] + defaultSelection: string[] + selectionChanged: (selected: string[]) => void } interface TagsFilterState { - selected: string[]; + selected: string[] } export class TagsFilter extends React.Component { constructor(props: TagsFilterProps) { - super(props); + super(props) this.state = { selected: props.defaultSelection, - }; + } } private onChange = (item: DropDownItem) => { - let selected = []; - const idx = this.state.selected.indexOf(item.value as string); + let selected = [] + const idx = this.state.selected.indexOf(item.value as string) if (idx >= 0) { - selected = this.state.selected.splice(idx, 1) && this.state.selected; + selected = this.state.selected.splice(idx, 1) && this.state.selected } else { - selected = this.state.selected.concat(item.value as string); + selected = this.state.selected.concat(item.value as string) } - this.setState({ selected }); - this.props.selectionChanged(selected); - }; + this.setState({ selected }) + this.props.selectionChanged(selected) + } private renderText = () => { - const text = this.state.selected.length === 0 ? "any tag" : this.state.selected.length === 1 ? "1 tag" : `${this.state.selected.length} tags`; - return <>{text}; - }; + const text = this.state.selected.length === 0 ? "any tag" : this.state.selected.length === 1 ? "1 tag" : `${this.state.selected.length} tags` + return <>{text} + } public render() { if (this.props.tags.length === 0) { - return null; + return null } const items = this.props.tags.map((t) => { @@ -57,14 +57,22 @@ export class TagsFilter extends React.Component ), - }; - }); + } + }) return (
    with - +
    - ); + ) } } diff --git a/public/pages/Home/index.ts b/public/pages/Home/index.ts index 9372d4b5f..3f31d61c5 100644 --- a/public/pages/Home/index.ts +++ b/public/pages/Home/index.ts @@ -1 +1 @@ -export * from "./Home.page"; +export * from "./Home.page" diff --git a/public/pages/MyNotifications/MyNotifications.page.tsx b/public/pages/MyNotifications/MyNotifications.page.tsx index 6b157e7d6..e5965ddeb 100644 --- a/public/pages/MyNotifications/MyNotifications.page.tsx +++ b/public/pages/MyNotifications/MyNotifications.page.tsx @@ -1,37 +1,37 @@ -import "./MyNotifications.page.scss"; +import "./MyNotifications.page.scss" -import React from "react"; +import React from "react" -import { Notification } from "@fider/models"; -import { MultiLineText, Moment, Heading, List, ListItem } from "@fider/components"; -import { actions } from "@fider/services"; -import { FaBell } from "react-icons/fa"; +import { Notification } from "@fider/models" +import { MultiLineText, Moment, Heading, List, ListItem } from "@fider/components" +import { actions } from "@fider/services" +import { FaBell } from "react-icons/fa" interface MyNotificationsPageProps { - notifications: Notification[]; + notifications: Notification[] } interface MyNotificationsPageState { - unread: Notification[]; - recent: Notification[]; + unread: Notification[] + recent: Notification[] } export default class MyNotificationsPage extends React.Component { constructor(props: MyNotificationsPageProps) { - super(props); + super(props) const [unread, recent] = (this.props.notifications || []).reduce( (result, item) => { - result[item.read ? 1 : 0].push(item); - return result; + result[item.read ? 1 : 0].push(item) + return result }, [[] as Notification[], [] as Notification[]] - ); + ) this.state = { unread, recent, - }; + } } private items(notifications: Notification[]): JSX.Element[] { @@ -45,16 +45,16 @@ export default class MyNotificationsPage extends React.Component - ); - }); + ) + }) } private markAllAsRead = async () => { - const response = await actions.markAllAsRead(); + const response = await actions.markAllAsRead() if (response.ok) { - location.reload(); + location.reload() } - }; + } public render() { return ( @@ -82,6 +82,6 @@ export default class MyNotificationsPage extends React.Component )}
    - ); + ) } } diff --git a/public/pages/MyNotifications/index.ts b/public/pages/MyNotifications/index.ts index 9b3c5df4c..1c5b310c2 100644 --- a/public/pages/MyNotifications/index.ts +++ b/public/pages/MyNotifications/index.ts @@ -1 +1 @@ -export * from "./MyNotifications.page"; +export * from "./MyNotifications.page" diff --git a/public/pages/MySettings/MySettings.page.tsx b/public/pages/MySettings/MySettings.page.tsx index 73ff91d03..5367b08a2 100644 --- a/public/pages/MySettings/MySettings.page.tsx +++ b/public/pages/MySettings/MySettings.page.tsx @@ -1,34 +1,34 @@ -import "./MySettings.page.scss"; +import "./MySettings.page.scss" -import React from "react"; +import React from "react" -import { Modal, Form, Button, Heading, Input, Select, SelectOption, ImageUploader } from "@fider/components"; +import { Modal, Form, Button, Heading, Input, Select, SelectOption, ImageUploader } from "@fider/components" -import { UserSettings, UserAvatarType, ImageUpload } from "@fider/models"; -import { Failure, actions, Fider } from "@fider/services"; -import { FaRegAddressCard } from "react-icons/fa"; -import { NotificationSettings } from "./components/NotificationSettings"; -import { APIKeyForm } from "./components/APIKeyForm"; -import { DangerZone } from "./components/DangerZone"; +import { UserSettings, UserAvatarType, ImageUpload } from "@fider/models" +import { Failure, actions, Fider } from "@fider/services" +import { FaRegAddressCard } from "react-icons/fa" +import { NotificationSettings } from "./components/NotificationSettings" +import { APIKeyForm } from "./components/APIKeyForm" +import { DangerZone } from "./components/DangerZone" interface MySettingsPageState { - showModal: boolean; - name: string; - newEmail: string; - avatar?: ImageUpload; - avatarType: UserAvatarType; - changingEmail: boolean; - error?: Failure; - userSettings: UserSettings; + showModal: boolean + name: string + newEmail: string + avatar?: ImageUpload + avatarType: UserAvatarType + changingEmail: boolean + error?: Failure + userSettings: UserSettings } interface MySettingsPageProps { - userSettings: UserSettings; + userSettings: UserSettings } export default class MySettingsPage extends React.Component { constructor(props: MySettingsPageProps) { - super(props); + super(props) this.state = { showModal: false, changingEmail: false, @@ -36,7 +36,7 @@ export default class MySettingsPage extends React.Component { @@ -45,71 +45,71 @@ export default class MySettingsPage extends React.Component { - const result = await actions.changeUserEmail(this.state.newEmail); + const result = await actions.changeUserEmail(this.state.newEmail) if (result.ok) { this.setState({ error: undefined, changingEmail: false, showModal: true, - }); + }) } else if (result.error) { - this.setState({ error: result.error }); + this.setState({ error: result.error }) } - }; + } private startChangeEmail = () => { - this.setState({ changingEmail: true }); - }; + this.setState({ changingEmail: true }) + } private cancelChangeEmail = async () => { this.setState({ changingEmail: false, newEmail: "", error: undefined, - }); - }; + }) + } private avatarTypeChanged = (opt?: SelectOption) => { if (opt) { - this.setState({ avatarType: opt.value as UserAvatarType }); + this.setState({ avatarType: opt.value as UserAvatarType }) } - }; + } private setName = (name: string) => { - this.setState({ name }); - }; + this.setState({ name }) + } private setNotificationSettings = (userSettings: UserSettings) => { - this.setState({ userSettings }); - }; + this.setState({ userSettings }) + } private closeModal = () => { - this.setState({ showModal: false }); - }; + this.setState({ showModal: false }) + } private setNewEmail = (newEmail: string) => { - this.setState({ newEmail }); - }; + this.setState({ newEmail }) + } private setAvatar = (avatar: ImageUpload): void => { - this.setState({ avatar }); - }; + this.setState({ avatar }) + } public render() { const changeEmail = ( change - ); + ) return (
    @@ -143,7 +143,11 @@ export default class MySettingsPage extends React.Component -

    {Fider.session.user.email || this.state.changingEmail ? "Your email is private and will never be publicly displayed." : "Your account doesn't have an email."}

    +

    + {Fider.session.user.email || this.state.changingEmail + ? "Your email is private and will never be publicly displayed." + : "Your account doesn't have an email."} +

    {this.state.changingEmail && ( <>
    - ); + ) } } diff --git a/public/pages/MySettings/components/APIKeyForm.tsx b/public/pages/MySettings/components/APIKeyForm.tsx index 007263440..e05eed94c 100644 --- a/public/pages/MySettings/components/APIKeyForm.tsx +++ b/public/pages/MySettings/components/APIKeyForm.tsx @@ -1,23 +1,23 @@ -import React from "react"; -import { Button } from "@fider/components"; -import { actions } from "@fider/services"; +import React from "react" +import { Button } from "@fider/components" +import { actions } from "@fider/services" interface APIKeyFormState { - apiKey?: string; + apiKey?: string } -export class APIKeyForm extends React.Component<{}, APIKeyFormState> { - constructor(props: {}) { - super(props); - this.state = {}; +export class APIKeyForm extends React.Component { + constructor(props: any) { + super(props) + this.state = {} } private regenerate = async () => { - const result = await actions.regenerateAPIKey(); + const result = await actions.regenerateAPIKey() if (result.ok) { - this.setState({ apiKey: result.data.apiKey }); + this.setState({ apiKey: result.data.apiKey }) } - }; + } private showAPIKey() { return ( @@ -27,17 +27,19 @@ export class APIKeyForm extends React.Component<{}, APIKeyFormState> {

    Stored it securely on your servers and never store it in the client side of your app.

    - ); + ) } public render() { return (

    API Key

    -

    The API Key is only shown whenever generated. If your Key is lost or has been compromised, generated a new one and take note of it.

    +

    + The API Key is only shown whenever generated. If your Key is lost or has been compromised, generated a new one and take note of it. +

    To learn how to use the API, read the{" "} - + official documentation . @@ -49,6 +51,6 @@ export class APIKeyForm extends React.Component<{}, APIKeyFormState> {

    {this.state.apiKey && this.showAPIKey()}
    - ); + ) } } diff --git a/public/pages/MySettings/components/DangerZone.tsx b/public/pages/MySettings/components/DangerZone.tsx index ecf94a3a1..e4026308d 100644 --- a/public/pages/MySettings/components/DangerZone.tsx +++ b/public/pages/MySettings/components/DangerZone.tsx @@ -1,37 +1,37 @@ -import React from "react"; +import React from "react" -import { Button, Modal, ButtonClickEvent } from "@fider/components"; -import { actions, notify, navigator } from "@fider/services"; +import { Button, Modal, ButtonClickEvent } from "@fider/components" +import { actions, notify, navigator } from "@fider/services" interface DangerZoneState { - clicked: boolean; + clicked: boolean } -export class DangerZone extends React.Component<{}, DangerZoneState> { - constructor(props: {}) { - super(props); +export class DangerZone extends React.Component { + constructor(props: any) { + super(props) this.state = { clicked: false, - }; + } } public onClickDelete = async () => { - this.setState({ clicked: true }); - }; + this.setState({ clicked: true }) + } public onCancel = async () => { - this.setState({ clicked: false }); - }; + this.setState({ clicked: false }) + } public onConfirm = async (e: ButtonClickEvent) => { - const response = await actions.deleteCurrentAccount(); + const response = await actions.deleteCurrentAccount() if (response.ok) { - e.preventEnable(); - navigator.goHome(); + e.preventEnable() + navigator.goHome() } else { - notify.error("Failed to delete your account. Try again later"); + notify.error("Failed to delete your account. Try again later") } - }; + } public render() { return ( @@ -39,7 +39,10 @@ export class DangerZone extends React.Component<{}, DangerZoneState> { Delete account -

    When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it will be anonymised.

    +

    + When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it + will be anonymised. +

    This process is irreversible. Are you sure?

    @@ -55,12 +58,15 @@ export class DangerZone extends React.Component<{}, DangerZoneState> {

    Delete account

    -

    When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it will be anonymised.

    +

    + When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it will + be anonymised. +

    This process is irreversible. Please be certain.

    - ); + ) } } diff --git a/public/pages/MySettings/components/NotificationSettings.tsx b/public/pages/MySettings/components/NotificationSettings.tsx index e362a5083..988d4b67a 100644 --- a/public/pages/MySettings/components/NotificationSettings.tsx +++ b/public/pages/MySettings/components/NotificationSettings.tsx @@ -1,82 +1,82 @@ -import React, { useState } from "react"; +import React, { useState } from "react" -import { UserSettings } from "@fider/models"; -import { Toggle, Segment, Segments, Field } from "@fider/components"; -import { useFider } from "@fider/hooks"; +import { UserSettings } from "@fider/models" +import { Toggle, Segment, Segments, Field } from "@fider/components" +import { useFider } from "@fider/hooks" interface NotificationSettingsProps { - userSettings: UserSettings; - settingsChanged: (settings: UserSettings) => void; + userSettings: UserSettings + settingsChanged: (settings: UserSettings) => void } -type Channel = number; -const WebChannel: Channel = 1; -const EmailChannel: Channel = 2; +type Channel = number +const WebChannel: Channel = 1 +const EmailChannel: Channel = 2 export const NotificationSettings = (props: NotificationSettingsProps) => { - const fider = useFider(); - const [userSettings, setUserSettings] = useState(props.userSettings); + const fider = useFider() + const [userSettings, setUserSettings] = useState(props.userSettings) const isEnabled = (settingsKey: string, channel: Channel): boolean => { if (settingsKey in userSettings) { - return (parseInt(userSettings[settingsKey], 10) & channel) > 0; + return (parseInt(userSettings[settingsKey], 10) & channel) > 0 } - return false; - }; + return false + } const toggle = async (settingsKey: string, channel: Channel) => { const nextSettings = { ...userSettings, [settingsKey]: (parseInt(userSettings[settingsKey], 10) ^ channel).toString(), - }; - setUserSettings(nextSettings); - props.settingsChanged(nextSettings); - }; + } + setUserSettings(nextSettings) + props.settingsChanged(nextSettings) + } const icon = (settingsKey: string, channel: Channel) => { - const active = isEnabled(settingsKey, channel); - const label = channel === WebChannel ? "Web" : "Email"; - const onToggle = () => toggle(settingsKey, channel); - return ; - }; + const active = isEnabled(settingsKey, channel) + const label = channel === WebChannel ? "Web" : "Email" + const onToggle = () => toggle(settingsKey, channel) + return + } const info = (settingsKey: string, aboutForVisitors: string, aboutForCollaborators: string) => { - const about = fider.session.user.isCollaborator ? aboutForCollaborators : aboutForVisitors; - const webEnabled = isEnabled(settingsKey, WebChannel); - const emailEnabled = isEnabled(settingsKey, EmailChannel); + const about = fider.session.user.isCollaborator ? aboutForCollaborators : aboutForVisitors + const webEnabled = isEnabled(settingsKey, WebChannel) + const emailEnabled = isEnabled(settingsKey, EmailChannel) if (!webEnabled && !emailEnabled) { return (

    - You'll NOT receive any notification about this event. + You'll NOT receive any notification about this event.

    - ); + ) } else if (webEnabled && !emailEnabled) { return (

    - You'll receive web notifications about {about}. + You'll receive web notifications about {about}.

    - ); + ) } else if (!webEnabled && emailEnabled) { return (

    - You'll receive email notifications about {about}. + You'll receive email notifications about {about}.

    - ); + ) } else if (webEnabled && emailEnabled) { return (

    - You'll receive web and email notifications about {about}. + You'll receive web and email notifications about {about}.

    - ); + ) } - return null; - }; + return null + } return ( <> -

    Use following panel to choose which events you'd like to receive notification

    +

    Use following panel to choose which events you'd like to receive notification

    @@ -99,7 +99,11 @@ export const NotificationSettings = (props: NotificationSettingsProps) => { Status Changed - {info("event_notification_change_status", "status change on posts you've subscribed to", "status change on all posts unless individually unsubscribed")} + {info( + "event_notification_change_status", + "status change on posts you've subscribed to", + "status change on all posts unless individually unsubscribed" + )}

    {icon("event_notification_change_status", WebChannel)} {icon("event_notification_change_status", EmailChannel)} @@ -108,5 +112,5 @@ export const NotificationSettings = (props: NotificationSettingsProps) => {

    - ); -}; + ) +} diff --git a/public/pages/MySettings/index.ts b/public/pages/MySettings/index.ts index 1a0e7a5bb..1d42aba77 100644 --- a/public/pages/MySettings/index.ts +++ b/public/pages/MySettings/index.ts @@ -1 +1 @@ -export * from "./MySettings.page"; +export * from "./MySettings.page" diff --git a/public/pages/OAuthEcho/OAuthEcho.page.tsx b/public/pages/OAuthEcho/OAuthEcho.page.tsx index 30f7b36b6..b8fef6a50 100644 --- a/public/pages/OAuthEcho/OAuthEcho.page.tsx +++ b/public/pages/OAuthEcho/OAuthEcho.page.tsx @@ -1,27 +1,27 @@ -import "./OAuthEcho.page.scss"; +import "./OAuthEcho.page.scss" -import React from "react"; -import { navigator } from "@fider/services"; -import { Segments, Segment } from "@fider/components"; -import { FaCheckCircle, FaTimesCircle, FaExclamationTriangle } from "react-icons/fa"; +import React from "react" +import { navigator } from "@fider/services" +import { Segments, Segment } from "@fider/components" +import { FaCheckCircle, FaTimesCircle, FaExclamationTriangle } from "react-icons/fa" interface OAuthEchoPageProps { - err: string | undefined; - body: string; + err: string | undefined + body: string profile: { - id: string; - name: string; - email: string; - }; + id: string + name: string + email: string + } } -const ok = ; -const error = ; -const warn = ; +const ok = +const error = +const warn = -export default class OAuthEchoPage extends React.Component { +export default class OAuthEchoPage extends React.Component { public componentDidMount() { - navigator.replaceState("/"); + navigator.replaceState("/") } private renderError() { @@ -30,19 +30,19 @@ export default class OAuthEchoPage extends React.ComponentError
    {this.props.err}
    - ); + ) } private renderParseResult() { - const idOk = this.props.profile && this.props.profile.id !== ""; - const nameOk = this.props.profile && this.props.profile.name !== "Anonymous"; - const emailOk = this.props.profile && this.props.profile.email !== ""; + const idOk = this.props.profile && this.props.profile.id !== "" + const nameOk = this.props.profile && this.props.profile.name !== "Anonymous" + const emailOk = this.props.profile && this.props.profile.email !== "" - let responseBody = ""; + let responseBody = "" try { - responseBody = JSON.stringify(JSON.parse(this.props.body), null, " "); + responseBody = JSON.stringify(JSON.parse(this.props.body), null, " ") } catch { - responseBody = this.props.body; + responseBody = this.props.body } return ( @@ -64,7 +64,7 @@ export default class OAuthEchoPage extends React.ComponentName: {this.props.profile && this.props.profile.name} {!nameOk && (

    - Name is required, if not found we'll use Anonymous as the name of every new user. + Name is required, if not found we'll use Anonymous as the name of every new user.

    )}

    @@ -73,12 +73,16 @@ export default class OAuthEchoPage extends React.Component {emailOk ? ok : warn} Email: {this.props.profile && this.props.profile.email} - {!emailOk &&

    Email is not required, but highly recommended. If invalid or not found, new users won't be able to receive notifications.

    } + {!emailOk && ( +

    + Email is not required, but highly recommended. If invalid or not found, new users won't be able to receive notifications. +

    + )}

    - ); + ) } public render() { @@ -86,6 +90,6 @@ export default class OAuthEchoPage extends React.Component {this.props.err ? this.renderError() : this.renderParseResult()} - ); + ) } } diff --git a/public/pages/OAuthEcho/index.ts b/public/pages/OAuthEcho/index.ts index 0bd990b2d..f7293623c 100644 --- a/public/pages/OAuthEcho/index.ts +++ b/public/pages/OAuthEcho/index.ts @@ -1 +1 @@ -export * from "./OAuthEcho.page"; +export * from "./OAuthEcho.page" diff --git a/public/pages/ShowPost/ShowPost.page.tsx b/public/pages/ShowPost/ShowPost.page.tsx index 80889860f..5800216e0 100644 --- a/public/pages/ShowPost/ShowPost.page.tsx +++ b/public/pages/ShowPost/ShowPost.page.tsx @@ -1,78 +1,93 @@ -import "./ShowPost.page.scss"; - -import React from "react"; - -import { Comment, Post, Tag, Vote, ImageUpload } from "@fider/models"; -import { actions, Failure, Fider } from "@fider/services"; - -import { VoteCounter, ShowPostResponse, Button, UserName, Avatar, Moment, MultiLineText, List, ListItem, Input, Form, TextArea, MultiImageUploader, ImageViewer } from "@fider/components"; -import { FaSave, FaTimes, FaEdit } from "react-icons/fa"; -import { ResponseForm } from "./components/ResponseForm"; -import { TagsPanel } from "./components/TagsPanel"; -import { NotificationsPanel } from "./components/NotificationsPanel"; -import { ModerationPanel } from "./components/ModerationPanel"; -import { DiscussionPanel } from "./components/DiscussionPanel"; -import { VotesPanel } from "./components/VotesPanel"; +import "./ShowPost.page.scss" + +import React from "react" + +import { Comment, Post, Tag, Vote, ImageUpload } from "@fider/models" +import { actions, Failure, Fider } from "@fider/services" + +import { + VoteCounter, + ShowPostResponse, + Button, + UserName, + Avatar, + Moment, + MultiLineText, + List, + ListItem, + Input, + Form, + TextArea, + MultiImageUploader, + ImageViewer, +} from "@fider/components" +import { FaSave, FaTimes, FaEdit } from "react-icons/fa" +import { ResponseForm } from "./components/ResponseForm" +import { TagsPanel } from "./components/TagsPanel" +import { NotificationsPanel } from "./components/NotificationsPanel" +import { ModerationPanel } from "./components/ModerationPanel" +import { DiscussionPanel } from "./components/DiscussionPanel" +import { VotesPanel } from "./components/VotesPanel" interface ShowPostPageProps { - post: Post; - subscribed: boolean; - comments: Comment[]; - tags: Tag[]; - votes: Vote[]; - attachments: string[]; + post: Post + subscribed: boolean + comments: Comment[] + tags: Tag[] + votes: Vote[] + attachments: string[] } interface ShowPostPageState { - editMode: boolean; - newTitle: string; - attachments: ImageUpload[]; - newDescription: string; - error?: Failure; + editMode: boolean + newTitle: string + attachments: ImageUpload[] + newDescription: string + error?: Failure } export default class ShowPostPage extends React.Component { constructor(props: ShowPostPageProps) { - super(props); + super(props) this.state = { editMode: false, newTitle: this.props.post.title, newDescription: this.props.post.description, attachments: [], - }; + } } private saveChanges = async () => { - const result = await actions.updatePost(this.props.post.number, this.state.newTitle, this.state.newDescription, this.state.attachments); + const result = await actions.updatePost(this.props.post.number, this.state.newTitle, this.state.newDescription, this.state.attachments) if (result.ok) { - location.reload(); + location.reload() } else { this.setState({ error: result.error, - }); + }) } - }; + } private setNewTitle = (newTitle: string) => { - this.setState({ newTitle }); - }; + this.setState({ newTitle }) + } private setNewDescription = (newDescription: string) => { - this.setState({ newDescription }); - }; + this.setState({ newDescription }) + } private setAttachments = (attachments: ImageUpload[]) => { - this.setState({ attachments }); - }; + this.setState({ attachments }) + } private cancelEdit = async () => { - this.setState({ error: undefined, editMode: false }); - }; + this.setState({ error: undefined, editMode: false }) + } private startEdit = async () => { - this.setState({ editMode: true }); - }; + this.setState({ editMode: true }) + } public render() { return ( @@ -157,6 +172,6 @@ export default class ShowPostPage extends React.Component - ); + ) } } diff --git a/public/pages/ShowPost/components/CommentInput.tsx b/public/pages/ShowPost/components/CommentInput.tsx index 17e8c5699..97cd882ec 100644 --- a/public/pages/ShowPost/components/CommentInput.tsx +++ b/public/pages/ShowPost/components/CommentInput.tsx @@ -1,54 +1,54 @@ -import React, { useState, useRef } from "react"; +import React, { useState, useRef } from "react" -import { Post, ImageUpload } from "@fider/models"; -import { Avatar, UserName, Button, TextArea, Form, MultiImageUploader } from "@fider/components/common"; -import { SignInModal } from "@fider/components"; +import { Post, ImageUpload } from "@fider/models" +import { Avatar, UserName, Button, TextArea, Form, MultiImageUploader } from "@fider/components/common" +import { SignInModal } from "@fider/components" -import { cache, actions, Failure, Fider } from "@fider/services"; -import { useFider } from "@fider/hooks"; +import { cache, actions, Failure, Fider } from "@fider/services" +import { useFider } from "@fider/hooks" interface CommentInputProps { - post: Post; + post: Post } -const CACHE_TITLE_KEY = "CommentInput-Comment-"; +const CACHE_TITLE_KEY = "CommentInput-Comment-" export const CommentInput = (props: CommentInputProps) => { - const getCacheKey = () => `${CACHE_TITLE_KEY}${props.post.id}`; + const getCacheKey = () => `${CACHE_TITLE_KEY}${props.post.id}` - const fider = useFider(); - const inputRef = useRef(); - const [content, setContent] = useState((fider.session.isAuthenticated && cache.session.get(getCacheKey())) || ""); - const [isSignInModalOpen, setIsSignInModalOpen] = useState(false); - const [attachments, setAttachments] = useState([]); - const [error, setError] = useState(undefined); + const fider = useFider() + const inputRef = useRef() + const [content, setContent] = useState((fider.session.isAuthenticated && cache.session.get(getCacheKey())) || "") + const [isSignInModalOpen, setIsSignInModalOpen] = useState(false) + const [attachments, setAttachments] = useState([]) + const [error, setError] = useState(undefined) const commentChanged = (newContent: string) => { - cache.session.set(getCacheKey(), newContent); - setContent(newContent); - }; + cache.session.set(getCacheKey(), newContent) + setContent(newContent) + } - const hideModal = () => setIsSignInModalOpen(false); - const clearError = () => setError(undefined); + const hideModal = () => setIsSignInModalOpen(false) + const clearError = () => setError(undefined) const submit = async () => { - clearError(); + clearError() - const result = await actions.createComment(props.post.number, content, attachments); + const result = await actions.createComment(props.post.number, content, attachments) if (result.ok) { - cache.session.remove(getCacheKey()); - location.reload(); + cache.session.remove(getCacheKey()) + location.reload() } else { - setError(result.error); + setError(result.error) } - }; + } const handleOnFocus = () => { if (!fider.session.isAuthenticated && inputRef.current) { - inputRef.current.blur(); - setIsSignInModalOpen(true); + inputRef.current.blur() + setIsSignInModalOpen(true) } - }; + } return ( <> @@ -57,7 +57,15 @@ export const CommentInput = (props: CommentInputProps) => { {Fider.session.isAuthenticated && }
    {Fider.session.isAuthenticated && } -