diff --git a/ui/.eslintrc.js b/ui/.eslintrc.js
index e5314a2..e14b0ea 100644
--- a/ui/.eslintrc.js
+++ b/ui/.eslintrc.js
@@ -1,10 +1,18 @@
module.exports = {
+ root: true,
+ parser: '@typescript-eslint/parser',
env: {
browser: true,
es6: true,
},
- ignorePatterns: ['**/*.ts', '**/*.tsx'],
- extends: ['eslint:recommended', 'plugin:react/recommended'],
+ ignorePatterns: ['node_modules', 'dist'],
+ extends: [
+ 'eslint:recommended',
+ 'plugin:react/recommended',
+ 'plugin:@typescript-eslint/eslint-recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'prettier',
+ ],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
@@ -19,17 +27,20 @@ module.exports = {
ecmaVersion: 2018,
sourceType: 'module',
},
- plugins: ['react', 'react-hooks'],
+ plugins: ['react', 'react-hooks', '@typescript-eslint'],
rules: {
- 'no-unused-vars': 'warn',
+ 'no-unused-vars': 'off',
+ '@typescript-eslint/no-unused-vars': 'warn',
'react/display-name': 'off',
+ '@typescript-eslint/no-var-requires': 'off',
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
},
settings: {
react: {
version: 'detect',
},
},
- parser: 'babel-eslint',
+ // parser: 'babel-eslint',
overrides: [
Object.assign(require('eslint-plugin-jest').configs.recommended, {
files: ['**/*.test.js'],
@@ -43,5 +54,11 @@ module.exports = {
}
),
}),
+ {
+ files: ['**/*.js'],
+ rules: {
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
+ },
+ },
],
}
diff --git a/ui/babel.config.js b/ui/babel.config.js
index 43e0db3..5cdd249 100644
--- a/ui/babel.config.js
+++ b/ui/babel.config.js
@@ -2,7 +2,7 @@ module.exports = function (api) {
const isTest = api.env('test')
const isProduction = api.env('NODE_ENV') == 'production'
- let presets = ['@babel/preset-react']
+ let presets = ['@babel/preset-typescript', '@babel/preset-react']
let plugins = []
if (isTest) {
diff --git a/ui/build.mjs b/ui/build.mjs
index 3cab176..42f4006 100644
--- a/ui/build.mjs
+++ b/ui/build.mjs
@@ -23,7 +23,7 @@ const esbuildOptions = {
entryPoints: ['src/index.tsx'],
plugins: [
babel({
- filter: /photoview\/ui\/src\/.*\.js$/,
+ filter: /photoview\/ui\/src\/.*\.(js|tsx?)$/,
}),
],
publicPath: process.env.UI_PUBLIC_URL || '/',
@@ -66,25 +66,25 @@ if (watchMode) {
open: false,
})
- bs.watch('src/**/*.js').on('change', async args => {
+ bs.watch('src/**/*.@(js|tsx|ts)').on('change', async args => {
console.log('reloading', args)
builderPromise = (await builderPromise).rebuild()
bs.reload(args)
})
} else {
- const esbuildPromise = esbuild
- .build(esbuildOptions)
- .then(() => console.log('esbuild done'))
+ const build = async () => {
+ await esbuild.build(esbuildOptions)
- const workboxPromise = workboxBuild
- .generateSW({
+ console.log('esbuild done')
+
+ await workboxBuild.generateSW({
globDirectory: 'dist/',
globPatterns: ['**/*.{png,svg,woff2,ttf,eot,woff,js,ico,html,json,css}'],
swDest: 'dist/service-worker.js',
})
- .then(() => console.log('workbox done'))
- Promise.all([esbuildPromise, workboxPromise]).then(() =>
+ console.log('workbox done')
console.log('build complete')
- )
+ }
+ build()
}
diff --git a/ui/package-lock.json b/ui/package-lock.json
index ef8a704..2298621 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -15,6 +15,7 @@
"@babel/plugin-transform-runtime": "^7.13.15",
"@babel/preset-env": "^7.13.15",
"@babel/preset-react": "^7.13.13",
+ "@babel/preset-typescript": "^7.13.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3",
"babel-plugin-graphql-tag": "^3.2.0",
@@ -60,6 +61,10 @@
"@types/react-helmet": "^6.1.1",
"@types/react-router-dom": "^5.1.7",
"@types/styled-components": "^5.1.9",
+ "@types/url-join": "^4.0.0",
+ "@typescript-eslint/eslint-plugin": "^4.21.0",
+ "@typescript-eslint/parser": "^4.21.0",
+ "eslint-config-prettier": "^8.1.0",
"husky": "^6.0.0",
"jest": "^26.6.3",
"lint-staged": "^10.5.4",
@@ -769,6 +774,17 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/plugin-syntax-typescript": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.13.tgz",
+ "integrity": "sha512-cHP3u1JiUiG2LFDKbXnwVad81GvfyIOmCD6HIEId6ojrY0Drfy2q1jw7BwN7dE84+kTnBjLkXoL3IEy/3JPu2w==",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.12.13"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/plugin-transform-arrow-functions": {
"version": "7.13.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz",
@@ -1192,6 +1208,19 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/plugin-transform-typescript": {
+ "version": "7.13.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.13.0.tgz",
+ "integrity": "sha512-elQEwluzaU8R8dbVuW2Q2Y8Nznf7hnjM7+DSCd14Lo5fF63C9qNLbwZYbmZrtV9/ySpSUpkRpQXvJb6xyu4hCQ==",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.13.0",
+ "@babel/helper-plugin-utils": "^7.13.0",
+ "@babel/plugin-syntax-typescript": "^7.12.13"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/plugin-transform-unicode-escapes": {
"version": "7.12.13",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz",
@@ -1330,6 +1359,19 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/preset-typescript": {
+ "version": "7.13.0",
+ "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.13.0.tgz",
+ "integrity": "sha512-LXJwxrHy0N3f6gIJlYbLta1D9BDtHpQeqwzM0LIfjDlr6UE/D5Mc7W4iDiQzaE+ks0sTjT26ArcHWnJVt0QiHw==",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.13.0",
+ "@babel/helper-validator-option": "^7.12.17",
+ "@babel/plugin-transform-typescript": "^7.13.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/runtime": {
"version": "7.13.10",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz",
@@ -2344,31 +2386,31 @@
}
},
"node_modules/@nodelib/fs.scandir": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
- "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
+ "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
"dependencies": {
- "@nodelib/fs.stat": "2.0.3",
+ "@nodelib/fs.stat": "2.0.4",
"run-parallel": "^1.1.9"
},
"engines": {
"node": ">= 8"
}
},
- "node_modules/@nodelib/fs.scandir/node_modules/@nodelib/fs.stat": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
- "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+ "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==",
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.walk": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
- "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
+ "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
"dependencies": {
- "@nodelib/fs.scandir": "2.1.3",
+ "@nodelib/fs.scandir": "2.1.4",
"fastq": "^1.6.0"
},
"engines": {
@@ -2882,6 +2924,12 @@
"@types/jest": "*"
}
},
+ "node_modules/@types/url-join": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/url-join/-/url-join-4.0.0.tgz",
+ "integrity": "sha512-awrJu8yML4E/xTwr2EMatC+HBnHGoDxc2+ImA9QyeUELI1S7dOCIZcyjki1rkwoA8P2D2NVgLAJLjnclkdLtAw==",
+ "dev": true
+ },
"node_modules/@types/yargs": {
"version": "15.0.9",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.9.tgz",
@@ -2900,64 +2948,164 @@
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.1.tgz",
"integrity": "sha512-wmk0xQI6Yy7Fs/il4EpOcflG4uonUpYGqvZARESLc2oy4u69fkatFLbJOeW4Q6awO15P4rduAe6xkwHevpXcUQ=="
},
- "node_modules/@typescript-eslint/experimental-utils": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.6.0.tgz",
- "integrity": "sha512-pnh6Beh2/4xjJVNL+keP49DFHk3orDHHFylSp3WEjtgW3y1U+6l+jNnJrGlbs6qhAz5z96aFmmbUyKhunXKvKw==",
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz",
+ "integrity": "sha512-FPUyCPKZbVGexmbCFI3EQHzCZdy2/5f+jv6k2EDljGdXSRc0cKvbndd2nHZkSLqCNOPk0jB6lGzwIkglXcYVsQ==",
+ "devOptional": true,
"dependencies": {
- "@types/json-schema": "^7.0.3",
- "@typescript-eslint/scope-manager": "4.6.0",
- "@typescript-eslint/types": "4.6.0",
- "@typescript-eslint/typescript-estree": "4.6.0",
- "eslint-scope": "^5.0.0",
- "eslint-utils": "^2.0.0"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.6.0.tgz",
- "integrity": "sha512-uZx5KvStXP/lwrMrfQQwDNvh2ppiXzz5TmyTVHb+5TfZ3sUP7U1onlz3pjoWrK9konRyFe1czyxObWTly27Ang==",
- "dependencies": {
- "@typescript-eslint/types": "4.6.0",
- "@typescript-eslint/visitor-keys": "4.6.0"
- },
- "engines": {
- "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.6.0.tgz",
- "integrity": "sha512-5FAgjqH68SfFG4UTtIFv+rqYJg0nLjfkjD0iv+5O27a0xEeNZ5rZNDvFGZDizlCD1Ifj7MAbSW2DPMrf0E9zjA==",
- "engines": {
- "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.6.0.tgz",
- "integrity": "sha512-s4Z9qubMrAo/tw0CbN0IN4AtfwuehGXVZM0CHNMdfYMGBDhPdwTEpBrecwhP7dRJu6d9tT9ECYNaWDHvlFSngA==",
- "dependencies": {
- "@typescript-eslint/types": "4.6.0",
- "@typescript-eslint/visitor-keys": "4.6.0",
+ "@typescript-eslint/experimental-utils": "4.21.0",
+ "@typescript-eslint/scope-manager": "4.21.0",
"debug": "^4.1.1",
- "globby": "^11.0.1",
- "is-glob": "^4.0.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/eslint-plugin/node_modules/semver": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "devOptional": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/experimental-utils": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.21.0.tgz",
+ "integrity": "sha512-cEbgosW/tUFvKmkg3cU7LBoZhvUs+ZPVM9alb25XvR0dal4qHL3SiUqHNrzoWSxaXA9gsifrYrS1xdDV6w/gIA==",
+ "dependencies": {
+ "@types/json-schema": "^7.0.3",
+ "@typescript-eslint/scope-manager": "4.21.0",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/typescript-estree": "4.21.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.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.21.0.tgz",
+ "integrity": "sha512-eyNf7QmE5O/l1smaQgN0Lj2M/1jOuNg2NrBm1dqqQN0sVngTLyw8tdCbih96ixlhbF1oINoN8fDCyEH9SjLeIA==",
+ "devOptional": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "4.21.0",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/typescript-estree": "4.21.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.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.21.0.tgz",
+ "integrity": "sha512-kfOjF0w1Ix7+a5T1knOw00f7uAP9Gx44+OEsNQi0PvvTPLYeXJlsCJ4tYnDj5PQEYfpcgOH5yBlw7K+UEI9Agw==",
+ "dependencies": {
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/visitor-keys": "4.21.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.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.21.0.tgz",
+ "integrity": "sha512-+OQaupjGVVc8iXbt6M1oZMwyKQNehAfLYJJ3SdvnofK2qcjfor9pEM62rVjBknhowTkh+2HF+/KdRAc/wGBN2w==",
+ "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.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.21.0.tgz",
+ "integrity": "sha512-ZD3M7yLaVGVYLw4nkkoGKumb7Rog7QID9YOWobFDMQKNl+vPxqVIW/uDk+MDeGc+OHcoG2nJ2HphwiPNajKw3w==",
+ "dependencies": {
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/visitor-keys": "4.21.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/typescript-estree/node_modules/semver": {
- "version": "7.3.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
- "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
"bin": {
"semver": "bin/semver.js"
},
@@ -2966,15 +3114,19 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.6.0.tgz",
- "integrity": "sha512-38Aa9Ztl0XyFPVzmutHXqDMCu15Xx8yKvUo38Gu3GhsuckCh3StPI5t2WIO9LHEsOH7MLmlGfKUisU8eW1Sjhg==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.21.0.tgz",
+ "integrity": "sha512-dH22dROWGi5Z6p+Igc8bLVLmwy7vEe8r+8c+raPQU0LxgogPUrRAtRGtvBWmlr9waTu3n+QLt/qrS/hWzk1x5w==",
"dependencies": {
- "@typescript-eslint/types": "4.6.0",
+ "@typescript-eslint/types": "4.21.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/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
@@ -5173,6 +5325,18 @@
"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-jest": {
"version": "24.3.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.3.5.tgz",
@@ -5934,6 +6098,75 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
+ "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==",
+ "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-glob/node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fast-glob/node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fast-glob/node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/micromatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
+ "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
+ "dependencies": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.2.3"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/fast-glob/node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
"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",
@@ -5945,9 +6178,9 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
},
"node_modules/fastq": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz",
- "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==",
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
+ "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
"dependencies": {
"reusify": "^1.0.4"
}
@@ -6291,9 +6524,9 @@
}
},
"node_modules/globby": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
- "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
+ "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
"dependencies": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
@@ -6304,52 +6537,9 @@
},
"engines": {
"node": ">=10"
- }
- },
- "node_modules/globby/node_modules/@nodelib/fs.stat": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
- "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/globby/node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dependencies": {
- "fill-range": "^7.0.1"
},
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/globby/node_modules/fast-glob": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
- "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
- "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/globby/node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/globby/node_modules/ignore": {
@@ -6360,37 +6550,6 @@
"node": ">= 4"
}
},
- "node_modules/globby/node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/globby/node_modules/micromatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
- "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
- "dependencies": {
- "braces": "^3.0.1",
- "picomatch": "^2.0.5"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/globby/node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
"node_modules/graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
@@ -9981,6 +10140,17 @@
"loose-envify": "cli.js"
}
},
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/lz-string": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
@@ -10773,11 +10943,14 @@
"dev": true
},
"node_modules/picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz",
+ "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==",
"engines": {
"node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pirates": {
@@ -10981,6 +11154,25 @@
"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==",
+ "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/quickselect": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
@@ -11639,9 +11831,26 @@
}
},
"node_modules/run-parallel": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
- "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q=="
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "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/rw": {
"version": "1.3.3",
@@ -13894,6 +14103,11 @@
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
},
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
"node_modules/yaml": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
@@ -14543,6 +14757,14 @@
"@babel/helper-plugin-utils": "^7.12.13"
}
},
+ "@babel/plugin-syntax-typescript": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.13.tgz",
+ "integrity": "sha512-cHP3u1JiUiG2LFDKbXnwVad81GvfyIOmCD6HIEId6ojrY0Drfy2q1jw7BwN7dE84+kTnBjLkXoL3IEy/3JPu2w==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.12.13"
+ }
+ },
"@babel/plugin-transform-arrow-functions": {
"version": "7.13.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz",
@@ -14863,6 +15085,16 @@
"@babel/helper-plugin-utils": "^7.12.13"
}
},
+ "@babel/plugin-transform-typescript": {
+ "version": "7.13.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.13.0.tgz",
+ "integrity": "sha512-elQEwluzaU8R8dbVuW2Q2Y8Nznf7hnjM7+DSCd14Lo5fF63C9qNLbwZYbmZrtV9/ySpSUpkRpQXvJb6xyu4hCQ==",
+ "requires": {
+ "@babel/helper-create-class-features-plugin": "^7.13.0",
+ "@babel/helper-plugin-utils": "^7.13.0",
+ "@babel/plugin-syntax-typescript": "^7.12.13"
+ }
+ },
"@babel/plugin-transform-unicode-escapes": {
"version": "7.12.13",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz",
@@ -14988,6 +15220,16 @@
"@babel/plugin-transform-react-pure-annotations": "^7.12.1"
}
},
+ "@babel/preset-typescript": {
+ "version": "7.13.0",
+ "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.13.0.tgz",
+ "integrity": "sha512-LXJwxrHy0N3f6gIJlYbLta1D9BDtHpQeqwzM0LIfjDlr6UE/D5Mc7W4iDiQzaE+ks0sTjT26ArcHWnJVt0QiHw==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.13.0",
+ "@babel/helper-validator-option": "^7.12.17",
+ "@babel/plugin-transform-typescript": "^7.13.0"
+ }
+ },
"@babel/runtime": {
"version": "7.13.10",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz",
@@ -15825,27 +16067,25 @@
"integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q=="
},
"@nodelib/fs.scandir": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
- "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
+ "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
"requires": {
- "@nodelib/fs.stat": "2.0.3",
+ "@nodelib/fs.stat": "2.0.4",
"run-parallel": "^1.1.9"
- },
- "dependencies": {
- "@nodelib/fs.stat": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
- "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA=="
- }
}
},
+ "@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=="
+ },
"@nodelib/fs.walk": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
- "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
+ "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
"requires": {
- "@nodelib/fs.scandir": "2.1.3",
+ "@nodelib/fs.scandir": "2.1.4",
"fastq": "^1.6.0"
}
},
@@ -16298,6 +16538,12 @@
"@types/jest": "*"
}
},
+ "@types/url-join": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/url-join/-/url-join-4.0.0.tgz",
+ "integrity": "sha512-awrJu8yML4E/xTwr2EMatC+HBnHGoDxc2+ImA9QyeUELI1S7dOCIZcyjki1rkwoA8P2D2NVgLAJLjnclkdLtAw==",
+ "dev": true
+ },
"@types/yargs": {
"version": "15.0.9",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.9.tgz",
@@ -16316,61 +16562,102 @@
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.1.tgz",
"integrity": "sha512-wmk0xQI6Yy7Fs/il4EpOcflG4uonUpYGqvZARESLc2oy4u69fkatFLbJOeW4Q6awO15P4rduAe6xkwHevpXcUQ=="
},
- "@typescript-eslint/experimental-utils": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.6.0.tgz",
- "integrity": "sha512-pnh6Beh2/4xjJVNL+keP49DFHk3orDHHFylSp3WEjtgW3y1U+6l+jNnJrGlbs6qhAz5z96aFmmbUyKhunXKvKw==",
+ "@typescript-eslint/eslint-plugin": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz",
+ "integrity": "sha512-FPUyCPKZbVGexmbCFI3EQHzCZdy2/5f+jv6k2EDljGdXSRc0cKvbndd2nHZkSLqCNOPk0jB6lGzwIkglXcYVsQ==",
+ "devOptional": true,
"requires": {
- "@types/json-schema": "^7.0.3",
- "@typescript-eslint/scope-manager": "4.6.0",
- "@typescript-eslint/types": "4.6.0",
- "@typescript-eslint/typescript-estree": "4.6.0",
- "eslint-scope": "^5.0.0",
- "eslint-utils": "^2.0.0"
- }
- },
- "@typescript-eslint/scope-manager": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.6.0.tgz",
- "integrity": "sha512-uZx5KvStXP/lwrMrfQQwDNvh2ppiXzz5TmyTVHb+5TfZ3sUP7U1onlz3pjoWrK9konRyFe1czyxObWTly27Ang==",
- "requires": {
- "@typescript-eslint/types": "4.6.0",
- "@typescript-eslint/visitor-keys": "4.6.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.6.0.tgz",
- "integrity": "sha512-5FAgjqH68SfFG4UTtIFv+rqYJg0nLjfkjD0iv+5O27a0xEeNZ5rZNDvFGZDizlCD1Ifj7MAbSW2DPMrf0E9zjA=="
- },
- "@typescript-eslint/typescript-estree": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.6.0.tgz",
- "integrity": "sha512-s4Z9qubMrAo/tw0CbN0IN4AtfwuehGXVZM0CHNMdfYMGBDhPdwTEpBrecwhP7dRJu6d9tT9ECYNaWDHvlFSngA==",
- "requires": {
- "@typescript-eslint/types": "4.6.0",
- "@typescript-eslint/visitor-keys": "4.6.0",
+ "@typescript-eslint/experimental-utils": "4.21.0",
+ "@typescript-eslint/scope-manager": "4.21.0",
"debug": "^4.1.1",
- "globby": "^11.0.1",
- "is-glob": "^4.0.1",
+ "functional-red-black-tree": "^1.0.1",
"lodash": "^4.17.15",
+ "regexpp": "^3.0.0",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
},
"dependencies": {
"semver": {
- "version": "7.3.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
- "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "devOptional": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ }
+ }
+ },
+ "@typescript-eslint/experimental-utils": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.21.0.tgz",
+ "integrity": "sha512-cEbgosW/tUFvKmkg3cU7LBoZhvUs+ZPVM9alb25XvR0dal4qHL3SiUqHNrzoWSxaXA9gsifrYrS1xdDV6w/gIA==",
+ "requires": {
+ "@types/json-schema": "^7.0.3",
+ "@typescript-eslint/scope-manager": "4.21.0",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/typescript-estree": "4.21.0",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^2.0.0"
+ }
+ },
+ "@typescript-eslint/parser": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.21.0.tgz",
+ "integrity": "sha512-eyNf7QmE5O/l1smaQgN0Lj2M/1jOuNg2NrBm1dqqQN0sVngTLyw8tdCbih96ixlhbF1oINoN8fDCyEH9SjLeIA==",
+ "devOptional": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "4.21.0",
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/typescript-estree": "4.21.0",
+ "debug": "^4.1.1"
+ }
+ },
+ "@typescript-eslint/scope-manager": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.21.0.tgz",
+ "integrity": "sha512-kfOjF0w1Ix7+a5T1knOw00f7uAP9Gx44+OEsNQi0PvvTPLYeXJlsCJ4tYnDj5PQEYfpcgOH5yBlw7K+UEI9Agw==",
+ "requires": {
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/visitor-keys": "4.21.0"
+ }
+ },
+ "@typescript-eslint/types": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.21.0.tgz",
+ "integrity": "sha512-+OQaupjGVVc8iXbt6M1oZMwyKQNehAfLYJJ3SdvnofK2qcjfor9pEM62rVjBknhowTkh+2HF+/KdRAc/wGBN2w=="
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.21.0.tgz",
+ "integrity": "sha512-ZD3M7yLaVGVYLw4nkkoGKumb7Rog7QID9YOWobFDMQKNl+vPxqVIW/uDk+MDeGc+OHcoG2nJ2HphwiPNajKw3w==",
+ "requires": {
+ "@typescript-eslint/types": "4.21.0",
+ "@typescript-eslint/visitor-keys": "4.21.0",
+ "debug": "^4.1.1",
+ "globby": "^11.0.1",
+ "is-glob": "^4.0.1",
+ "semver": "^7.3.2",
+ "tsutils": "^3.17.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
}
}
},
"@typescript-eslint/visitor-keys": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.6.0.tgz",
- "integrity": "sha512-38Aa9Ztl0XyFPVzmutHXqDMCu15Xx8yKvUo38Gu3GhsuckCh3StPI5t2WIO9LHEsOH7MLmlGfKUisU8eW1Sjhg==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.21.0.tgz",
+ "integrity": "sha512-dH22dROWGi5Z6p+Igc8bLVLmwy7vEe8r+8c+raPQU0LxgogPUrRAtRGtvBWmlr9waTu3n+QLt/qrS/hWzk1x5w==",
"requires": {
- "@typescript-eslint/types": "4.6.0",
+ "@typescript-eslint/types": "4.21.0",
"eslint-visitor-keys": "^2.0.0"
},
"dependencies": {
@@ -18296,6 +18583,13 @@
}
}
},
+ "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-jest": {
"version": "24.3.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.3.5.tgz",
@@ -18720,6 +19014,59 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
+ "fast-glob": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
+ "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
+ "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"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
+ },
+ "micromatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
+ "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.2.3"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ }
+ }
+ },
"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",
@@ -18731,9 +19078,9 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
},
"fastq": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz",
- "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==",
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
+ "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
"requires": {
"reusify": "^1.0.4"
}
@@ -19005,9 +19352,9 @@
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
},
"globby": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
- "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
+ "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
"requires": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
@@ -19017,66 +19364,10 @@
"slash": "^3.0.0"
},
"dependencies": {
- "@nodelib/fs.stat": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
- "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA=="
- },
- "braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "fast-glob": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
- "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
- "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"
- }
- },
- "fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
"ignore": {
"version": "5.1.8",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw=="
- },
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
- },
- "micromatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
- "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
- "requires": {
- "braces": "^3.0.1",
- "picomatch": "^2.0.5"
- }
- },
- "to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "requires": {
- "is-number": "^7.0.0"
- }
}
}
},
@@ -21898,6 +22189,14 @@
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
"lz-string": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
@@ -22521,9 +22820,9 @@
"dev": true
},
"picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz",
+ "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg=="
},
"pirates": {
"version": "4.0.1",
@@ -22682,6 +22981,11 @@
"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=="
+ },
"quickselect": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
@@ -23227,9 +23531,12 @@
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA=="
},
"run-parallel": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
- "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q=="
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "requires": {
+ "queue-microtask": "^1.2.2"
+ }
},
"rw": {
"version": "1.3.3",
@@ -25118,6 +25425,11 @@
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
},
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
"yaml": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
diff --git a/ui/package.json b/ui/package.json
index 24d6612..04be30a 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -15,6 +15,7 @@
"@babel/plugin-transform-runtime": "^7.13.15",
"@babel/preset-env": "^7.13.15",
"@babel/preset-react": "^7.13.13",
+ "@babel/preset-typescript": "^7.13.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3",
"babel-plugin-graphql-tag": "^3.2.0",
@@ -56,7 +57,7 @@
"start": "node --experimental-modules build.mjs watch",
"build": "NODE_ENV=production node --experimental-modules build.mjs",
"test": "npm run lint && npm run jest",
- "lint": "eslint ./src --max-warnings 0 --cache",
+ "lint": "eslint ./src --max-warnings 0 --cache --config .eslintrc.js",
"jest": "jest",
"genSchemaTypes": "npx apollo client:codegen --target=typescript",
"prepare": "(cd .. && npx husky install)"
@@ -69,6 +70,10 @@
"@types/react-helmet": "^6.1.1",
"@types/react-router-dom": "^5.1.7",
"@types/styled-components": "^5.1.9",
+ "@types/url-join": "^4.0.0",
+ "@typescript-eslint/eslint-plugin": "^4.21.0",
+ "@typescript-eslint/parser": "^4.21.0",
+ "eslint-config-prettier": "^8.1.0",
"husky": "^6.0.0",
"jest": "^26.6.3",
"lint-staged": "^10.5.4",
diff --git a/ui/src/@types/index.d.ts b/ui/src/@types/index.d.ts
new file mode 100644
index 0000000..d41bc37
--- /dev/null
+++ b/ui/src/@types/index.d.ts
@@ -0,0 +1,4 @@
+declare module '*.svg' {
+ const src: string
+ export default src
+}
diff --git a/ui/src/Layout.tsx b/ui/src/Layout.tsx
index fe11940..bcb2241 100644
--- a/ui/src/Layout.tsx
+++ b/ui/src/Layout.tsx
@@ -80,7 +80,7 @@ const SideButtonLink = styled(NavLink)`
`
type SideButtonProps = {
- children: any
+ children: ReactChild | ReactChild[]
to: string
exact: boolean
}
diff --git a/ui/src/apolloClient.js b/ui/src/apolloClient.ts
similarity index 76%
rename from ui/src/apolloClient.js
rename to ui/src/apolloClient.ts
index c353ad9..c239aa8 100644
--- a/ui/src/apolloClient.js
+++ b/ui/src/apolloClient.ts
@@ -4,6 +4,8 @@ import {
split,
ApolloLink,
HttpLink,
+ ServerError,
+ FieldMergeFunction,
} from '@apollo/client'
import { getMainDefinition } from '@apollo/client/utilities'
import { onError } from '@apollo/client/link/error'
@@ -12,6 +14,7 @@ import { WebSocketLink } from '@apollo/client/link/ws'
import urlJoin from 'url-join'
import { clearTokenCookie } from './helpers/authentication'
import { MessageState } from './components/messages/Messages'
+import { Message } from './components/messages/SubscriptionsHook'
export const GRAPHQL_ENDPOINT = process.env.PHOTOVIEW_API_ENDPOINT
? urlJoin(process.env.PHOTOVIEW_API_ENDPOINT, '/graphql')
@@ -26,12 +29,12 @@ console.log('GRAPHQL ENDPOINT', GRAPHQL_ENDPOINT)
const apiProtocol = new URL(GRAPHQL_ENDPOINT).protocol
-let websocketUri = new URL(GRAPHQL_ENDPOINT)
+const websocketUri = new URL(GRAPHQL_ENDPOINT)
websocketUri.protocol = apiProtocol === 'https:' ? 'wss:' : 'ws:'
const wsLink = new WebSocketLink({
- uri: websocketUri,
- credentials: 'include',
+ uri: websocketUri.toString(),
+ // credentials: 'include',
})
const link = split(
@@ -48,7 +51,7 @@ const link = split(
)
const linkError = onError(({ graphQLErrors, networkError }) => {
- let errorMessages = []
+ const errorMessages = []
if (graphQLErrors) {
graphQLErrors.map(({ message, locations, path }) =>
@@ -82,7 +85,7 @@ const linkError = onError(({ graphQLErrors, networkError }) => {
console.log(`[Network error]: ${JSON.stringify(networkError)}`)
clearTokenCookie()
- const errors = networkError.result.errors
+ const errors = (networkError as ServerError).result.errors
if (errors.length == 1) {
errorMessages.push({
@@ -92,7 +95,9 @@ const linkError = onError(({ graphQLErrors, networkError }) => {
} else if (errors.length > 1) {
errorMessages.push({
header: 'Multiple server errors',
- content: `Received ${graphQLErrors.length} errors from the server. You are being logged out in an attempt to recover.`,
+ content: `Received ${
+ graphQLErrors?.length || 0
+ } errors from the server. You are being logged out in an attempt to recover.`,
})
}
}
@@ -106,26 +111,32 @@ const linkError = onError(({ graphQLErrors, networkError }) => {
...msg,
},
}))
- MessageState.set(messages => [...messages, ...newMessages])
+ MessageState.set((messages: Message[]) => [...messages, ...newMessages])
}
})
+type PaginateCacheType = {
+ keyArgs: string[]
+ merge: FieldMergeFunction
+}
+
// Modified version of Apollo's offsetLimitPagination()
-const paginateCache = keyArgs => ({
- keyArgs,
- merge(existing, incoming, { args, fieldName }) {
- const merged = existing ? existing.slice(0) : []
- if (args?.paginate) {
- const { offset = 0 } = args.paginate
- for (let i = 0; i < incoming.length; ++i) {
- merged[offset + i] = incoming[i]
+const paginateCache = (keyArgs: string[]) =>
+ ({
+ keyArgs,
+ merge(existing, incoming, { args, fieldName }) {
+ const merged = existing ? existing.slice(0) : []
+ if (args?.paginate) {
+ const { offset = 0 } = args.paginate
+ for (let i = 0; i < incoming.length; ++i) {
+ merged[offset + i] = incoming[i]
+ }
+ } else {
+ throw new Error(`Paginate argument is missing for query: ${fieldName}`)
}
- } else {
- throw new Error(`Paginate argument is missing for query: ${fieldName}`)
- }
- return merged
- },
-})
+ return merged
+ },
+ } as PaginateCacheType)
const memoryCache = new InMemoryCache({
typePolicies: {
diff --git a/ui/src/components/AlbumTitle.js b/ui/src/components/AlbumTitle.tsx
similarity index 81%
rename from ui/src/components/AlbumTitle.js
rename to ui/src/components/AlbumTitle.tsx
index f4a6872..b7fd32b 100644
--- a/ui/src/components/AlbumTitle.js
+++ b/ui/src/components/AlbumTitle.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, useContext } from 'react'
import PropTypes from 'prop-types'
-import { Breadcrumb } from 'semantic-ui-react'
+import { Breadcrumb, IconProps } from 'semantic-ui-react'
import { Link } from 'react-router-dom'
import styled from 'styled-components'
import { Icon } from 'semantic-ui-react'
@@ -8,6 +8,7 @@ import { SidebarContext } from './sidebar/Sidebar'
import AlbumSidebar from './sidebar/AlbumSidebar'
import { useLazyQuery, gql } from '@apollo/client'
import { authToken } from '../helpers/authentication'
+import { albumPathQuery } from './__generated__/albumPathQuery'
const Header = styled.h1`
margin: 24px 0 8px 0 !important;
@@ -32,7 +33,7 @@ const StyledIcon = styled(Icon)`
}
`
-const SettingsIcon = props => {
+const SettingsIcon = (props: IconProps) => {
return
}
@@ -48,8 +49,18 @@ const ALBUM_PATH_QUERY = gql`
}
`
-const AlbumTitle = ({ album, disableLink = false }) => {
- const [fetchPath, { data: pathData }] = useLazyQuery(ALBUM_PATH_QUERY)
+type AlbumTitleProps = {
+ album: {
+ id: string
+ title: string
+ }
+ disableLink: boolean
+}
+
+const AlbumTitle = ({ album, disableLink = false }: AlbumTitleProps) => {
+ const [fetchPath, { data: pathData }] = useLazyQuery(
+ ALBUM_PATH_QUERY
+ )
const { updateSidebar } = useContext(SidebarContext)
useEffect(() => {
@@ -68,10 +79,7 @@ const AlbumTitle = ({ album, disableLink = false }) => {
let title = {album.title}
- let path = []
- if (pathData) {
- path = pathData.album.path
- }
+ const path = pathData?.album.path || []
const breadcrumbSections = path
.slice()
diff --git a/ui/src/components/PaginateLoader.js b/ui/src/components/PaginateLoader.tsx
similarity index 60%
rename from ui/src/components/PaginateLoader.js
rename to ui/src/components/PaginateLoader.tsx
index 19e6615..4c9ad2b 100644
--- a/ui/src/components/PaginateLoader.js
+++ b/ui/src/components/PaginateLoader.tsx
@@ -1,8 +1,12 @@
import React from 'react'
-import PropTypes from 'prop-types'
import { Loader } from 'semantic-ui-react'
-const PaginateLoader = ({ active, text }) => (
+type PaginateLoaderProps = {
+ active: boolean
+ text: string
+}
+
+const PaginateLoader = ({ active, text }: PaginateLoaderProps) => (
(
)
-PaginateLoader.propTypes = {
- active: PropTypes.bool,
- text: PropTypes.string,
-}
-
export default PaginateLoader
diff --git a/ui/src/components/header/Header.js b/ui/src/components/header/Header.tsx
similarity index 100%
rename from ui/src/components/header/Header.js
rename to ui/src/components/header/Header.tsx
diff --git a/ui/src/components/header/Searchbar.js b/ui/src/components/header/Searchbar.tsx
similarity index 75%
rename from ui/src/components/header/Searchbar.js
rename to ui/src/components/header/Searchbar.tsx
index 2f7886b..4d3d227 100644
--- a/ui/src/components/header/Searchbar.js
+++ b/ui/src/components/header/Searchbar.tsx
@@ -1,11 +1,15 @@
import React, { useState, useRef, useEffect } from 'react'
-import PropTypes from 'prop-types'
import styled from 'styled-components'
import { useLazyQuery, gql } from '@apollo/client'
-import { debounce } from '../../helpers/utils'
+import { debounce, DebouncedFn } from '../../helpers/utils'
import { ProtectedImage } from '../photoGallery/ProtectedMedia'
import { NavLink } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
+import {
+ searchQuery,
+ searchQuery_search_albums,
+ searchQuery_search_media,
+} from './__generated__/searchQuery'
const Container = styled.div`
height: 60px;
@@ -30,7 +34,7 @@ const SearchField = styled.input`
}
`
-const Results = styled.div`
+const Results = styled.div<{ show: boolean }>`
display: ${({ show }) => (show ? 'block' : 'none')};
position: absolute;
width: 100%;
@@ -79,27 +83,29 @@ const SEARCH_QUERY = gql`
const SearchBar = () => {
const { t } = useTranslation()
- const [fetchSearches, fetchResult] = useLazyQuery(SEARCH_QUERY)
+ const [fetchSearches, fetchResult] = useLazyQuery(SEARCH_QUERY)
const [query, setQuery] = useState('')
const [fetched, setFetched] = useState(false)
- let debouncedFetch = useRef(null)
+ type QueryFn = (query: string) => void
+
+ const debouncedFetch = useRef>(null)
useEffect(() => {
- debouncedFetch.current = debounce(query => {
+ debouncedFetch.current = debounce(query => {
fetchSearches({ variables: { query } })
setFetched(true)
}, 250)
return () => {
- debouncedFetch.current.cancel()
+ debouncedFetch.current?.cancel()
}
}, [])
- const fetchEvent = e => {
+ const fetchEvent = (e: React.ChangeEvent) => {
e.persist()
setQuery(e.target.value)
- if (e.target.value.trim() != '') {
+ if (e.target.value.trim() != '' && debouncedFetch.current) {
debouncedFetch.current(e.target.value.trim())
} else {
setFetched(false)
@@ -108,7 +114,12 @@ const SearchBar = () => {
let results = null
if (query.trim().length > 0 && fetched) {
- results =
+ results = (
+
+ )
}
return (
@@ -128,17 +139,21 @@ const ResultTitle = styled.h1`
margin: 12px 0 0.25rem;
`
-const SearchResults = ({ result }) => {
- const { t } = useTranslation()
- const { data, loading } = result
- const query = data && data.search.query
+type SearchResultsProps = {
+ searchData?: searchQuery
+ loading: boolean
+}
- const media = (data && data.search.media) || []
- const albums = (data && data.search.albums) || []
+const SearchResults = ({ searchData, loading }: SearchResultsProps) => {
+ const { t } = useTranslation()
+ const query = searchData?.search.query || ''
+
+ const media = searchData?.search.media || []
+ const albums = searchData?.search.albums || []
let message = null
if (loading) message = t('header.search.loading', 'Loading results...')
- else if (data && media.length == 0 && albums.length == 0)
+ else if (searchData && media.length == 0 && albums.length == 0)
message = t('header.search.no_results', 'No results found')
const albumElements = albums.map(album => (
@@ -155,7 +170,7 @@ const SearchResults = ({ result }) => {
// Prevent input blur event
e.preventDefault()
}}
- show={data}
+ show={!!searchData}
>
{message}
{albumElements.length > 0 && (
@@ -174,10 +189,6 @@ const SearchResults = ({ result }) => {
)
}
-SearchResults.propTypes = {
- result: PropTypes.object,
-}
-
const RowLink = styled(NavLink)`
display: flex;
align-items: center;
@@ -205,31 +216,31 @@ const RowTitle = styled.span`
padding-left: 8px;
`
-const PhotoRow = ({ query, media }) => (
+type PhotoRowArgs = {
+ query: string
+ media: searchQuery_search_media
+}
+
+const PhotoRow = ({ query, media }: PhotoRowArgs) => (
{searchHighlighted(query, media.title)}
)
-PhotoRow.propTypes = {
- query: PropTypes.string.isRequired,
- media: PropTypes.object.isRequired,
+type AlbumRowArgs = {
+ query: string
+ album: searchQuery_search_albums
}
-const AlbumRow = ({ query, album }) => (
+const AlbumRow = ({ query, album }: AlbumRowArgs) => (
{searchHighlighted(query, album.title)}
)
-AlbumRow.propTypes = {
- query: PropTypes.string.isRequired,
- album: PropTypes.object.isRequired,
-}
-
-const searchHighlighted = (query, text) => {
+const searchHighlighted = (query: string, text: string) => {
const i = text.toLowerCase().indexOf(query.toLowerCase())
if (i == -1) {
diff --git a/ui/src/components/messages/Messages.js b/ui/src/components/messages/Messages.js
index d16ae24..894c3f5 100644
--- a/ui/src/components/messages/Messages.js
+++ b/ui/src/components/messages/Messages.js
@@ -17,9 +17,11 @@ const Container = styled.div`
}
`
-export let MessageState = {
- set: null,
- get: null,
+export const MessageState = {
+ set: fn => {
+ console.warn('set function is not defined yet, called with', fn)
+ },
+ get: [],
add: message => {
MessageState.set(messages => {
const newMessages = messages.filter(msg => msg.key != message.key)
diff --git a/ui/src/components/messages/SubscriptionsHook.js b/ui/src/components/messages/SubscriptionsHook.ts
similarity index 69%
rename from ui/src/components/messages/SubscriptionsHook.js
rename to ui/src/components/messages/SubscriptionsHook.ts
index 5b52737..de1b287 100644
--- a/ui/src/components/messages/SubscriptionsHook.js
+++ b/ui/src/components/messages/SubscriptionsHook.ts
@@ -1,7 +1,9 @@
+import { notificationSubscription } from './__generated__/notificationSubscription'
import PropTypes from 'prop-types'
import { useEffect } from 'react'
import { useSubscription, gql } from '@apollo/client'
import { authToken } from '../../helpers/authentication'
+import { NotificationType } from '../../../__generated__/globalTypes'
const notificationSubscription = gql`
subscription notificationSubscription {
@@ -18,14 +20,37 @@ const notificationSubscription = gql`
}
`
-let messageTimeoutHandles = new Map()
+const messageTimeoutHandles = new Map()
-const SubscriptionsHook = ({ messages, setMessages }) => {
+export interface Message {
+ key: string
+ type: NotificationType
+ timeout?: number
+ props: {
+ header: string
+ content: string
+ negative?: boolean
+ positive?: boolean
+ percent?: number
+ }
+}
+
+type SubscriptionHookProps = {
+ messages: Message[]
+ setMessages: React.Dispatch>
+}
+
+const SubscriptionsHook = ({
+ messages,
+ setMessages,
+}: SubscriptionHookProps) => {
if (!authToken()) {
return null
}
- const { data, error } = useSubscription(notificationSubscription)
+ const { data, error } = useSubscription(
+ notificationSubscription
+ )
useEffect(() => {
if (error) {
@@ -33,7 +58,7 @@ const SubscriptionsHook = ({ messages, setMessages }) => {
...state,
{
key: Math.random().toString(26),
- type: 'message',
+ type: NotificationType.Message,
props: {
header: 'Network error',
content: error.message,
@@ -54,16 +79,16 @@ const SubscriptionsHook = ({ messages, setMessages }) => {
return
}
- const newNotification = {
+ const newNotification: Message = {
key: msg.key,
- type: msg.type.toLowerCase(),
- timeout: msg.timeout,
+ type: msg.type,
+ timeout: msg.timeout || undefined,
props: {
header: msg.header,
content: msg.content,
negative: msg.negative,
positive: msg.positive,
- percent: msg.progress,
+ percent: msg.progress || undefined,
},
}
diff --git a/ui/src/components/routes/AuthorizedRoute.js b/ui/src/components/routes/AuthorizedRoute.tsx
similarity index 71%
rename from ui/src/components/routes/AuthorizedRoute.js
rename to ui/src/components/routes/AuthorizedRoute.tsx
index b0ccb2c..2ba606e 100644
--- a/ui/src/components/routes/AuthorizedRoute.js
+++ b/ui/src/components/routes/AuthorizedRoute.tsx
@@ -1,5 +1,5 @@
-import React, { useEffect } from 'react'
-import PropTypes from 'prop-types'
+import React, { ReactChild, useEffect } from 'react'
+import PropTypes, { ReactComponentLike } from 'prop-types'
import { Route, Redirect } from 'react-router-dom'
import { useLazyQuery } from '@apollo/client'
import { authToken } from '../../helpers/authentication'
@@ -21,22 +21,31 @@ export const useIsAdmin = (enabled = true) => {
return data?.myUser?.admin
}
-export const Authorized = ({ children }) => {
+export const Authorized = ({ children }: { children: JSX.Element }) => {
const token = authToken()
return token ? children : null
}
-const AuthorizedRoute = ({ component: Component, admin = false, ...props }) => {
+type AuthorizedRouteProps = {
+ component: ReactComponentLike
+ admin: boolean
+}
+
+const AuthorizedRoute = ({
+ component: Component,
+ admin = false,
+ ...props
+}: AuthorizedRouteProps) => {
const token = authToken()
const isAdmin = useIsAdmin(admin)
- let unauthorizedRedirect = null
+ let unauthorizedRedirect: null | ReactChild = null
if (!token) {
unauthorizedRedirect =
}
- let adminRedirect = null
+ let adminRedirect: null | ReactChild = null
if (token && admin) {
if (isAdmin === false) {
adminRedirect =
diff --git a/ui/src/helpers/LazyLoad.js b/ui/src/helpers/LazyLoad.ts
similarity index 65%
rename from ui/src/helpers/LazyLoad.js
rename to ui/src/helpers/LazyLoad.ts
index 6892bf2..f70410d 100644
--- a/ui/src/helpers/LazyLoad.js
+++ b/ui/src/helpers/LazyLoad.ts
@@ -1,4 +1,6 @@
class LazyLoad {
+ observer: null | IntersectionObserver
+
constructor() {
this.observe = this.observe.bind(this)
this.loadImages = this.loadImages.bind(this)
@@ -6,22 +8,22 @@ class LazyLoad {
this.observer = null
}
- observe(images) {
+ observe(images: Element[]) {
if (!this.observer) {
this.observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting || entry.intersectionRatio > 0) {
const element = entry.target
this.setSrcAttribute(element)
- this.observer.unobserve(element)
+ this.observer?.unobserve(element)
}
})
})
}
- Array.from(images).forEach(image => this.observer.observe(image))
+ Array.from(images).forEach(image => this.observer?.observe(image))
}
- loadImages(elements) {
+ loadImages(elements: Element[]) {
const images = Array.from(elements)
if (images.length) {
if ('IntersectionObserver' in window) {
@@ -36,11 +38,18 @@ class LazyLoad {
this.observer && this.observer.disconnect()
}
- setSrcAttribute(element) {
+ setSrcAttribute(element: Element) {
if (element.hasAttribute('data-src')) {
const src = element.getAttribute('data-src')
- element.removeAttribute('data-src')
- element.setAttribute('src', src)
+ if (src) {
+ element.removeAttribute('data-src')
+ element.setAttribute('src', src)
+ } else {
+ console.warn(
+ 'WARN: expected element to have `data-src` property',
+ element
+ )
+ }
}
}
}
diff --git a/ui/src/helpers/authentication.js b/ui/src/helpers/authentication.ts
similarity index 75%
rename from ui/src/helpers/authentication.js
rename to ui/src/helpers/authentication.ts
index 3a60643..abe3655 100644
--- a/ui/src/helpers/authentication.js
+++ b/ui/src/helpers/authentication.ts
@@ -1,4 +1,4 @@
-export function saveTokenCookie(token) {
+export function saveTokenCookie(token: string) {
const maxAge = 14 * 24 * 60 * 60
document.cookie = `auth-token=${token} ;max-age=${maxAge} ;path=/ ;sameSite=Lax`
@@ -13,11 +13,11 @@ export function authToken() {
return match && match[1]
}
-export function saveSharePassword(shareToken, password) {
+export function saveSharePassword(shareToken: string, password: string) {
document.cookie = `share-token-pw-${shareToken}=${password} ;path=/ ;sameSite=Lax`
}
-export function getSharePassword(shareToken) {
+export function getSharePassword(shareToken: string) {
const match = document.cookie.match(
`share-token-pw-${shareToken}=([\\d\\w]+)`
)
diff --git a/ui/src/helpers/utils.js b/ui/src/helpers/utils.js
deleted file mode 100644
index b36de48..0000000
--- a/ui/src/helpers/utils.js
+++ /dev/null
@@ -1,28 +0,0 @@
-export function debounce(func, wait, triggerRising) {
- let timeout = null
-
- const debounced = (...args) => {
- if (timeout) {
- clearTimeout(timeout)
- timeout = null
- } else if (triggerRising) {
- func(...args)
- }
-
- timeout = setTimeout(() => {
- timeout = null
- func(...args)
- }, wait)
- }
-
- debounced.cancel = () => {
- clearTimeout(timeout)
- timeout = null
- }
-
- return debounced
-}
-
-export function isNil(value) {
- return value === undefined || value === null
-}
diff --git a/ui/src/helpers/utils.ts b/ui/src/helpers/utils.ts
new file mode 100644
index 0000000..e543c1b
--- /dev/null
+++ b/ui/src/helpers/utils.ts
@@ -0,0 +1,39 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+export interface DebouncedFn any> {
+ (...args: Parameters): void
+ cancel(): void
+}
+
+export function debounce any>(
+ func: T,
+ wait: number,
+ triggerRising?: boolean
+): DebouncedFn {
+ let timeout: number | undefined = undefined
+
+ const debounced = (...args: Parameters) => {
+ if (timeout) {
+ clearTimeout(timeout)
+ timeout = undefined
+ } else if (triggerRising) {
+ func(...args)
+ }
+
+ timeout = window.setTimeout(() => {
+ timeout = undefined
+ func(...args)
+ }, wait)
+ }
+
+ debounced.cancel = () => {
+ clearTimeout(timeout)
+ timeout = undefined
+ }
+
+ return debounced
+}
+
+export function isNil(value: any) {
+ return value === undefined || value === null
+}
diff --git a/ui/src/hooks/useScrollPagination.js b/ui/src/hooks/useScrollPagination.ts
similarity index 65%
rename from ui/src/hooks/useScrollPagination.js
rename to ui/src/hooks/useScrollPagination.ts
index 165bc87..2e7f716 100644
--- a/ui/src/hooks/useScrollPagination.js
+++ b/ui/src/hooks/useScrollPagination.ts
@@ -1,26 +1,44 @@
import { useCallback, useEffect, useRef, useState } from 'react'
-const useScrollPagination = ({ loading, fetchMore, data, getItems }) => {
- const observer = useRef(null)
- const observerElem = useRef(null)
+interface ScrollPaginationArgs {
+ loading: boolean
+ data: D
+ fetchMore(args: { variables: { offset: number } }): Promise<{ data: D }>
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ getItems(data: D): any[]
+}
+
+type ScrollPaginationResult = {
+ finished: boolean
+ containerElem(node: null | Element): void
+}
+
+function useScrollPagination({
+ loading,
+ fetchMore,
+ data,
+ getItems,
+}: ScrollPaginationArgs): ScrollPaginationResult {
+ const observer = useRef(null)
+ const observerElem = useRef(null)
const [finished, setFinished] = useState(false)
const reconfigureIntersectionObserver = () => {
- var options = {
+ const options = {
root: null,
rootMargin: '-100% 0px 0px 0px',
threshold: 0,
}
// delete old observer
- if (observer.current) observer.current.disconnect()
+ observer.current?.disconnect()
if (finished) return
// configure new observer
observer.current = new IntersectionObserver(entities => {
if (entities.find(x => x.isIntersecting == false)) {
- let itemCount = getItems(data).length
+ const itemCount = getItems(data).length
fetchMore({
variables: {
offset: itemCount,
@@ -40,7 +58,7 @@ const useScrollPagination = ({ loading, fetchMore, data, getItems }) => {
}
}
- const containerElem = useCallback(node => {
+ const containerElem = useCallback((node: null | Element): void => {
observerElem.current = node
// cleanup
@@ -55,7 +73,7 @@ const useScrollPagination = ({ loading, fetchMore, data, getItems }) => {
// only observe when not loading
useEffect(() => {
- if (observer.current != null) {
+ if (observer.current && observerElem.current) {
if (loading) {
observer.current.unobserve(observerElem.current)
} else {
diff --git a/ui/src/hooks/useURLParameters.js b/ui/src/hooks/useURLParameters.ts
similarity index 79%
rename from ui/src/hooks/useURLParameters.js
rename to ui/src/hooks/useURLParameters.ts
index 6ad3829..79c0051 100644
--- a/ui/src/hooks/useURLParameters.js
+++ b/ui/src/hooks/useURLParameters.ts
@@ -6,7 +6,7 @@ function useURLParameters() {
const url = new URL(urlString)
const params = new URLSearchParams(url.search)
- const getParam = (key, defaultValue = null) => {
+ const getParam = (key: string, defaultValue = null) => {
return params.has(key) ? params.get(key) : defaultValue
}
@@ -15,12 +15,12 @@ function useURLParameters() {
setUrlString(document.location.href)
}
- const setParam = (key, value) => {
+ const setParam = (key: string, value: string) => {
params.set(key, value)
updateParams()
}
- const setParams = pairs => {
+ const setParams = (pairs: { key: string; value: string }[]) => {
for (const pair of pairs) {
params.set(pair.key, pair.value)
}
diff --git a/ui/src/localization.js b/ui/src/localization.ts
similarity index 89%
rename from ui/src/localization.js
rename to ui/src/localization.ts
index 3890d3a..882ad83 100644
--- a/ui/src/localization.js
+++ b/ui/src/localization.ts
@@ -1,7 +1,7 @@
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
-export default function setupLocalization() {
+export default function setupLocalization(): void {
i18n.use(initReactI18next).init({
resources: {
en: {
diff --git a/ui/tsconfig.json b/ui/tsconfig.json
index b3854d6..fd4fb47 100644
--- a/ui/tsconfig.json
+++ b/ui/tsconfig.json
@@ -4,9 +4,12 @@
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
- // "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
- // "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
- // "lib": [], /* Specify library files to be included in the compilation. */
+ "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
+ "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
+ "lib": [
+ "es2015",
+ "dom"
+ ] /* Specify library files to be included in the compilation. */,
"allowJs": true /* Allow javascript files to be compiled. */,
// "checkJs": true, /* Report errors in .js files. */
"jsx": "preserve" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */,
@@ -48,7 +51,9 @@
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
- // "typeRoots": [], /* List of folders to include type definitions from. */
+ "typeRoots": [
+ "./src/@types/"
+ ] /* List of folders to include type definitions from. */,
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
@@ -68,5 +73,6 @@
/* Advanced Options */
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
- }
+ },
+ "exclude": ["node_modules/", "dist/"]
}