diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..b9470778 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ diff --git a/.eslintrc.js b/.eslintrc.js index 4b1f140f..b1a39d9e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,27 +1,212 @@ +// eslint-disable-next-line no-undef module.exports = { - "env": { - "browser": true, - "es2021": true + env: { + browser: true, + es2021: true }, - "extends": [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:@typescript-eslint/recommended" + extends: [ + // 'standard', + 'eslint:recommended', + //'plugin:@eslint-community/eslint-comments/recommended', + //'plugin:@typescript-eslint/recommended', + //'plugin:import/recommended', + //'plugin:import/typescript', + //'plugin:promise/recommended', + //'plugin:security/recommended-legacy', + 'plugin:react/recommended', ], - "overrides": [ - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" + parserOptions: { + ecmaVersion: 'latest', + parser: '@typescript-eslint/parser', + sourceType: 'module', }, - "plugins": [ - "react", - "react-hooks", - "@typescript-eslint" + plugins: [ + //'@typescript-eslint', + //'import', + //'promise', + //'security', + //'no-catch-all', + 'react', + 'react-hooks', ], - "rules": { - "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks - "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies - } + settings: { + //'import/resolver': { + // typescript: true, + // node: true, + //}, + 'react': { + 'version': 'detect' + } + }, + rules: { + 'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks + 'react-hooks/exhaustive-deps': 'warn', // Checks effect dependencies + 'react/react-in-jsx-scope': 'off' // Disable requirement for React import + // 'no-catch-all/no-catch-all': 'error', + // 'no-console': 'error', + // 'no-debugger': 'error', + // camelcase: 'error', + // indent: ['error', 2], + // 'linebreak-style': ['error', 'unix'], + // semi: ['error', 'never'], + // // This makes sure our vike router does not throw errors + // 'vue/multi-word-component-names': [ + // 'error', + // { + // ignores: ['+Page'], + // }, + // ], + // // Optional eslint-comments rule + // '@eslint-community/eslint-comments/no-unused-disable': 'error', + // '@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }], + // // import + // 'import/export': 'error', + // 'import/no-deprecated': 'error', + // 'import/no-empty-named-blocks': 'error', + // 'import/no-extraneous-dependencies': 'error', + // 'import/no-mutable-exports': 'error', + // 'import/no-unused-modules': 'error', + // 'import/no-named-as-default': 'error', + // 'import/no-named-as-default-member': 'error', + // 'import/no-amd': 'error', + // 'import/no-commonjs': 'error', + // 'import/no-import-module-exports': 'error', + // 'import/no-nodejs-modules': 'off', + // 'import/unambiguous': 'off', // not compatible with scriptless vue files + // 'import/default': 'error', + // 'import/named': 'error', + // 'import/namespace': 'error', + // 'import/no-absolute-path': 'error', + // 'import/no-cycle': 'error', + // 'import/no-dynamic-require': 'error', + // 'import/no-internal-modules': 'off', + // 'import/no-relative-packages': 'error', + // 'import/no-relative-parent-imports': [ + // 'error', + // { + // ignore: [ + // '#[src,root,components,pages,assets,layouts,queries,stores,plugins,context,types]/*', + // ], + // }, + // ], + // 'import/no-self-import': 'error', + // 'import/no-unresolved': 'error', + // 'import/no-useless-path-segments': 'error', + // 'import/no-webpack-loader-syntax': 'error', + // 'import/consiste@typescript-eslint + // { + // json: 'always', + // }, + // ], + // 'import/first': 'error', + // 'import/group-exports': 'off', + // 'import/newline-after-import': 'error', + // 'import/no-anonymous-default-export': 'off', // todo - consider to enable again + // 'import/no-default-export': 'off', // incompatible with vite & vike + // 'import/no-duplicates': 'error', + // 'import/no-named-default': 'error', + // 'import/no-namespace': 'error', + // 'import/no-unassigned-import': 'error', + // 'import/order': [ + // 'error', + // { + // groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], + // 'newlines-between': 'always', + // alphabetize: { + // order: 'asc', // sort in ascending order. Options: ["ignore", "asc", "desc"] + // caseInsensitive: true, // ignore case. Options: [true, false] + // }, + // distinctGroup: true, + // }, + // ], + // 'import/prefer-default-export': 'off', + // // promise + // 'promise/catch-or-return': 'error', + // 'promise/no-return-wrap': 'error', + // 'promise/param-names': 'error', + // 'promise/always-return': 'error', + // 'promise/no-native': 'off', + // 'promise/no-nesting': 'warn', + // 'promise/no-promise-in-callback': 'warn', + // 'promise/no-callback-in-promise': 'warn', + // 'promise/avoid-new': 'warn', + // 'promise/no-new-statics': 'error', + // 'promise/no-return-in-finally': 'warn', + // 'promise/valid-params': 'warn', + // 'promise/prefer-await-to-callbacks': 'error', + // 'promise/no-multiple-resolved': 'error', + }, + overrides: [ + { + files: ['*.ts', '*.tsx'], + parser: '@typescript-eslint/parser', + // parserOptions: { + // tsconfigRootDir: __dirname, + // project: ['./tsconfig.json', '**/tsconfig.json'], + // ecmaVersion: 'latest', + // parser: '@typescript-eslint/parser', + // sourceType: 'module', + // }, + // plugins: ['@typescript-eslint'], + // extends: [ + // 'plugin:@typescript-eslint/recommended', + // 'plugin:@typescript-eslint/recommended-requiring-type-checking', + // 'plugin:@typescript-eslint/strict', + // ], + // rules: { + // // allow explicitly defined dangling promises + // '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }], + // 'no-void': ['error', { allowAsStatement: true }], + // }, + // }, + // { + // files: ['!*.json'], + // plugins: ['prettier'], + // extends: ['plugin:prettier/recommended'], + // rules: { + // 'prettier/prettier': 'error', + // }, + }, + { + files: ['*.json'], + plugins: ['json'], + extends: ['plugin:json/recommended-with-comments'], + }, + // { + // files: ['*.{test,spec}.[tj]s'], + // plugins: ['vitest'], + // extends: ['plugin:vitest/all'], + // rules: { + // 'vitest/prefer-lowercase-title': 'off', + // 'vitest/no-hooks': 'off', + // 'vitest/consistent-test-filename': 'off', + // 'vitest/prefer-expect-assertions': [ + // 'off', + // { + // onlyFunctionsWithExpectInLoop: true, + // onlyFunctionsWithExpectInCallback: true, + // }, + // ], + // 'vitest/prefer-strict-equal': 'off', + // 'vitest/prefer-to-be-falsy': 'off', + // 'vitest/prefer-to-be-truthy': 'off', + // 'vitest/require-hook': [ + // 'error', + // { + // allowedFunctionCalls: [ + // 'mockClient.setRequestHandler', + // 'setActivePinia', + // 'provideApolloClient', + // ], + // }, + // ], + // }, + // }, + { + files: ['*.yaml', '*.yml'], + parser: 'yaml-eslint-parser', + plugins: ['yml'], + extends: ['plugin:yml/prettier'], + }, + ], } diff --git a/.github/workflows/test.build.yml b/.github/workflows/test.build.yml new file mode 100644 index 00000000..336ef680 --- /dev/null +++ b/.github/workflows/test.build.yml @@ -0,0 +1,33 @@ +name: build + +on: push + +jobs: + files-changed: + name: Detect File Changes - build + runs-on: ubuntu-latest + outputs: + build: ${{ steps.filter.outputs.build }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + id: filter + with: + filters: | + build: + - '.github/workflows/**/*' + - 'src/**/*' + + build: + if: needs.files-changed.outputs.build == 'true' + name: Build + needs: files-changed + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7 + - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.0.3 + with: + node-version-file: './.tool-versions' + - name: Build + run: npm install && npm run build + working-directory: ./ diff --git a/package-lock.json b/package-lock.json index 4ed638a7..392c2484 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,8 +39,10 @@ "autoprefixer": "^10.4.14", "daisyui": "^4.6.1", "eslint": "^8.24.0", + "eslint-plugin-json": "^3.1.0", "eslint-plugin-react": "^7.31.8", "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-yml": "^1.14.0", "postcss": "^8.4.21", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -1650,6 +1652,49 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-compat-utils/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-json": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-3.1.0.tgz", + "integrity": "sha512-MrlG2ynFEHe7wDGwbUuFPsaT2b1uhuEFhJ+W1f1u+1C2EkXmTYJp4B1aAdQQ8M+CC3t//N/oRKiIVw14L2HR1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "vscode-json-languageservice": "^4.1.6" + }, + "engines": { + "node": ">=12.0" + } + }, "node_modules/eslint-plugin-react": { "version": "7.31.8", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", @@ -1719,6 +1764,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-yml": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-1.14.0.tgz", + "integrity": "sha512-ESUpgYPOcAYQO9czugcX5OqRvn/ydDVwGCPXY4YjPqc09rHaUVUA6IE6HLQys4rXk/S+qx3EwTd1wHCwam/OWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.2", + "eslint-compat-utils": "^0.5.0", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "yaml-eslint-parser": "^1.2.1" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -2891,6 +2959,13 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -2981,6 +3056,13 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -5998,6 +6080,48 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vscode-json-languageservice": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz", + "integrity": "sha512-xGmv9QIWs2H8obGbWg+sIPI/3/pFgj/5OWBhNzs00BkYQ9UaB2F6JJaGB/2/YOZJ3BvLXQTC4Q7muqU25QgAhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-languageserver-textdocument": "^1.0.3", + "vscode-languageserver-types": "^3.16.0", + "vscode-nls": "^5.0.0", + "vscode-uri": "^3.0.3" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-nls": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", + "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true, + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6057,6 +6181,37 @@ "node": ">= 6" } }, + "node_modules/yaml-eslint-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.2.3.tgz", + "integrity": "sha512-4wZWvE398hCP7O8n3nXKu/vdq1HcH01ixYlCREaJL5NUMwQ0g3MaGFUBNSlmBtKmhbtVG/Cm6lyYmSVTEVil8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.0.0", + "lodash": "^4.17.21", + "yaml": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/yaml-eslint-parser/node_modules/yaml": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 977e88ea..1aeb9779 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,10 @@ "autoprefixer": "^10.4.14", "daisyui": "^4.6.1", "eslint": "^8.24.0", + "eslint-plugin-json": "^3.1.0", "eslint-plugin-react": "^7.31.8", "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-yml": "^1.14.0", "postcss": "^8.4.21", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/postcss.config.js b/postcss.config.js index 28d577f0..3bf778b7 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-undef module.exports = { plugins: { tailwindcss: {}, diff --git a/src/Components/AppShell/ContextWrapper.tsx b/src/Components/AppShell/ContextWrapper.tsx index c3fd20cd..01468225 100644 --- a/src/Components/AppShell/ContextWrapper.tsx +++ b/src/Components/AppShell/ContextWrapper.tsx @@ -17,12 +17,14 @@ import { BrowserRouter as Router, useLocation } from 'react-router-dom'; // Helper context to determine if the ContextWrapper is already present. const ContextCheckContext = createContext(false); +// eslint-disable-next-line react/prop-types export const ContextWrapper = ({ children }) => { const isWrapped = useContext(ContextCheckContext); // Check if we are already inside a Router let location; try { + // eslint-disable-next-line react-hooks/rules-of-hooks location = useLocation(); } catch (e) { location = null; @@ -63,6 +65,7 @@ export const ContextWrapper = ({ children }) => { return children; }; +// eslint-disable-next-line react/prop-types export const Wrappers = ({ children }) => { const queryClient = new QueryClient(); diff --git a/src/Components/AppShell/NavBar.tsx b/src/Components/AppShell/NavBar.tsx index 055d9099..e09be0ce 100644 --- a/src/Components/AppShell/NavBar.tsx +++ b/src/Components/AppShell/NavBar.tsx @@ -18,6 +18,7 @@ export default function NavBar({ appName, userType}: { appName: string, userType useEffect(() => { const profile = user && items.find(i => (i.user_created?.id === user.id) && i.layer?.itemType.name === userType); profile ? setUserProfile(profile) : setUserProfile({id: crypto.randomUUID(), name: user?.first_name, text: ""}); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [user, items]) useEffect(() => { @@ -39,8 +40,8 @@ export default function NavBar({ appName, userType}: { appName: string, userType useEffect(() => { - let params = new URLSearchParams(location.search); - let embedded = params.get("embedded"); + const params = new URLSearchParams(location.search); + const embedded = params.get("embedded"); embedded!="true" && setShowNav(true) }, [location]); diff --git a/src/Components/AppShell/SetAssetsApi.tsx b/src/Components/AppShell/SetAssetsApi.tsx index f0f17664..410d3063 100644 --- a/src/Components/AppShell/SetAssetsApi.tsx +++ b/src/Components/AppShell/SetAssetsApi.tsx @@ -7,6 +7,7 @@ export const SetAssetsApi = ({assetsApi}:{assetsApi: AssetsApi}) => { useEffect(() => { setAssetsApi(assetsApi) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [assetsApi]) diff --git a/src/Components/AppShell/SideBar.tsx b/src/Components/AppShell/SideBar.tsx index de9f2c64..7b1754c5 100644 --- a/src/Components/AppShell/SideBar.tsx +++ b/src/Components/AppShell/SideBar.tsx @@ -11,6 +11,7 @@ import * as React from 'react'; type route = { path: string; + // eslint-disable-next-line no-undef icon: JSX.Element; name: string; submenu?: route; @@ -53,12 +54,12 @@ export function SideBar({ routes, bottomRoutes }: { routes: route[], bottomRoute useEffect(() => { - let params = new URLSearchParams(location.search); - let embedded = params.get("embedded"); + const params = new URLSearchParams(location.search); + const embedded = params.get("embedded"); embedded != "true" && setEmbedded(false) }, [location]); - let params = new URLSearchParams(window.location.search); + const params = new URLSearchParams(window.location.search); return (