diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml index 496b8e434..56c8517f3 100644 --- a/.github/workflows/ci-front.yaml +++ b/.github/workflows/ci-front.yaml @@ -145,7 +145,7 @@ jobs: - name: Front / Install Dependencies run: cd front && yarn - name: Front / Run linter - run: cd front && yarn lint --config .eslintrc-ci.js + run: cd front && yarn lint --config .eslintrc-ci.cjs front-jest: needs: front-yarn-install runs-on: ubuntu-latest diff --git a/.vscode/settings.json b/.vscode/settings.json index 3f4b28eeb..c33ef9aea 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -38,5 +38,11 @@ "cSpell.words": [ "twentyhq" ], - "typescript.preferences.importModuleSpecifier": "non-relative" + "typescript.preferences.importModuleSpecifier": "non-relative", + "[javascript][typescript][typescriptreact]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.addMissingImports": "always" + } + } } \ No newline at end of file diff --git a/front/.eslintrc-ci.js b/front/.eslintrc-ci.cjs similarity index 84% rename from front/.eslintrc-ci.js rename to front/.eslintrc-ci.cjs index 53a455b90..9d6e8e979 100644 --- a/front/.eslintrc-ci.js +++ b/front/.eslintrc-ci.cjs @@ -8,7 +8,7 @@ module.exports = { }, ], extends: [ - './.eslintrc.js' + './.eslintrc.cjs' ], rules: { 'no-console': 'error', diff --git a/front/.eslintrc.js b/front/.eslintrc.cjs similarity index 57% rename from front/.eslintrc.js rename to front/.eslintrc.cjs index d431859be..b9f9d2051 100644 --- a/front/.eslintrc.js +++ b/front/.eslintrc.cjs @@ -1,37 +1,118 @@ module.exports = { parser: '@typescript-eslint/parser', - parserOptions: { - project: 'tsconfig.json', - tsconfigRootDir: __dirname, - sourceType: 'module', - ecmaVersion: "2023" - }, - plugins: [ - '@typescript-eslint/eslint-plugin', - 'unused-imports', - 'simple-import-sort', - 'prefer-arrow', - 'import', - 'twenty', - ], - extends: [ - 'plugin:@typescript-eslint/recommended', - 'plugin:prettier/recommended', - 'plugin:storybook/recommended', - 'plugin:react/recommended', - 'plugin:react-hooks/recommended', - ], root: true, env: { + browser: true, node: true, jest: true, }, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json', './tsconfig.node.json'], + tsconfigRootDir: __dirname, + }, + rules: { + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'off', + 'simple-import-sort/imports': 'error', + 'simple-import-sort/exports': 'error', + 'twenty/effect-components': 'error', + 'twenty/no-hardcoded-colors': 'error', + 'twenty/matching-state-variable': 'error', + 'twenty/component-props-naming': 'error', + 'twenty/sort-css-properties-alphabetically': 'error', + 'twenty/styled-components-prefixed-with-styled': 'error', + 'twenty/no-state-useref': 'error', + 'func-style': ['error', 'declaration', { allowArrowFunctions: true }], + 'no-unused-vars': 'off', + 'react/jsx-props-no-spreading': [ + 'error', + { + explicitSpread: 'ignore', + }, + ], + 'react-hooks/exhaustive-deps': [ + 'warn', + { + additionalHooks: 'useRecoilCallback', + }, + ], + 'unused-imports/no-unused-imports': 'warn', + 'unused-imports/no-unused-vars': [ + 'warn', + { + vars: 'all', + varsIgnorePattern: '^_', + args: 'after-used', + argsIgnorePattern: '^_', + }, + ], + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['@tabler/icons-react'], + message: 'Icon imports are only allowed for `@/ui/icon`', + }, + { + group: ['react-hotkeys-web-hook'], + importNames: ['useHotkeys'], + message: 'Please use the custom wrapper: `useScopedHotkeys`', + }, + ], + }, + ], + '@typescript-eslint/consistent-type-imports': [ + 'error', + { prefer: 'no-type-imports' }, + ], + 'no-console': ['warn', { allow: ['group', 'groupCollapsed', 'groupEnd'] }], + // 'react-refresh/only-export-components': [ + // 'warn', + // { allowConstantExport: true }, + // ], + }, + settings: { + react: { + version: 'detect', + }, + }, + extends: [ + 'plugin:@typescript-eslint/recommended', + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + 'plugin:prettier/recommended', + 'plugin:storybook/recommended', + ], + plugins: [ + '@typescript-eslint/eslint-plugin', + 'simple-import-sort', + 'unused-imports', + 'prefer-arrow', + 'twenty', + 'react-refresh', + ], + ignorePatterns: [ + 'mockServiceWorker.js', + '**/generated*/*', + '.eslintrc.cjs', + '*.config.cjs', + '*.config.ts', + '*config.js', + 'codegen*', + ], overrides: [ { files: ['*.stories.tsx', '*.test.ts'], rules: { 'no-console': 'off', - } + }, }, { files: ['*.js', '*.jsx', '*.ts', '*.tsx'], @@ -43,7 +124,7 @@ module.exports = { 'react/jsx-uses-react': 'off', 'react/react-in-jsx-scope': 'off', 'no-control-regex': 0, - 'import/no-duplicates': ["error", {"considerQueryString": true}], + 'no-undef': 'off', 'simple-import-sort/imports': [ 'error', { @@ -53,76 +134,19 @@ module.exports = { ['^\\u0000'], ['^\\.\\.(?!/?$)', '^\\.\\./?$'], ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'], - ['^.+\\.?(css)$'] - ] - } + ['^.+\\.?(css)$'], + ], + }, ], 'prefer-arrow/prefer-arrow-functions': [ 'error', { - "disallowPrototype": true, - "singleReturnOnly": false, - "classPropertiesAllowed": false - } - ] - } - }, - ], - ignorePatterns: ['.eslintrc.js', 'codegen*.js', '**/generated*/*', '*.config.js'], - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error', - 'twenty/effect-components': 'error', - 'twenty/no-hardcoded-colors': 'error', - 'twenty/matching-state-variable': 'error', - 'twenty/component-props-naming': 'error', - 'twenty/sort-css-properties-alphabetically': 'error', - 'twenty/styled-components-prefixed-with-styled': 'error', - 'twenty/no-state-useref': 'error', - 'func-style':['error', 'declaration', { 'allowArrowFunctions': true }], - "@typescript-eslint/no-unused-vars": "off", - "no-unused-vars": "off", - "react/jsx-props-no-spreading": [ - "error", { - "explicitSpread": "ignore", - } - ], - "react-hooks/exhaustive-deps": [ - "warn", { - "additionalHooks": "useRecoilCallback" - } - ], - "unused-imports/no-unused-imports": "warn", - "unused-imports/no-unused-vars": [ - "warn", - { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" } - ], - 'no-restricted-imports': [ - 'error', - { - 'patterns': [ - { - 'group': ['@tabler/icons-react'], - 'message': 'Icon imports are only allowed for `@/ui/icon`', - }, - { - 'group': ['react-hotkeys-web-hook'], - "importNames": ["useHotkeys"], - 'message': 'Please use the custom wrapper: `useScopedHotkeys`', + disallowPrototype: true, + singleReturnOnly: false, + classPropertiesAllowed: false, }, ], }, - ], - "@typescript-eslint/consistent-type-imports": ["error", { "prefer": "no-type-imports" }], - 'no-console': ['warn', { allow: ['group', 'groupCollapsed', 'groupEnd'] }], - }, - settings: { - "react": { - "version": "detect" - } - } + }, + ], }; diff --git a/front/.gitignore b/front/.gitignore index ea617b5d6..00cb9385c 100644 --- a/front/.gitignore +++ b/front/.gitignore @@ -1,7 +1,15 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* # dependencies /node_modules +/coverage* /.pnp .pnp.js @@ -12,16 +20,22 @@ build-storybook.log # production /build +dist +dist-ssr -# misc -.DS_Store +# env .env.local .env.development.local .env.test.local .env.production.local -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -.nyc_output +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/front/.prettierignore b/front/.prettierignore new file mode 100644 index 000000000..48f48cec2 --- /dev/null +++ b/front/.prettierignore @@ -0,0 +1,3 @@ +**/generated*/ +*.lock +*.yaml \ No newline at end of file diff --git a/front/.prettierrc b/front/.prettierrc index 9d36f26d8..4510dc5c8 100644 --- a/front/.prettierrc +++ b/front/.prettierrc @@ -2,4 +2,4 @@ "singleQuote": true, "trailingComma": "all", "endOfLine": "auto" -} \ No newline at end of file +} diff --git a/front/.storybook/main.js b/front/.storybook/main.js deleted file mode 100644 index 699315238..000000000 --- a/front/.storybook/main.js +++ /dev/null @@ -1,94 +0,0 @@ -const path = require('path'); - -computeStoriesGlob = () => { - if (process.env.STORYBOOK_SCOPE === 'pages') { - return [ - '../src/pages/**/*.stories.@(js|jsx|ts|tsx)', - '../src/__stories__/*.stories.@(js|jsx|ts|tsx)', - '../src/pages/**/*.docs.mdx', - '../src/__stories__/*.docs.mdx' - ] - } - - if (process.env.STORYBOOK_SCOPE === 'modules') { - return ['../src/modules/**/*.stories.@(js|jsx|ts|tsx)', '../src/modules/**/*.docs.mdx'] - } - - if (process.env.STORYBOOK_SCOPE === 'ui-docs') { - return ['../src/modules/ui/**/*.docs.mdx']; - } - - return ['../src/**/*.stories.@(js|jsx|ts|tsx)', '../src/**/*.docs.mdx'] -}; - -module.exports = { - webpackFinal: (config) => { - config.module.rules.push({ - test: /\.tsx?$/, - exclude: /node_modules/, - use: [ - { - loader: require.resolve('babel-loader'), - options: { - presets: [ - require('@babel/preset-typescript').default, - [ - require('@babel/preset-react').default, - { - runtime: 'automatic', - }, - ], - require('@babel/preset-env').default, - ], - }, - }, - ], - }); - config.resolve.extensions.push('.ts', '.tsx'); - config.module.rules.push({ - test: /\.mjs$/, - include: /node_modules/, - type: 'javascript/auto', - }); - config.module.rules.push({ - test: /\.svg$/, - use: [ - { - loader: '@svgr/webpack', - }, - { - loader: 'file-loader', - options: { - name: 'static/media/[path][name].[ext]', - }, - }, - ], - type: 'javascript/auto', - issuer: { - and: [/\.(ts|tsx|js|jsx|md|mdx)$/], - }, - }); - config.resolve.extensions.push('.mjs'); - config.resolve.alias = { - ...config.resolve.alias, - '~': path.resolve(__dirname, '../src'), - '@': path.resolve(__dirname, '../src/modules'), - }; - return config; - }, - stories: computeStoriesGlob(), - addons: [ - '@storybook/addon-links', - '@storybook/addon-essentials', - '@storybook/addon-interactions', - '@storybook/addon-coverage', - '@storybook/addon-styling', - 'storybook-addon-pseudo-states', - 'storybook-addon-cookie', - ], - docs: { autodocs: false }, - framework: { - name: '@storybook/react-webpack5', - options: {}, - }, -}; diff --git a/front/.storybook/main.ts b/front/.storybook/main.ts new file mode 100644 index 000000000..ccc903898 --- /dev/null +++ b/front/.storybook/main.ts @@ -0,0 +1,45 @@ +import type { StorybookConfig } from '@storybook/react-vite'; + +const computeStoriesGlob = () => { + if (process.env.STORYBOOK_SCOPE === 'pages') { + return [ + '../src/pages/**/*.stories.@(js|jsx|ts|tsx)', + '../src/__stories__/*.stories.@(js|jsx|ts|tsx)', + '../src/pages/**/*.docs.mdx', + '../src/__stories__/*.docs.mdx' + ] + } + + if (process.env.STORYBOOK_SCOPE === 'modules') { + return ['../src/modules/**/*.stories.@(js|jsx|ts|tsx)', '../src/modules/**/*.docs.mdx'] + } + + if (process.env.STORYBOOK_SCOPE === 'ui-docs') { + return ['../src/modules/ui/**/*.docs.mdx']; + } + + return ['../src/**/*.docs.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'] +}; + +const config: StorybookConfig = { + stories: computeStoriesGlob(), + staticDirs: ['../public'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-onboarding', + '@storybook/addon-interactions', + '@storybook/addon-coverage', + '@storybook/addon-themes', + 'storybook-addon-cookie', + 'storybook-addon-pseudo-states', + ], + framework: { + name: '@storybook/react-vite', + options: {}, + }, + docs: { + autodocs: false, + }, +}; +export default config; diff --git a/front/.storybook/preview-head.html b/front/.storybook/preview-head.html index b846fe879..06bfbae2f 100644 --- a/front/.storybook/preview-head.html +++ b/front/.storybook/preview-head.html @@ -2,7 +2,12 @@ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet" /> + + +