Make eslint check for typescript errors
Fix errors after making eslint more strict
This commit is contained in:
parent
b0512d7128
commit
4c9e9a2b9a
|
@ -0,0 +1,3 @@
|
|||
node_modules
|
||||
dist
|
||||
coverage
|
|
@ -1,3 +1,5 @@
|
|||
/* global __dirname */
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
|
@ -11,6 +13,7 @@ module.exports = {
|
|||
'plugin:react/recommended',
|
||||
'plugin:@typescript-eslint/eslint-recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
'prettier',
|
||||
],
|
||||
globals: {
|
||||
|
@ -21,6 +24,8 @@ module.exports = {
|
|||
require: 'readonly',
|
||||
},
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
|
@ -41,30 +46,13 @@ module.exports = {
|
|||
version: 'detect',
|
||||
},
|
||||
},
|
||||
// parser: 'babel-eslint',
|
||||
overrides: [
|
||||
// Object.assign(require('eslint-plugin-jest').configs.recommended, {
|
||||
// files: ['**/*.test.js', '**/*.test.ts', '**/*.test.tsx'],
|
||||
// env: { jest: true },
|
||||
// plugins: ['jest', 'jest-dom'],
|
||||
// rules: Object.assign(
|
||||
// require('eslint-plugin-jest').configs.recommended.rules,
|
||||
// {
|
||||
// 'no-import-assign': 'off',
|
||||
// 'react/prop-types': 'off',
|
||||
// 'jest/valid-title': 'off',
|
||||
// }
|
||||
// ),
|
||||
// settings: {
|
||||
// jest: {
|
||||
// version: 26,
|
||||
// },
|
||||
// },
|
||||
// }),
|
||||
{
|
||||
files: ['**/*.js'],
|
||||
files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'off',
|
||||
'@typescript-eslint/no-misused-promises': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
"@testing-library/user-event": "^14.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
||||
"@typescript-eslint/parser": "^5.30.6",
|
||||
"@vitest/ui": "^0.17.1",
|
||||
"apollo": "2.34.0",
|
||||
"apollo-language-server": "1.26.9",
|
||||
|
@ -5326,13 +5328,13 @@
|
|||
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.30.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
|
||||
"integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==",
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz",
|
||||
"integrity": "sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.30.5",
|
||||
"@typescript-eslint/type-utils": "5.30.5",
|
||||
"@typescript-eslint/utils": "5.30.5",
|
||||
"@typescript-eslint/scope-manager": "5.30.6",
|
||||
"@typescript-eslint/type-utils": "5.30.6",
|
||||
"@typescript-eslint/utils": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"ignore": "^5.2.0",
|
||||
|
@ -5357,6 +5359,99 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz",
|
||||
"integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz",
|
||||
"integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz",
|
||||
"integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.6.tgz",
|
||||
"integrity": "sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.30.6",
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/typescript-estree": "5.30.6",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz",
|
||||
"integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
|
@ -5390,13 +5485,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "5.30.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz",
|
||||
"integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==",
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.6.tgz",
|
||||
"integrity": "sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.30.5",
|
||||
"@typescript-eslint/types": "5.30.5",
|
||||
"@typescript-eslint/typescript-estree": "5.30.5",
|
||||
"@typescript-eslint/scope-manager": "5.30.6",
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/typescript-estree": "5.30.6",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -5415,6 +5510,90 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz",
|
||||
"integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz",
|
||||
"integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz",
|
||||
"integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz",
|
||||
"integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.30.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
|
||||
|
@ -5432,11 +5611,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.30.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz",
|
||||
"integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==",
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz",
|
||||
"integrity": "sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/utils": "5.30.5",
|
||||
"@typescript-eslint/utils": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
|
@ -5456,6 +5635,113 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz",
|
||||
"integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz",
|
||||
"integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz",
|
||||
"integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.6.tgz",
|
||||
"integrity": "sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.30.6",
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/typescript-estree": "5.30.6",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz",
|
||||
"integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "5.30.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
|
||||
|
@ -28832,13 +29118,13 @@
|
|||
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.30.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
|
||||
"integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==",
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz",
|
||||
"integrity": "sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==",
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.30.5",
|
||||
"@typescript-eslint/type-utils": "5.30.5",
|
||||
"@typescript-eslint/utils": "5.30.5",
|
||||
"@typescript-eslint/scope-manager": "5.30.6",
|
||||
"@typescript-eslint/type-utils": "5.30.6",
|
||||
"@typescript-eslint/utils": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"ignore": "^5.2.0",
|
||||
|
@ -28847,6 +29133,56 @@
|
|||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz",
|
||||
"integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz",
|
||||
"integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg=="
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz",
|
||||
"integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.6.tgz",
|
||||
"integrity": "sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==",
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.30.6",
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/typescript-estree": "5.30.6",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz",
|
||||
"integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
|
@ -28866,14 +29202,61 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "5.30.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz",
|
||||
"integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==",
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.6.tgz",
|
||||
"integrity": "sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==",
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.30.5",
|
||||
"@typescript-eslint/types": "5.30.5",
|
||||
"@typescript-eslint/typescript-estree": "5.30.5",
|
||||
"@typescript-eslint/scope-manager": "5.30.6",
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/typescript-estree": "5.30.6",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz",
|
||||
"integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz",
|
||||
"integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg=="
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz",
|
||||
"integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz",
|
||||
"integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
|
@ -28886,13 +29269,73 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "5.30.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz",
|
||||
"integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==",
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz",
|
||||
"integrity": "sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==",
|
||||
"requires": {
|
||||
"@typescript-eslint/utils": "5.30.5",
|
||||
"@typescript-eslint/utils": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz",
|
||||
"integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz",
|
||||
"integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg=="
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz",
|
||||
"integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/visitor-keys": "5.30.6",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.6.tgz",
|
||||
"integrity": "sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==",
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.30.6",
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"@typescript-eslint/typescript-estree": "5.30.6",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.30.6",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz",
|
||||
"integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.30.6",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
"scripts": {
|
||||
"start": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint ./src --max-warnings 0 --cache --config .eslintrc.js",
|
||||
"lint": "eslint ./src --max-warnings 0 --config .eslintrc.js",
|
||||
"test": "vitest",
|
||||
"test:ci": "CI=true vitest --reporter verbose --run --coverage",
|
||||
"genSchemaTypes": "apollo client:codegen --target=typescript --globalTypesFile=src/__generated__/globalTypes.ts && prettier --write */**/__generated__/*.ts",
|
||||
"genSchemaTypes": "apollo client:codegen --target=typescript --globalTypesFile=src/__generated__/globalTypes.ts --passthroughCustomScalars && prettier --write */**/__generated__/*.ts",
|
||||
"extractTranslations": "i18next -c i18next-parser.config.js",
|
||||
"prepare": "(cd .. && ./ui/node_modules/.bin/husky install)"
|
||||
},
|
||||
|
@ -63,6 +63,8 @@
|
|||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
"@testing-library/user-event": "^14.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
||||
"@typescript-eslint/parser": "^5.30.6",
|
||||
"@vitest/ui": "^0.17.1",
|
||||
"apollo": "2.34.0",
|
||||
"apollo-language-server": "1.26.9",
|
||||
|
|
|
@ -5,3 +5,16 @@ declare module '*.svg' {
|
|||
export { ReactComponent }
|
||||
// export default content
|
||||
}
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly REACT_APP_BUILD_VERSION: string | undefined
|
||||
readonly REACT_APP_BUILD_DATE: string | undefined
|
||||
readonly REACT_APP_BUILD_COMMIT_SHA: string | undefined
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
|
||||
type Time = string
|
||||
type Any = object
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import React, { useCallback } from 'react'
|
||||
import { useQuery, gql } from '@apollo/client'
|
||||
import AlbumGallery from '../../components/albumGallery/AlbumGallery'
|
||||
import AlbumGallery, {
|
||||
ALBUM_GALLERY_FRAGMENT,
|
||||
} from '../../components/albumGallery/AlbumGallery'
|
||||
import Layout from '../../components/layout/Layout'
|
||||
import useURLParameters from '../../hooks/useURLParameters'
|
||||
import useScrollPagination from '../../hooks/useScrollPagination'
|
||||
|
@ -10,10 +12,9 @@ import { albumQuery, albumQueryVariables } from './__generated__/albumQuery'
|
|||
import useOrderingParams from '../../hooks/useOrderingParams'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { isNil } from '../../helpers/utils'
|
||||
import { MEDIA_GALLERY_FRAGMENT } from '../../components/photoGallery/MediaGallery'
|
||||
|
||||
const ALBUM_QUERY = gql`
|
||||
${MEDIA_GALLERY_FRAGMENT}
|
||||
${ALBUM_GALLERY_FRAGMENT}
|
||||
|
||||
query albumQuery(
|
||||
$id: ID!
|
||||
|
@ -24,27 +25,7 @@ const ALBUM_QUERY = gql`
|
|||
$offset: Int
|
||||
) {
|
||||
album(id: $id) {
|
||||
id
|
||||
title
|
||||
subAlbums(
|
||||
order: { order_by: "title", order_direction: $orderDirection }
|
||||
) {
|
||||
id
|
||||
title
|
||||
thumbnail {
|
||||
id
|
||||
thumbnail {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
media(
|
||||
paginate: { limit: $limit, offset: $offset }
|
||||
order: { order_by: $mediaOrderBy, order_direction: $orderDirection }
|
||||
onlyFavorites: $onlyFavorites
|
||||
) {
|
||||
...MediaGalleryFields
|
||||
}
|
||||
...AlbumGalleryFields
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
@ -9,10 +9,10 @@ import { mockInitialSetupGraphql } from './loginTestHelpers'
|
|||
|
||||
vi.mock('../../helpers/authentication.ts')
|
||||
|
||||
const authToken = authentication.authToken // as vi.Mock<ReturnType<typeof authentication.authToken>>
|
||||
const authToken = vi.mocked(authentication.authToken)
|
||||
|
||||
describe('Initial setup page', () => {
|
||||
test('Render initial setup form', async () => {
|
||||
test('Render initial setup form', () => {
|
||||
authToken.mockImplementation(() => null)
|
||||
|
||||
const history = createMemoryHistory({
|
||||
|
|
|
@ -10,6 +10,10 @@ import { CheckInitialSetup } from './__generated__/CheckInitialSetup'
|
|||
import { useForm } from 'react-hook-form'
|
||||
import { Submit, TextField } from '../../primitives/form/Input'
|
||||
import MessageBox from '../../primitives/form/MessageBox'
|
||||
import {
|
||||
InitialSetup,
|
||||
InitialSetupVariables,
|
||||
} from './__generated__/InitialSetup'
|
||||
|
||||
const initialSetupMutation = gql`
|
||||
mutation InitialSetup(
|
||||
|
@ -59,13 +63,12 @@ const InitialSetupPage = () => {
|
|||
}, [notInitialSetup])
|
||||
|
||||
const [authorize, { loading: authorizeLoading, data: authorizationData }] =
|
||||
useMutation(initialSetupMutation, {
|
||||
useMutation<InitialSetup, InitialSetupVariables>(initialSetupMutation, {
|
||||
onCompleted: data => {
|
||||
const { success, token } = data.initialSetupWizard
|
||||
if (!data.initialSetupWizard) return
|
||||
|
||||
if (success) {
|
||||
login(token)
|
||||
}
|
||||
const { success, token } = data.initialSetupWizard
|
||||
if (success && token) login(token)
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -84,8 +87,8 @@ const InitialSetupPage = () => {
|
|||
}
|
||||
|
||||
let errorMessage = null
|
||||
if (authorizationData && !authorizationData.initialSetupWizard.success) {
|
||||
errorMessage = authorizationData.initialSetupWizard.status
|
||||
if (authorizationData && !authorizationData?.initialSetupWizard?.success) {
|
||||
errorMessage = authorizationData?.initialSetupWizard?.status
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -138,7 +141,7 @@ const InitialSetupPage = () => {
|
|||
<MessageBox
|
||||
type="negative"
|
||||
message={errorMessage}
|
||||
show={errorMessage}
|
||||
show={!!errorMessage}
|
||||
/>
|
||||
<Submit className="mt-2" disabled={authorizeLoading}>
|
||||
{t('login_page.initial_setup.field.submit', 'Setup Photoview')}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { mockInitialSetupGraphql } from './loginTestHelpers'
|
|||
|
||||
vi.mock('../../helpers/authentication.ts')
|
||||
|
||||
const authToken = authentication.authToken // as vi.Mock<ReturnType<typeof authentication.authToken>>
|
||||
const authToken = vi.mocked(authentication.authToken)
|
||||
|
||||
describe('Login page redirects', () => {
|
||||
test('Auth token redirect', async () => {
|
||||
|
@ -54,7 +54,7 @@ describe('Login page redirects', () => {
|
|||
})
|
||||
|
||||
describe('Login page', () => {
|
||||
test('Render login form', async () => {
|
||||
test('Render login form', () => {
|
||||
authToken.mockImplementation(() => null)
|
||||
|
||||
const history = createMemoryHistory({
|
||||
|
|
|
@ -106,7 +106,7 @@ const LoginForm = () => {
|
|||
<input
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
value={t('login_page.field.submit', 'Sign in') as string}
|
||||
value={t('login_page.field.submit', 'Sign in')}
|
||||
className="rounded-md px-8 py-2 mt-2 focus:outline-none cursor-pointer bg-gradient-to-bl from-[#FF8246] to-[#D6264D] text-white font-semibold focus:ring-2 focus:ring-red-200 disabled:cursor-default disabled:opacity-80"
|
||||
/>
|
||||
<MessageBox
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { ProtectedImage } from '../../components/photoGallery/ProtectedMedia'
|
||||
import {
|
||||
ProtectedImage,
|
||||
ProtectedImageProps,
|
||||
} from '../../components/photoGallery/ProtectedMedia'
|
||||
import {
|
||||
myFaces_myFaceGroups_imageFaces_media,
|
||||
myFaces_myFaceGroups_imageFaces_rectangle,
|
||||
} from './__generated__/myFaces'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const FaceImage = styled(({ origin, selectable, scale, ...rest }) => (
|
||||
type FaceImageProps = ProtectedImageProps & {
|
||||
origin: { x: number; y: number }
|
||||
selectable: boolean
|
||||
scale: number
|
||||
}
|
||||
|
||||
const FaceImage = styled(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
({ origin, selectable, scale, ...rest }: FaceImageProps) => (
|
||||
<ProtectedImage {...rest} />
|
||||
))<{ origin: { x: number; y: number }; selectable: boolean; scale: number }>`
|
||||
)
|
||||
)`
|
||||
position: absolute;
|
||||
transform-origin: ${({ origin }) => `${origin.x * 100}% ${origin.y * 100}%`};
|
||||
object-fit: cover;
|
||||
|
|
|
@ -218,7 +218,7 @@ describe('FaceDetails component', () => {
|
|||
})
|
||||
})
|
||||
|
||||
test('cancel add label to face group', async () => {
|
||||
test('cancel add label to face group', () => {
|
||||
render(
|
||||
<MockedProvider mocks={[]} addTypename={false}>
|
||||
<MemoryRouter>
|
||||
|
|
|
@ -3,7 +3,7 @@ import React, { useEffect, useReducer } from 'react'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import PaginateLoader from '../../../components/PaginateLoader'
|
||||
import MediaGallery from '../../../components/photoGallery/MediaGallery'
|
||||
import { photoGalleryReducer } from '../../../components/photoGallery/photoGalleryReducer'
|
||||
import { mediaGalleryReducer } from '../../../components/photoGallery/mediaGalleryReducer'
|
||||
import useScrollPagination from '../../../hooks/useScrollPagination'
|
||||
import FaceGroupTitle from './FaceGroupTitle'
|
||||
import {
|
||||
|
@ -62,7 +62,7 @@ const SingleFaceGroup = ({ faceGroupID }: SingleFaceGroupProps) => {
|
|||
},
|
||||
})
|
||||
|
||||
const [mediaState, dispatchMedia] = useReducer(photoGalleryReducer, {
|
||||
const [mediaState, dispatchMedia] = useReducer(mediaGalleryReducer, {
|
||||
presenting: false,
|
||||
activeIndex: -1,
|
||||
media: [],
|
||||
|
|
|
@ -49,7 +49,7 @@ const MapClusterMarker = ({
|
|||
marker,
|
||||
dispatchMarkerMedia,
|
||||
}: MapClusterMarkerProps) => {
|
||||
const thumbnail = JSON.parse(marker.thumbnail)
|
||||
const thumbnail = JSON.parse(marker.thumbnail) as { url: string }
|
||||
|
||||
const presentMedia = () => {
|
||||
dispatchMarkerMedia({
|
||||
|
|
|
@ -7,7 +7,7 @@ import styled from 'styled-components'
|
|||
import Layout from '../../components/layout/Layout'
|
||||
import { registerMediaMarkers } from '../../components/mapbox/mapboxHelperFunctions'
|
||||
import useMapboxMap from '../../components/mapbox/MapboxMap'
|
||||
import { urlPresentModeSetupHook } from '../../components/photoGallery/photoGalleryReducer'
|
||||
import { urlPresentModeSetupHook } from '../../components/photoGallery/mediaGalleryReducer'
|
||||
import MapPresentMarker from './MapPresentMarker'
|
||||
import { PlacesAction, placesReducer } from './placesReducer'
|
||||
import { mediaGeoJson } from './__generated__/mediaGeoJson'
|
||||
|
@ -108,7 +108,7 @@ const configureMapbox =
|
|||
|
||||
map.addSource('media', {
|
||||
type: 'geojson',
|
||||
data: mapboxData?.myMediaGeoJson,
|
||||
data: mapboxData?.myMediaGeoJson as never,
|
||||
cluster: true,
|
||||
clusterRadius: 50,
|
||||
clusterProperties: {
|
||||
|
|
|
@ -11,5 +11,5 @@ export interface mediaGeoJson {
|
|||
/**
|
||||
* Get media owned by the logged in user, returned in GeoJson format
|
||||
*/
|
||||
myMediaGeoJson: any
|
||||
myMediaGeoJson: Any
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { PresentMarker } from './PlacesPage'
|
||||
import {
|
||||
PhotoGalleryState,
|
||||
MediaGalleryState,
|
||||
PhotoGalleryAction,
|
||||
photoGalleryReducer,
|
||||
} from './../../components/photoGallery/photoGalleryReducer'
|
||||
mediaGalleryReducer,
|
||||
} from '../../components/photoGallery/mediaGalleryReducer'
|
||||
|
||||
export interface PlacesState extends PhotoGalleryState {
|
||||
export interface PlacesState extends MediaGalleryState {
|
||||
presentMarker?: PresentMarker
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,6 @@ export function placesReducer(
|
|||
}
|
||||
}
|
||||
default:
|
||||
return photoGalleryReducer(state, action)
|
||||
return mediaGalleryReducer(state, action)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
ScannerConcurrentWorkers,
|
||||
} from './ScannerConcurrentWorkers'
|
||||
|
||||
test('load ScannerConcurrentWorkers', async () => {
|
||||
test('load ScannerConcurrentWorkers', () => {
|
||||
const graphqlMocks = [
|
||||
{
|
||||
request: {
|
||||
|
|
|
@ -4,6 +4,11 @@ import { useTranslation } from 'react-i18next'
|
|||
import Checkbox from '../../../primitives/form/Checkbox'
|
||||
import { TextField, Button, ButtonGroup } from '../../../primitives/form/Input'
|
||||
import { TableRow, TableCell } from '../../../primitives/Table'
|
||||
import { createUser, createUserVariables } from './__generated__/createUser'
|
||||
import {
|
||||
userAddRootPath,
|
||||
userAddRootPathVariables,
|
||||
} from './__generated__/userAddRootPath'
|
||||
|
||||
export const CREATE_USER_MUTATION = gql`
|
||||
mutation createUser($username: String!, $admin: Boolean!) {
|
||||
|
@ -46,21 +51,22 @@ const AddUserRow = ({ setShow, show, onUserAdded }: AddUserRowProps) => {
|
|||
onUserAdded()
|
||||
}
|
||||
|
||||
const [addRootPath, { loading: addRootPathLoading }] = useMutation(
|
||||
USER_ADD_ROOT_PATH_MUTATION,
|
||||
{
|
||||
const [addRootPath, { loading: addRootPathLoading }] = useMutation<
|
||||
userAddRootPath,
|
||||
userAddRootPathVariables
|
||||
>(USER_ADD_ROOT_PATH_MUTATION, {
|
||||
onCompleted: () => {
|
||||
finished()
|
||||
},
|
||||
onError: () => {
|
||||
finished()
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const [createUser, { loading: createUserLoading }] = useMutation(
|
||||
CREATE_USER_MUTATION,
|
||||
{
|
||||
const [createUser, { loading: createUserLoading }] = useMutation<
|
||||
createUser,
|
||||
createUserVariables
|
||||
>(CREATE_USER_MUTATION, {
|
||||
onCompleted: ({ createUser: { id } }) => {
|
||||
if (state.rootPath) {
|
||||
addRootPath({
|
||||
|
@ -73,8 +79,7 @@ const AddUserRow = ({ setShow, show, onUserAdded }: AddUserRowProps) => {
|
|||
finished()
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const loading = addRootPathLoading || createUserLoading
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ export type UserRowChildProps = {
|
|||
|
||||
export type UserRowProps = {
|
||||
user: settingsUsersQuery_user
|
||||
refetchUsers(): void
|
||||
refetchUsers: () => void
|
||||
}
|
||||
|
||||
const UserRow = ({ user, refetchUsers }: UserRowProps) => {
|
||||
|
|
|
@ -10,9 +10,7 @@ import {
|
|||
const VERSION = import.meta.env.REACT_APP_BUILD_VERSION ?? 'undefined'
|
||||
const BUILD_DATE = import.meta.env.REACT_APP_BUILD_DATE ?? 'undefined'
|
||||
|
||||
const COMMIT_SHA = import.meta.env.REACT_APP_BUILD_COMMIT_SHA as
|
||||
| string
|
||||
| undefined
|
||||
const COMMIT_SHA = import.meta.env.REACT_APP_BUILD_COMMIT_SHA
|
||||
let commitLink: ReactElement
|
||||
|
||||
if (COMMIT_SHA) {
|
||||
|
|
|
@ -25,7 +25,7 @@ const PasswordProtectedShare = ({
|
|||
const [invalidPassword, setInvalidPassword] = useState(false)
|
||||
|
||||
const onSubmit = () => {
|
||||
refetchWithPassword(watch('password'))
|
||||
refetchWithPassword(watch('password') as string)
|
||||
setInvalidPassword(true)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,14 @@ import MediaSharePage from './MediaSharePage'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import PasswordProtectedShare from './PasswordProtectedShare'
|
||||
import { isNil } from '../../helpers/utils'
|
||||
import {
|
||||
SharePageToken,
|
||||
SharePageTokenVariables,
|
||||
} from './__generated__/SharePageToken'
|
||||
import {
|
||||
ShareTokenValidatePassword,
|
||||
ShareTokenValidatePasswordVariables,
|
||||
} from './__generated__/ShareTokenValidatePassword'
|
||||
|
||||
export const SHARE_TOKEN_QUERY = gql`
|
||||
query SharePageToken($token: String!, $password: String) {
|
||||
|
@ -90,17 +98,20 @@ const AuthorizedTokenRoute = () => {
|
|||
const token = tokenFromParams()
|
||||
const password = getSharePassword(token)
|
||||
|
||||
const { loading, error, data } = useQuery(SHARE_TOKEN_QUERY, {
|
||||
const { loading, error, data } = useQuery<
|
||||
SharePageToken,
|
||||
SharePageTokenVariables
|
||||
>(SHARE_TOKEN_QUERY, {
|
||||
variables: {
|
||||
token,
|
||||
password,
|
||||
},
|
||||
})
|
||||
|
||||
if (error) return <div>{error.message}</div>
|
||||
if (!isNil(error)) return <div>{error.message}</div>
|
||||
if (loading) return <div>{t('general.loading.default', 'Loading...')}</div>
|
||||
|
||||
if (data.shareToken.album) {
|
||||
if (data?.shareToken.album) {
|
||||
const SharedSubAlbumPage = () => {
|
||||
const { subAlbum } = useParams()
|
||||
if (isNil(subAlbum))
|
||||
|
@ -128,7 +139,7 @@ const AuthorizedTokenRoute = () => {
|
|||
)
|
||||
}
|
||||
|
||||
if (data.shareToken.media) {
|
||||
if (data?.shareToken.media) {
|
||||
return <MediaSharePage media={data.shareToken.media} />
|
||||
}
|
||||
|
||||
|
@ -144,16 +155,16 @@ export const TokenRoute = () => {
|
|||
const { t } = useTranslation()
|
||||
const token = tokenFromParams()
|
||||
|
||||
const { loading, error, data, refetch } = useQuery(
|
||||
VALIDATE_TOKEN_PASSWORD_QUERY,
|
||||
{
|
||||
const { loading, error, data, refetch } = useQuery<
|
||||
ShareTokenValidatePassword,
|
||||
ShareTokenValidatePasswordVariables
|
||||
>(VALIDATE_TOKEN_PASSWORD_QUERY, {
|
||||
notifyOnNetworkStatusChange: true,
|
||||
variables: {
|
||||
token: token,
|
||||
password: getSharePassword(token),
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
if (error) {
|
||||
if (error.message == 'GraphQL error: share not found') {
|
||||
|
|
|
@ -122,7 +122,7 @@ export interface SharePageToken_shareToken_media_exif {
|
|||
* The name of the lens
|
||||
*/
|
||||
lens: string | null
|
||||
dateShot: any | null
|
||||
dateShot: Time | null
|
||||
/**
|
||||
* The exposure time of the image
|
||||
*/
|
||||
|
|
|
@ -136,7 +136,7 @@ export interface shareAlbumQuery_album_media_exif {
|
|||
* The name of the lens
|
||||
*/
|
||||
lens: string | null
|
||||
dateShot: any | null
|
||||
dateShot: Time | null
|
||||
/**
|
||||
* The exposure time of the image
|
||||
*/
|
||||
|
|
|
@ -56,19 +56,24 @@ const link = split(
|
|||
const linkError = onError(({ graphQLErrors, networkError }) => {
|
||||
const errorMessages = []
|
||||
|
||||
const formatPath = (path: readonly (string | number)[] | undefined) =>
|
||||
path?.join('::') ?? 'undefined'
|
||||
|
||||
if (graphQLErrors) {
|
||||
graphQLErrors.map(({ message, locations, path }) =>
|
||||
console.log(
|
||||
`[GraphQL error]: Message: ${message}, Location: ${JSON.stringify(
|
||||
locations
|
||||
)} Path: ${path}`
|
||||
)} Path: ${formatPath(path)}`
|
||||
)
|
||||
)
|
||||
|
||||
if (graphQLErrors.length == 1) {
|
||||
errorMessages.push({
|
||||
header: 'Something went wrong',
|
||||
content: `Server error: ${graphQLErrors[0].message} at (${graphQLErrors[0].path})`,
|
||||
content: `Server error: ${graphQLErrors[0].message} at (${formatPath(
|
||||
graphQLErrors[0].path
|
||||
)})`,
|
||||
})
|
||||
} else if (graphQLErrors.length > 1) {
|
||||
errorMessages.push({
|
||||
|
@ -88,7 +93,8 @@ const linkError = onError(({ graphQLErrors, networkError }) => {
|
|||
console.log(`[Network error]: ${JSON.stringify(networkError)}`)
|
||||
clearTokenCookie()
|
||||
|
||||
const errors = (networkError as ServerError)?.result.errors || []
|
||||
const errors =
|
||||
((networkError as ServerError)?.result.errors as Error[]) || []
|
||||
|
||||
if (errors.length == 1) {
|
||||
errorMessages.push({
|
||||
|
@ -120,7 +126,7 @@ const linkError = onError(({ graphQLErrors, networkError }) => {
|
|||
|
||||
type PaginateCacheType = {
|
||||
keyArgs: string[]
|
||||
merge: FieldMergeFunction
|
||||
merge: FieldMergeFunction<unknown[], unknown[]>
|
||||
}
|
||||
|
||||
// Modified version of Apollo's offsetLimitPagination()
|
||||
|
@ -130,7 +136,7 @@ const paginateCache = (keyArgs: string[]) =>
|
|||
merge(existing, incoming, { args, fieldName }) {
|
||||
const merged = existing ? existing.slice(0) : []
|
||||
if (args?.paginate) {
|
||||
const { offset = 0 } = args.paginate
|
||||
const { offset = 0 } = args.paginate as { offset: number }
|
||||
for (let i = 0; i < incoming.length; ++i) {
|
||||
merged[offset + i] = incoming[i]
|
||||
}
|
||||
|
|
|
@ -1,49 +1,46 @@
|
|||
import React, { useEffect, useReducer } from 'react'
|
||||
import AlbumTitle from '../album/AlbumTitle'
|
||||
import MediaGallery from '../photoGallery/MediaGallery'
|
||||
import MediaGallery, {
|
||||
MEDIA_GALLERY_FRAGMENT,
|
||||
} from '../photoGallery/MediaGallery'
|
||||
import AlbumBoxes from './AlbumBoxes'
|
||||
import AlbumFilter from '../album/AlbumFilter'
|
||||
import {
|
||||
albumQuery_album_media_highRes,
|
||||
albumQuery_album_media_thumbnail,
|
||||
albumQuery_album_media_videoWeb,
|
||||
albumQuery_album_subAlbums,
|
||||
} from '../../Pages/AlbumPage/__generated__/albumQuery'
|
||||
import {
|
||||
photoGalleryReducer,
|
||||
mediaGalleryReducer,
|
||||
urlPresentModeSetupHook,
|
||||
} from '../photoGallery/photoGalleryReducer'
|
||||
} from '../photoGallery/mediaGalleryReducer'
|
||||
import { MediaOrdering, SetOrderingFn } from '../../hooks/useOrderingParams'
|
||||
import { MediaType } from '../../__generated__/globalTypes'
|
||||
import { gql } from '@apollo/client'
|
||||
import { AlbumGalleryFields } from './__generated__/AlbumGalleryFields'
|
||||
|
||||
type AlbumGalleryAlbum = {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
title: string
|
||||
subAlbums: albumQuery_album_subAlbums[]
|
||||
media: {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
type: MediaType
|
||||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: albumQuery_album_media_thumbnail | null
|
||||
/**
|
||||
* URL to display the photo in full resolution, will be null for videos
|
||||
*/
|
||||
highRes: albumQuery_album_media_highRes | null
|
||||
/**
|
||||
* URL to get the video in a web format that can be played in the browser, will be null for photos
|
||||
*/
|
||||
videoWeb: albumQuery_album_media_videoWeb | null
|
||||
favorite?: boolean
|
||||
blurhash: string | null
|
||||
}[]
|
||||
}
|
||||
export const ALBUM_GALLERY_FRAGMENT = gql`
|
||||
${MEDIA_GALLERY_FRAGMENT}
|
||||
|
||||
fragment AlbumGalleryFields on Album {
|
||||
id
|
||||
title
|
||||
subAlbums(order: { order_by: "title", order_direction: $orderDirection }) {
|
||||
id
|
||||
title
|
||||
thumbnail {
|
||||
id
|
||||
thumbnail {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
media(
|
||||
paginate: { limit: $limit, offset: $offset }
|
||||
order: { order_by: $mediaOrderBy, order_direction: $orderDirection }
|
||||
onlyFavorites: $onlyFavorites
|
||||
) {
|
||||
...MediaGalleryFields
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
type AlbumGalleryProps = {
|
||||
album?: AlbumGalleryAlbum
|
||||
album?: AlbumGalleryFields
|
||||
loading?: boolean
|
||||
customAlbumLink?(albumID: string): string
|
||||
showFilter?: boolean
|
||||
|
@ -68,7 +65,7 @@ const AlbumGallery = React.forwardRef(
|
|||
}: AlbumGalleryProps,
|
||||
ref: React.ForwardedRef<HTMLDivElement>
|
||||
) => {
|
||||
const [mediaState, dispatchMedia] = useReducer(photoGalleryReducer, {
|
||||
const [mediaState, dispatchMedia] = useReducer(mediaGalleryReducer, {
|
||||
presenting: false,
|
||||
activeIndex: -1,
|
||||
media: album?.media || [],
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { MediaType } from './../../../__generated__/globalTypes'
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: AlbumGalleryFields
|
||||
// ====================================================
|
||||
|
||||
export interface AlbumGalleryFields_subAlbums_thumbnail_thumbnail {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface AlbumGalleryFields_subAlbums_thumbnail {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: AlbumGalleryFields_subAlbums_thumbnail_thumbnail | null
|
||||
}
|
||||
|
||||
export interface AlbumGalleryFields_subAlbums {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
title: string
|
||||
/**
|
||||
* An image in this album used for previewing this album
|
||||
*/
|
||||
thumbnail: AlbumGalleryFields_subAlbums_thumbnail | null
|
||||
}
|
||||
|
||||
export interface AlbumGalleryFields_media_thumbnail {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
/**
|
||||
* Width of the image in pixels
|
||||
*/
|
||||
width: number
|
||||
/**
|
||||
* Height of the image in pixels
|
||||
*/
|
||||
height: number
|
||||
}
|
||||
|
||||
export interface AlbumGalleryFields_media_highRes {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface AlbumGalleryFields_media_videoWeb {
|
||||
__typename: 'MediaURL'
|
||||
/**
|
||||
* URL for previewing the image
|
||||
*/
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface AlbumGalleryFields_media {
|
||||
__typename: 'Media'
|
||||
id: string
|
||||
type: MediaType
|
||||
/**
|
||||
* A short string that can be used to generate a blured version of the media, to show while the original is loading
|
||||
*/
|
||||
blurhash: string | null
|
||||
/**
|
||||
* URL to display the media in a smaller resolution
|
||||
*/
|
||||
thumbnail: AlbumGalleryFields_media_thumbnail | null
|
||||
/**
|
||||
* URL to display the photo in full resolution, will be null for videos
|
||||
*/
|
||||
highRes: AlbumGalleryFields_media_highRes | null
|
||||
/**
|
||||
* URL to get the video in a web format that can be played in the browser, will be null for photos
|
||||
*/
|
||||
videoWeb: AlbumGalleryFields_media_videoWeb | null
|
||||
favorite: boolean
|
||||
}
|
||||
|
||||
export interface AlbumGalleryFields {
|
||||
__typename: 'Album'
|
||||
id: string
|
||||
title: string
|
||||
/**
|
||||
* The albums contained in this album
|
||||
*/
|
||||
subAlbums: AlbumGalleryFields_subAlbums[]
|
||||
/**
|
||||
* The media inside this album
|
||||
*/
|
||||
media: AlbumGalleryFields_media[]
|
||||
}
|
|
@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react'
|
|||
import React from 'react'
|
||||
import Layout from './Layout'
|
||||
|
||||
test('Layout component', async () => {
|
||||
test('Layout component', () => {
|
||||
render(
|
||||
<Layout title="Test title">
|
||||
<p>layout_content</p>
|
||||
|
|
|
@ -9,7 +9,7 @@ import MainMenu, { MAPBOX_QUERY } from './MainMenu'
|
|||
|
||||
vi.mock('../../helpers/authentication.ts')
|
||||
|
||||
const authTokenMock = authentication.authToken // as vi.MockedFunction<typeof authentication.authToken>
|
||||
const authTokenMock = vi.mocked(authentication.authToken)
|
||||
|
||||
afterEach(() => {
|
||||
authTokenMock.mockClear()
|
||||
|
|
|
@ -5,6 +5,7 @@ import { authToken } from '../../helpers/authentication'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import { mapboxEnabledQuery } from '../../__generated__/mapboxEnabledQuery'
|
||||
import { tailwindClassNames } from '../../helpers/utils'
|
||||
import { faceDetectionEnabled } from './__generated__/faceDetectionEnabled'
|
||||
|
||||
export const MAPBOX_QUERY = gql`
|
||||
query mapboxEnabledQuery {
|
||||
|
@ -27,7 +28,7 @@ type MenuButtonProps = {
|
|||
background: string
|
||||
activeClasses?: string
|
||||
className?: string
|
||||
icon?: React.ReactChild
|
||||
icon?: React.ReactNode
|
||||
}
|
||||
|
||||
const MenuButton = ({
|
||||
|
@ -48,7 +49,7 @@ const MenuButton = ({
|
|||
`rounded-lg my-2 outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-dark-bg`,
|
||||
className,
|
||||
{
|
||||
[`ring-4 lg:ring-4 ${activeClasses}`]: isActive,
|
||||
[`ring-4 lg:ring-4 ${activeClasses ?? ''}`]: isActive,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -77,7 +78,7 @@ export const MainMenu = () => {
|
|||
? useQuery<mapboxEnabledQuery>(MAPBOX_QUERY)
|
||||
: null
|
||||
const faceDetectionEnabledQuery = authToken()
|
||||
? useQuery(FACE_DETECTION_ENABLED_QUERY)
|
||||
? useQuery<faceDetectionEnabled>(FACE_DETECTION_ENABLED_QUERY)
|
||||
: null
|
||||
|
||||
const mapboxEnabled = !!mapboxQuery?.data?.mapboxToken
|
||||
|
|
|
@ -15,5 +15,5 @@ export interface mapboxToken {
|
|||
/**
|
||||
* Get media owned by the logged in user, returned in GeoJson format
|
||||
*/
|
||||
myMediaGeoJson: any
|
||||
myMediaGeoJson: Any
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ const NOTIFICATION_SUBSCRIPTION = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const messageTimeoutHandles = new Map()
|
||||
const messageTimeoutHandles = new Map<string, number>()
|
||||
|
||||
export interface Message {
|
||||
key: string
|
||||
|
@ -101,7 +101,7 @@ const SubscriptionsHook = ({
|
|||
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
setMessages(messages => messages.filter(m => m.key != msg.key))
|
||||
}, msg.timeout)
|
||||
}, msg.timeout) as unknown as number
|
||||
|
||||
messageTimeoutHandles.set(msg.key, timeoutHandle)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react'
|
|||
import React from 'react'
|
||||
import { MediaType } from '../../__generated__/globalTypes'
|
||||
import MediaGallery from './MediaGallery'
|
||||
import { PhotoGalleryState } from './photoGalleryReducer'
|
||||
import { MediaGalleryState } from './mediaGalleryReducer'
|
||||
|
||||
vi.mock('./photoGalleryMutations', () => ({
|
||||
useMarkFavoriteMutation: () => [vi.fn()],
|
||||
|
@ -12,7 +12,7 @@ vi.mock('./photoGalleryMutations', () => ({
|
|||
test('photo gallery with media', () => {
|
||||
const dispatchMedia = vi.fn()
|
||||
|
||||
const mediaState: PhotoGalleryState = {
|
||||
const mediaState: MediaGalleryState = {
|
||||
activeIndex: 0,
|
||||
media: [
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ describe('photo gallery presenting', () => {
|
|||
const dispatchMedia = vi.fn()
|
||||
|
||||
test('not presenting', () => {
|
||||
const mediaStateNoPresent: PhotoGalleryState = {
|
||||
const mediaStateNoPresent: MediaGalleryState = {
|
||||
activeIndex: -1,
|
||||
media: [],
|
||||
presenting: false,
|
||||
|
@ -89,7 +89,7 @@ describe('photo gallery presenting', () => {
|
|||
})
|
||||
|
||||
test('presenting', () => {
|
||||
const mediaStatePresent: PhotoGalleryState = {
|
||||
const mediaStatePresent: MediaGalleryState = {
|
||||
activeIndex: 0,
|
||||
media: [
|
||||
{
|
||||
|
|
|
@ -5,8 +5,8 @@ import PresentView from './presentView/PresentView'
|
|||
import {
|
||||
openPresentModeAction,
|
||||
PhotoGalleryAction,
|
||||
PhotoGalleryState,
|
||||
} from './photoGalleryReducer'
|
||||
MediaGalleryState,
|
||||
} from './mediaGalleryReducer'
|
||||
import {
|
||||
toggleFavoriteAction,
|
||||
useMarkFavoriteMutation,
|
||||
|
@ -56,7 +56,7 @@ export const MEDIA_GALLERY_FRAGMENT = gql`
|
|||
|
||||
type MediaGalleryProps = {
|
||||
loading: boolean
|
||||
mediaState: PhotoGalleryState
|
||||
mediaState: MediaGalleryState
|
||||
dispatchMedia: React.Dispatch<PhotoGalleryAction>
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useEffect } from 'react'
|
||||
import { MediaGalleryFields } from './__generated__/MediaGalleryFields'
|
||||
|
||||
export interface PhotoGalleryState {
|
||||
export interface MediaGalleryState {
|
||||
presenting: boolean
|
||||
activeIndex: number
|
||||
media: MediaGalleryFields[]
|
||||
|
@ -18,10 +18,10 @@ export type PhotoGalleryAction =
|
|||
| { type: 'selectImage'; index: number }
|
||||
| { type: 'replaceMedia'; media: MediaGalleryFields[] }
|
||||
|
||||
export function photoGalleryReducer(
|
||||
state: PhotoGalleryState,
|
||||
export function mediaGalleryReducer(
|
||||
state: MediaGalleryState,
|
||||
action: PhotoGalleryAction
|
||||
): PhotoGalleryState {
|
||||
): MediaGalleryState {
|
||||
switch (action.type) {
|
||||
case 'nextImage':
|
||||
return {
|
||||
|
@ -69,15 +69,19 @@ export function photoGalleryReducer(
|
|||
}
|
||||
}
|
||||
|
||||
export interface MediaGalleryPopStateEvent extends PopStateEvent {
|
||||
state: MediaGalleryState
|
||||
}
|
||||
|
||||
export const urlPresentModeSetupHook = ({
|
||||
dispatchMedia,
|
||||
openPresentMode,
|
||||
}: {
|
||||
dispatchMedia: React.Dispatch<GalleryAction>
|
||||
openPresentMode: (event: PopStateEvent) => void
|
||||
openPresentMode: (event: MediaGalleryPopStateEvent) => void
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
const urlChangeListener = (event: PopStateEvent) => {
|
||||
const urlChangeListener = (event: MediaGalleryPopStateEvent) => {
|
||||
if (event.state.presenting === true) {
|
||||
openPresentMode(event)
|
||||
} else {
|
|
@ -1,5 +1,5 @@
|
|||
import { MediaGalleryFields } from './__generated__/MediaGalleryFields'
|
||||
import { gql, MutationFunction, useMutation } from '@apollo/client'
|
||||
import { PhotoGalleryProps_Media } from './MediaGallery'
|
||||
import {
|
||||
markMediaFavorite,
|
||||
markMediaFavoriteVariables,
|
||||
|
@ -24,7 +24,7 @@ export const toggleFavoriteAction = ({
|
|||
media,
|
||||
markFavorite,
|
||||
}: {
|
||||
media: PhotoGalleryProps_Media
|
||||
media: MediaGalleryFields
|
||||
markFavorite: MutationFunction<markMediaFavorite, markMediaFavoriteVariables>
|
||||
}) => {
|
||||
return markFavorite({
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { photoGalleryReducer, PhotoGalleryState } from './photoGalleryReducer'
|
||||
import { mediaGalleryReducer, MediaGalleryState } from './mediaGalleryReducer'
|
||||
import { MediaType } from '../../__generated__/globalTypes'
|
||||
|
||||
describe('photo gallery reducer', () => {
|
||||
const defaultState: PhotoGalleryState = {
|
||||
const defaultState: MediaGalleryState = {
|
||||
presenting: false,
|
||||
activeIndex: 0,
|
||||
media: [
|
||||
|
@ -34,13 +34,13 @@ describe('photo gallery reducer', () => {
|
|||
}
|
||||
|
||||
test('next image', () => {
|
||||
expect(photoGalleryReducer(defaultState, { type: 'nextImage' })).toEqual({
|
||||
expect(mediaGalleryReducer(defaultState, { type: 'nextImage' })).toEqual({
|
||||
...defaultState,
|
||||
activeIndex: 1,
|
||||
})
|
||||
|
||||
expect(
|
||||
photoGalleryReducer(
|
||||
mediaGalleryReducer(
|
||||
{ ...defaultState, activeIndex: 2 },
|
||||
{ type: 'nextImage' }
|
||||
)
|
||||
|
@ -52,14 +52,14 @@ describe('photo gallery reducer', () => {
|
|||
|
||||
test('previous image', () => {
|
||||
expect(
|
||||
photoGalleryReducer(defaultState, { type: 'previousImage' })
|
||||
mediaGalleryReducer(defaultState, { type: 'previousImage' })
|
||||
).toEqual({
|
||||
...defaultState,
|
||||
activeIndex: 2,
|
||||
})
|
||||
|
||||
expect(
|
||||
photoGalleryReducer(
|
||||
mediaGalleryReducer(
|
||||
{ ...defaultState, activeIndex: 2 },
|
||||
{ type: 'previousImage' }
|
||||
)
|
||||
|
@ -71,21 +71,21 @@ describe('photo gallery reducer', () => {
|
|||
|
||||
test('select image', () => {
|
||||
expect(
|
||||
photoGalleryReducer(defaultState, { type: 'selectImage', index: 1 })
|
||||
mediaGalleryReducer(defaultState, { type: 'selectImage', index: 1 })
|
||||
).toEqual({
|
||||
...defaultState,
|
||||
activeIndex: 1,
|
||||
})
|
||||
|
||||
expect(
|
||||
photoGalleryReducer(defaultState, { type: 'selectImage', index: 100 })
|
||||
mediaGalleryReducer(defaultState, { type: 'selectImage', index: 100 })
|
||||
).toEqual({
|
||||
...defaultState,
|
||||
activeIndex: 2,
|
||||
})
|
||||
|
||||
expect(
|
||||
photoGalleryReducer(defaultState, { type: 'selectImage', index: -5 })
|
||||
mediaGalleryReducer(defaultState, { type: 'selectImage', index: -5 })
|
||||
).toEqual({
|
||||
...defaultState,
|
||||
activeIndex: 0,
|
||||
|
@ -93,7 +93,7 @@ describe('photo gallery reducer', () => {
|
|||
})
|
||||
|
||||
test('present mode', () => {
|
||||
const openState = photoGalleryReducer(defaultState, {
|
||||
const openState = mediaGalleryReducer(defaultState, {
|
||||
type: 'openPresentMode',
|
||||
activeIndex: 10,
|
||||
})
|
||||
|
@ -104,7 +104,7 @@ describe('photo gallery reducer', () => {
|
|||
})
|
||||
|
||||
expect(
|
||||
photoGalleryReducer(openState, { type: 'closePresentMode' })
|
||||
mediaGalleryReducer(openState, { type: 'closePresentMode' })
|
||||
).toEqual({
|
||||
...openState,
|
||||
presenting: false,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useState, useRef, useEffect } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { debounce, DebouncedFn } from '../../../helpers/utils'
|
||||
import { closePresentModeAction, GalleryAction } from '../photoGalleryReducer'
|
||||
import { closePresentModeAction, GalleryAction } from '../mediaGalleryReducer'
|
||||
|
||||
import ExitIcon from './icons/Exit'
|
||||
import NextIcon from './icons/Next'
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { useEffect } from 'react'
|
|||
import styled, { createGlobalStyle } from 'styled-components'
|
||||
import PresentNavigationOverlay from './PresentNavigationOverlay'
|
||||
import PresentMedia from './PresentMedia'
|
||||
import { closePresentModeAction, GalleryAction } from '../photoGalleryReducer'
|
||||
import { closePresentModeAction, GalleryAction } from '../mediaGalleryReducer'
|
||||
import { MediaGalleryFields } from '../__generated__/MediaGalleryFields'
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
|
|
|
@ -14,7 +14,7 @@ const authToken = vi.mocked(authentication.authToken)
|
|||
describe('AuthorizedRoute component', () => {
|
||||
const AuthorizedComponent = () => <div>authorized content</div>
|
||||
|
||||
test('not logged in', async () => {
|
||||
test('not logged in', () => {
|
||||
authToken.mockImplementation(() => null)
|
||||
|
||||
render(
|
||||
|
@ -37,7 +37,7 @@ describe('AuthorizedRoute component', () => {
|
|||
expect(screen.queryByText('authorized content')).toBeNull()
|
||||
})
|
||||
|
||||
test('logged in', async () => {
|
||||
test('logged in', () => {
|
||||
authToken.mockImplementation(() => 'token-here')
|
||||
|
||||
render(
|
||||
|
|
|
@ -2,10 +2,12 @@ import { useLazyQuery } from '@apollo/client'
|
|||
import React, { useEffect } from 'react'
|
||||
import { Navigate } from 'react-router-dom'
|
||||
import { authToken } from '../../helpers/authentication'
|
||||
import { adminQuery } from '../../__generated__/adminQuery'
|
||||
import { ADMIN_QUERY } from '../layout/Layout'
|
||||
|
||||
export const useIsAdmin = () => {
|
||||
const [fetchAdminQuery, { data, called }] = useLazyQuery(ADMIN_QUERY)
|
||||
const [fetchAdminQuery, { data, called }] =
|
||||
useLazyQuery<adminQuery>(ADMIN_QUERY)
|
||||
|
||||
useEffect(() => {
|
||||
if (authToken() && !called) {
|
||||
|
|
|
@ -29,7 +29,7 @@ describe('routes', () => {
|
|||
expect(screen.getByText('mocked login page')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
test('invalid page should print a "not found" message', async () => {
|
||||
test('invalid page should print a "not found" message', () => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/random_non_existent_page']}>
|
||||
<Routes />
|
||||
|
|
|
@ -5,7 +5,7 @@ import { MediaSidebarMedia } from './MediaSidebar'
|
|||
import { MediaType } from '../../../__generated__/globalTypes'
|
||||
|
||||
describe('ExifDetails', () => {
|
||||
test('without EXIF information', async () => {
|
||||
test('without EXIF information', () => {
|
||||
const media: MediaSidebarMedia = {
|
||||
id: '1730',
|
||||
title: 'media_name.jpg',
|
||||
|
@ -45,14 +45,14 @@ describe('ExifDetails', () => {
|
|||
expect(screen.queryByText('Coordinates')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
test('with EXIF information', async () => {
|
||||
test('with EXIF information', () => {
|
||||
const media: MediaSidebarMedia = {
|
||||
id: '1730',
|
||||
title: 'media_name.jpg',
|
||||
type: MediaType.Photo,
|
||||
exif: {
|
||||
id: '1666',
|
||||
description: "Media description",
|
||||
description: 'Media description',
|
||||
camera: 'Canon EOS R',
|
||||
maker: 'Canon',
|
||||
lens: 'TAMRON SP 24-70mm F/2.8',
|
||||
|
|
|
@ -92,7 +92,7 @@ const ExifDetails = ({ media }: ExifDetailsProps) => {
|
|||
let metadata = Object.keys(videoMetadata)
|
||||
.filter(x => !['id', '__typename', 'width', 'height'].includes(x))
|
||||
.reduce((prev, curr) => {
|
||||
const value = videoMetadata[curr as string]
|
||||
const value = videoMetadata[curr]
|
||||
if (isNil(value)) return prev
|
||||
|
||||
return {
|
||||
|
|
|
@ -101,7 +101,7 @@ export interface sidebarMediaQuery_media_exif {
|
|||
* The name of the lens
|
||||
*/
|
||||
lens: string | null
|
||||
dateShot: any | null
|
||||
dateShot: Time | null
|
||||
/**
|
||||
* The exposure time of the image
|
||||
*/
|
||||
|
|
|
@ -379,7 +379,7 @@ type SidebarShareProps = {
|
|||
isPhoto: boolean
|
||||
loading: boolean
|
||||
shares?: sidebarGetPhotoShares_media_shares[]
|
||||
shareItem(item: { variables: { id: string } }): void
|
||||
shareItem: (item: { variables: { id: string } }) => Promise<unknown>
|
||||
}
|
||||
|
||||
const SidebarShare = ({
|
||||
|
|
|
@ -51,7 +51,7 @@ const formatBytes = (t: TranslationFn) => (bytes: number) => {
|
|||
case 4:
|
||||
return t('sidebar.download.filesize.tera_byte', '{{count}} TB', { count })
|
||||
default:
|
||||
return new Error(`invalid byte value: ${bytes}`)
|
||||
throw new Error(`invalid byte value: ${bytes}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ const downloadMediaShowProgress =
|
|||
return content
|
||||
}
|
||||
|
||||
const downloadBlob = async (blob: Blob, filename: string) => {
|
||||
const downloadBlob = (blob: Blob, filename: string) => {
|
||||
const objectUrl = window.URL.createObjectURL(blob)
|
||||
|
||||
const anchor = document.createElement('a')
|
||||
|
|
|
@ -22,5 +22,5 @@ export interface sidebarAlbumAddShare {
|
|||
export interface sidebarAlbumAddShareVariables {
|
||||
id: string
|
||||
password?: string | null
|
||||
expire?: any | null
|
||||
expire?: Time | null
|
||||
}
|
||||
|
|
|
@ -22,5 +22,5 @@ export interface sidebarPhotoAddShare {
|
|||
export interface sidebarPhotoAddShareVariables {
|
||||
id: string
|
||||
password?: string | null
|
||||
expire?: any | null
|
||||
expire?: Time | null
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
getActiveTimelineImage as getActiveTimelineMedia,
|
||||
timelineGalleryReducer,
|
||||
} from './timelineGalleryReducer'
|
||||
import { urlPresentModeSetupHook } from '../photoGallery/photoGalleryReducer'
|
||||
import { urlPresentModeSetupHook } from '../photoGallery/mediaGalleryReducer'
|
||||
import TimelineFilters from './TimelineFilters'
|
||||
import client from '../../apolloClient'
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ export interface earliestMedia_myMedia {
|
|||
/**
|
||||
* The date the image was shot or the date it was imported as a fallback
|
||||
*/
|
||||
date: any
|
||||
date: Time
|
||||
}
|
||||
|
||||
export interface earliestMedia {
|
||||
|
|
|
@ -84,7 +84,7 @@ export interface myTimeline_myTimeline {
|
|||
/**
|
||||
* The date the image was shot or the date it was imported as a fallback
|
||||
*/
|
||||
date: any
|
||||
date: Time
|
||||
}
|
||||
|
||||
export interface myTimeline {
|
||||
|
@ -98,5 +98,5 @@ export interface myTimelineVariables {
|
|||
onlyFavorites?: boolean | null
|
||||
limit?: number | null
|
||||
offset?: number | null
|
||||
fromDate?: any | null
|
||||
fromDate?: Time | null
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react'
|
||||
import { myTimeline_myTimeline } from './__generated__/myTimeline'
|
||||
import { TimelineGroup, TimelineGroupAlbum } from './TimelineGallery'
|
||||
import { GalleryAction } from '../photoGallery/photoGalleryReducer'
|
||||
import { GalleryAction } from '../photoGallery/mediaGalleryReducer'
|
||||
import { isNil } from '../../helpers/utils'
|
||||
|
||||
export interface TimelineMediaIndex {
|
||||
|
@ -179,8 +179,8 @@ export const getActiveTimelineImage = ({
|
|||
mediaState: TimelineGalleryState
|
||||
}) => {
|
||||
if (
|
||||
Object.values(mediaState.activeIndex).reduce(
|
||||
(acc, next) => next == -1 || acc,
|
||||
Object.values(mediaState.activeIndex).reduce<boolean>(
|
||||
(acc, next) => next === -1 || acc,
|
||||
false
|
||||
)
|
||||
) {
|
||||
|
|
|
@ -1,21 +1,19 @@
|
|||
import classNames, { Argument as ClassNamesArg } from 'classnames'
|
||||
import { overrideTailwindClasses } from 'tailwind-override'
|
||||
// import { overrideTailwindClasses } from 'tailwind-override'
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
export interface DebouncedFn<F extends (...args: any[]) => any> {
|
||||
export interface DebouncedFn<F extends (...args: unknown[]) => unknown> {
|
||||
(...args: Parameters<F>): void
|
||||
cancel(): void
|
||||
}
|
||||
|
||||
export function debounce<T extends (...args: any[]) => any>(
|
||||
func: T,
|
||||
export function debounce<F extends (...args: unknown[]) => unknown>(
|
||||
func: F,
|
||||
wait: number,
|
||||
triggerRising?: boolean
|
||||
): DebouncedFn<T> {
|
||||
): DebouncedFn<F> {
|
||||
let timeout: number | undefined = undefined
|
||||
|
||||
const debounced = (...args: Parameters<T>) => {
|
||||
const debounced = (...args: Parameters<F>) => {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
timeout = undefined
|
||||
|
@ -37,11 +35,12 @@ export function debounce<T extends (...args: any[]) => any>(
|
|||
return debounced
|
||||
}
|
||||
|
||||
export function isNil(value: any): value is undefined | null {
|
||||
export function isNil(value: unknown): value is undefined | null {
|
||||
return value === undefined || value === null
|
||||
}
|
||||
|
||||
export function exhaustiveCheck(value: never) {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
throw new Error(`Exhaustive check failed with value: ${value}`)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,24 +4,20 @@ import { useCallback, useEffect, useRef, useState } from 'react'
|
|||
interface ScrollPaginationArgs<D> {
|
||||
loading: boolean
|
||||
data: D | undefined
|
||||
fetchMore(args: {
|
||||
fetchMore: (args: {
|
||||
variables: { offset: number }
|
||||
}): Promise<ApolloQueryResult<D>>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getItems(data: D): any[]
|
||||
}) => Promise<ApolloQueryResult<D>>
|
||||
getItems: (data: D) => unknown[]
|
||||
}
|
||||
|
||||
type ScrollPaginationResult = {
|
||||
finished: boolean
|
||||
containerElem(node: null | Element): void
|
||||
containerElem: (node: null | Element) => void
|
||||
}
|
||||
|
||||
function useScrollPagination<D>({
|
||||
loading,
|
||||
fetchMore,
|
||||
data,
|
||||
getItems,
|
||||
}: ScrollPaginationArgs<D>): ScrollPaginationResult {
|
||||
const useScrollPagination: <D>(
|
||||
args: ScrollPaginationArgs<D>
|
||||
) => ScrollPaginationResult = ({ loading, fetchMore, data, getItems }) => {
|
||||
const observer = useRef<IntersectionObserver | null>(null)
|
||||
const observerElem = useRef<Element | null>(null)
|
||||
const [finished, setFinished] = useState(false)
|
||||
|
|
|
@ -3,12 +3,12 @@ import { useState } from 'react'
|
|||
export type UrlKeyValuePair = { key: string; value: string | null }
|
||||
|
||||
export type UrlParams = {
|
||||
getParam(key: string, defaultValue?: string | null): string | null
|
||||
setParam(key: string, value: string | null): void
|
||||
setParams(pairs: UrlKeyValuePair[]): void
|
||||
getParam: (key: string, defaultValue?: string | null) => string | null
|
||||
setParam: (key: string, value: string | null) => void
|
||||
setParams: (pairs: UrlKeyValuePair[]) => void
|
||||
}
|
||||
|
||||
function useURLParameters(): UrlParams {
|
||||
const useURLParameters: () => UrlParams = () => {
|
||||
const [urlString, setUrlString] = useState(document.location.href)
|
||||
|
||||
const url = new URL(urlString)
|
||||
|
|
|
@ -10,7 +10,9 @@ import { exhaustiveCheck, isNil } from './helpers/utils'
|
|||
export type TranslationFn = TFunction<'translation'>
|
||||
|
||||
export function setupLocalization(): void {
|
||||
i18n.use(initReactI18next).init({
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
lng: 'en',
|
||||
fallbackLng: 'en',
|
||||
returnNull: false,
|
||||
|
@ -24,6 +26,7 @@ export function setupLocalization(): void {
|
|||
useSuspense: import.meta.env.PROD,
|
||||
},
|
||||
})
|
||||
.catch(err => console.error('Failed to setup localization', err))
|
||||
}
|
||||
|
||||
const SITE_TRANSLATION = gql`
|
||||
|
|
|
@ -78,6 +78,7 @@ registerRoute(
|
|||
// This allows the web app to trigger skipWaiting via
|
||||
// registration.waiting.postMessage({type: 'SKIP_WAITING'})
|
||||
self.addEventListener('message', event => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
if (event.data && event.data.type === 'SKIP_WAITING') {
|
||||
self.skipWaiting()
|
||||
}
|
||||
|
|
|
@ -45,12 +45,16 @@ export function register(config?: Config) {
|
|||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
navigator.serviceWorker.ready
|
||||
.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service worker.' +
|
||||
'worker. To learn more, visit https://cra.link/PWA'
|
||||
)
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('Failed to load service worker')
|
||||
})
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config)
|
||||
|
@ -139,7 +143,7 @@ export function unregister() {
|
|||
.then(registration => {
|
||||
registration.unregister()
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error: Error) => {
|
||||
console.error(error.message)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,5 +17,5 @@
|
|||
"jsx": "react-jsx",
|
||||
"types": ["vitest/globals", "@testing-library/jest-dom"]
|
||||
},
|
||||
"include": ["src", "vite.config.ts"]
|
||||
"include": ["src", "vite.config.ts", ".eslintrc.js", "apollo.config.js"]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue