diff --git a/.vscode/settings.json b/.vscode/settings.json index 33fe63f7..04df0993 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "python.linting.flake8Enabled": true, - "python.linting.enabled": true + "python.linting.enabled": true, + "eslint.workingDirectories": [{ "mode": "auto" }] } \ No newline at end of file diff --git a/rsconcept/frontend/.eslintrc.json b/rsconcept/frontend/.eslintrc.json new file mode 100644 index 00000000..f3b0f326 --- /dev/null +++ b/rsconcept/frontend/.eslintrc.json @@ -0,0 +1,28 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "standard-with-typescript", + "plugin:react/recommended", + "plugin:react/jsx-runtime" + ], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module", + "project": ["tsconfig.json"] + }, + "plugins": [ + "react", "simple-import-sort" + ], + "rules": { + "simple-import-sort/imports": "error", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/semi": "off", + "@typescript-eslint/strict-boolean-expressions": "off", + "@typescript-eslint/space-before-function-paren": "off", + "@typescript-eslint/indent": "off", + "object-shorthand": "off" + } +} diff --git a/rsconcept/frontend/package-lock.json b/rsconcept/frontend/package-lock.json index f642658a..3e92c5f6 100644 --- a/rsconcept/frontend/package-lock.json +++ b/rsconcept/frontend/package-lock.json @@ -29,12 +29,20 @@ "react-tabs": "^6.0.1", "react-toastify": "^9.1.3", "styled-components": "^6.0.4", - "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.0", - "tailwindcss": "^3.3.2" + "@typescript-eslint/eslint-plugin": "^5.62.0", + "eslint": "^8.45.0", + "eslint-config-standard-with-typescript": "^37.0.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^16.0.1", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.33.0", + "eslint-plugin-simple-import-sort": "^10.0.0", + "tailwindcss": "^3.3.2", + "typescript": "^5.1.6" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2530,9 +2538,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.1.tgz", + "integrity": "sha512-O7x6dMstWLn2ktjcoiNLDkAGG2EjveHL+Vvc+n0fXumkJYAcSqcVYKtwDU+hDZ0uDUsnUagSYaZrOLAYE8un1A==", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -5956,6 +5964,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/builtins/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/builtins/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/builtins/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -7515,9 +7565,9 @@ } }, "node_modules/eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", + "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", @@ -7544,7 +7594,6 @@ "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", @@ -7556,7 +7605,6 @@ "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -7596,6 +7644,53 @@ "eslint": "^8.0.0" } }, + "node_modules/eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" + } + }, + "node_modules/eslint-config-standard-with-typescript": { + "version": "37.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-37.0.0.tgz", + "integrity": "sha512-V8I/Q1eFf9tiOuFHkbksUdWO3p1crFmewecfBtRxXdnvb71BCJx+1xAknlIRZMwZioMX3/bPtMVCZsf1+AjjOw==", + "dev": true, + "dependencies": { + "@typescript-eslint/parser": "^5.52.0", + "eslint-config-standard": "17.1.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.52.0", + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0", + "typescript": "*" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", @@ -7638,6 +7733,25 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-plugin-es-x": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.2.0.tgz", + "integrity": "sha512-9dvv5CcvNjSJPqnS5uZkqb3xmbeqRLnvXKK7iI5+oK/yTusyc46zbBZKENGsOfojm/mKfszyZb+wNqNPAPeGXA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.6.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, "node_modules/eslint-plugin-flowtype": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", @@ -7754,10 +7868,80 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, + "node_modules/eslint-plugin-n": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.0.1.tgz", + "integrity": "sha512-CDmHegJN0OF3L5cz5tATH84RPQm9kG+Yx39wIqIwPR2C0uhBGMWfbbOtetR83PQjjidA5aXMu+LEFw1jaSwvTA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^7.1.0", + "ignore": "^5.2.4", + "is-core-module": "^2.12.1", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.3" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-n/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-n/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, "node_modules/eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "version": "7.33.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.0.tgz", + "integrity": "sha512-qewL/8P34WkY8jAqdQxsiL82pDUeT7nhs8IsuXgfgnsEloKCT4miAV9N9kGtx7/KM9NH/NCGUE7Edt9iGxLXFw==", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flatmap": "^1.3.1", @@ -7772,7 +7956,7 @@ "object.values": "^1.1.6", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", + "semver": "^6.3.1", "string.prototype.matchall": "^4.0.8" }, "engines": { @@ -7820,6 +8004,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz", + "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, "node_modules/eslint-plugin-testing-library": { "version": "5.11.0", "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz", @@ -16973,15 +17166,15 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { diff --git a/rsconcept/frontend/package.json b/rsconcept/frontend/package.json index 1bf47974..7b4f8c10 100644 --- a/rsconcept/frontend/package.json +++ b/rsconcept/frontend/package.json @@ -24,7 +24,6 @@ "react-tabs": "^6.0.1", "react-toastify": "^9.1.3", "styled-components": "^6.0.4", - "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, "scripts": { @@ -33,12 +32,6 @@ "test": "react-scripts test", "eject": "react-scripts eject" }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, "browserslist": { "production": [ ">0.2%", @@ -53,6 +46,15 @@ }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.0", - "tailwindcss": "^3.3.2" + "@typescript-eslint/eslint-plugin": "^5.62.0", + "eslint": "^8.45.0", + "eslint-config-standard-with-typescript": "^37.0.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^16.0.1", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.33.0", + "eslint-plugin-simple-import-sort": "^10.0.0", + "tailwindcss": "^3.3.2", + "typescript": "^5.1.6" } } diff --git a/rsconcept/frontend/src/App.tsx b/rsconcept/frontend/src/App.tsx index a4b1f802..f9aed031 100644 --- a/rsconcept/frontend/src/App.tsx +++ b/rsconcept/frontend/src/App.tsx @@ -1,20 +1,20 @@ import { Route, Routes } from 'react-router-dom'; +import Footer from './components/Footer'; import Navigation from './components/Navigation/Navigation'; -import RSFormsPage from './pages/RSFormsPage'; -import RSFormPage from './pages/RSFormPage'; -import NotFoundPage from './pages/NotFoundPage'; +import ToasterThemed from './components/ToasterThemed'; import HomePage from './pages/HomePage'; import LoginPage from './pages/LoginPage'; -import RestorePasswordPage from './pages/RestorePasswordPage'; -import UserProfilePage from './pages/UserProfilePage'; -import RegisterPage from './pages/RegisterPage'; import ManualsPage from './pages/ManualsPage'; -import Footer from './components/Footer'; +import NotFoundPage from './pages/NotFoundPage'; +import RegisterPage from './pages/RegisterPage'; +import RestorePasswordPage from './pages/RestorePasswordPage'; import RSFormCreatePage from './pages/RSFormCreatePage'; -import ToasterThemed from './components/ToasterThemed'; +import RSFormPage from './pages/RSFormPage'; +import RSFormsPage from './pages/RSFormsPage'; +import UserProfilePage from './pages/UserProfilePage'; -function App() { +function App () { return (
@@ -32,9 +32,9 @@ function App() { } /> } /> } /> - + } /> - + } /> } /> } /> @@ -46,4 +46,4 @@ function App() { ); } -export default App; \ No newline at end of file +export default App; diff --git a/rsconcept/frontend/src/components/BackendError.tsx b/rsconcept/frontend/src/components/BackendError.tsx index 2dd66e88..2ceb9376 100644 --- a/rsconcept/frontend/src/components/BackendError.tsx +++ b/rsconcept/frontend/src/components/BackendError.tsx @@ -1,4 +1,5 @@ -import axios, { AxiosError } from 'axios'; +import axios, { type AxiosError } from 'axios'; + import PrettyJson from './Common/PrettyJSON'; export type ErrorInfo = string | Error | AxiosError | undefined; @@ -22,12 +23,12 @@ function DescribeError(error: ErrorInfo) { if (error.response.status === 404) { return (
-

{`Обращение к несуществующему API`}

+

{'Обращение к несуществующему API'}

); } - + const isHtml = error.response.headers['content-type'].includes('text/html'); return (
@@ -42,7 +43,7 @@ function DescribeError(error: ErrorInfo) { ); } -function BackendError({error}: BackendErrorProps) { +function BackendError({ error }: BackendErrorProps) { return (
{DescribeError(error)} @@ -50,4 +51,4 @@ function BackendError({error}: BackendErrorProps) { ); } -export default BackendError; \ No newline at end of file +export default BackendError; diff --git a/rsconcept/frontend/src/components/Common/Button.tsx b/rsconcept/frontend/src/components/Common/Button.tsx index 0308a4a6..4ef6f6bb 100644 --- a/rsconcept/frontend/src/components/Common/Button.tsx +++ b/rsconcept/frontend/src/components/Common/Button.tsx @@ -1,4 +1,4 @@ -import { MouseEventHandler } from 'react' +import { type MouseEventHandler } from 'react'; interface ButtonProps { id?: string @@ -14,14 +14,15 @@ interface ButtonProps { onClick?: MouseEventHandler | undefined } -function Button({id, text, icon, tooltip, +function Button({ + id, text, icon, tooltip, dense, disabled, - borderClass='border rounded', colorClass='clr-btn-default', widthClass='w-fit h-fit', + borderClass = 'border rounded', colorClass = 'clr-btn-default', widthClass = 'w-fit h-fit', loading, onClick, ...props }: ButtonProps) { - const padding = dense ? 'px-1' : 'px-3 py-2' - const cursor = 'disabled:cursor-not-allowed ' + (loading ? 'cursor-progress ': 'cursor-pointer ') + const padding = dense ? 'px-1' : 'px-3 py-2'; + const cursor = 'disabled:cursor-not-allowed ' + (loading ? 'cursor-progress ' : 'cursor-pointer '); return ( - ) + ); } -export default Button; \ No newline at end of file +export default Button; diff --git a/rsconcept/frontend/src/components/Common/Card.tsx b/rsconcept/frontend/src/components/Common/Card.tsx index d49be38b..0479e77e 100644 --- a/rsconcept/frontend/src/components/Common/Card.tsx +++ b/rsconcept/frontend/src/components/Common/Card.tsx @@ -4,7 +4,7 @@ interface CardProps { children: React.ReactNode } -function Card({title, widthClass='min-w-fit', children}: CardProps) { +function Card({ title, widthClass = 'min-w-fit', children }: CardProps) { return (
{ title &&

{title}

} @@ -13,4 +13,4 @@ function Card({title, widthClass='min-w-fit', children}: CardProps) { ); } -export default Card; \ No newline at end of file +export default Card; diff --git a/rsconcept/frontend/src/components/Common/Checkbox.tsx b/rsconcept/frontend/src/components/Common/Checkbox.tsx index 66fc1940..3fda76c0 100644 --- a/rsconcept/frontend/src/components/Common/Checkbox.tsx +++ b/rsconcept/frontend/src/components/Common/Checkbox.tsx @@ -10,7 +10,7 @@ export interface CheckboxProps { onChange?: (event: React.ChangeEvent) => void } -function Checkbox({id, required, disabled, label, widthClass='w-full', value, onChange}: CheckboxProps) { +function Checkbox({ id, required, disabled, label, widthClass = 'w-full', value, onChange }: CheckboxProps) { return (
- { label &&