diff --git a/.eslintrc.react.cjs b/.eslintrc.react.cjs index ce434e84d..680ad3b45 100644 --- a/.eslintrc.react.cjs +++ b/.eslintrc.react.cjs @@ -6,8 +6,71 @@ module.exports = { 'plugin:react/recommended', 'plugin:react-hooks/recommended', 'plugin:storybook/recommended', + 'plugin:prettier/recommended', + 'plugin:lingui/recommended', + 'plugin:@nx/typescript' ], - plugins: ['react-hooks', 'react-refresh'], + plugins: ['react-hooks', 'react-refresh', '@nx', 'prefer-arrow', 'import', 'unused-imports', 'unicorn', 'lingui'], + rules: { + 'lingui/no-single-variables-to-translate': 'off', + 'func-style': ['error', 'declaration', { allowArrowFunctions: true }], + 'no-console': ['warn', { allow: ['group', 'groupCollapsed', 'groupEnd'] }], + 'no-control-regex': 0, + 'no-debugger': 'error', + 'no-duplicate-imports': 'error', + 'no-undef': 'off', + 'no-unused-vars': 'off', + + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: 'scope:shared', + onlyDependOnLibsWithTags: ['scope:shared'], + }, + { + sourceTag: 'scope:backend', + onlyDependOnLibsWithTags: ['scope:shared', 'scope:backend'], + }, + { + sourceTag: 'scope:frontend', + onlyDependOnLibsWithTags: ['scope:shared', 'scope:frontend'], + }, + { + sourceTag: 'scope:zapier', + onlyDependOnLibsWithTags: ['scope:shared'], + }, + ], + }, + ], + + 'import/no-relative-packages': 'error', + 'import/no-useless-path-segments': 'error', + 'import/no-duplicates': ['error', { considerQueryString: true }], + + 'prefer-arrow/prefer-arrow-functions': [ + 'error', + { + disallowPrototype: true, + singleReturnOnly: false, + classPropertiesAllowed: false, + }, + ], + + 'unused-imports/no-unused-imports': 'warn', + 'unused-imports/no-unused-vars': [ + 'warn', + { + vars: 'all', + varsIgnorePattern: '^_', + args: 'after-used', + argsIgnorePattern: '^_', + }, + ], + }, overrides: [ { files: ['**/*.ts', '**/*.tsx'], @@ -34,6 +97,14 @@ module.exports = { ], }, ], + '@typescript-eslint/no-empty-interface': [ + 'error', + { + allowSingleExtends: true, + }, + ], + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-explicit-any': 'off', '@nx/workspace-effect-components': 'error', '@nx/workspace-no-hardcoded-colors': 'error', '@nx/workspace-matching-state-variable': 'error', @@ -83,5 +154,46 @@ module.exports = { ], }, }, + { + files: ['*.js', '*.jsx'], + extends: ['plugin:@nx/javascript'], + rules: {}, + }, + { + files: [ + '*.test.@(ts|tsx|js|jsx)', + ], + env: { + jest: true, + }, + rules: { + '@typescript-eslint/no-non-null-assertion': 'off', + }, + }, + { + files: ['**/*.constants.ts'], + rules: { + '@typescript-eslint/naming-convention': [ + 'error', + { + selector: 'variable', + format: ['UPPER_CASE'], + }, + ], + 'unicorn/filename-case': [ + 'warn', + { + cases: { + pascalCase: true, + }, + }, + ], + '@nx/workspace-max-consts-per-file': ['error', { max: 1 }], + }, + }, + { + files: ['*.json'], + parser: 'jsonc-eslint-parser', + }, ], }; diff --git a/packages/twenty-front/.env.example b/packages/twenty-front/.env.example index 718963811..381ac3fa1 100644 --- a/packages/twenty-front/.env.example +++ b/packages/twenty-front/.env.example @@ -1,5 +1,6 @@ REACT_APP_SERVER_BASE_URL=http://localhost:3000 VITE_BUILD_SOURCEMAP=false +VITE_DISABLE_ESLINT_CHECKER=true # ———————— Optional ———————— diff --git a/packages/twenty-front/.eslintrc.cjs b/packages/twenty-front/.eslintrc.cjs index 5f695e56e..a8a5418d5 100644 --- a/packages/twenty-front/.eslintrc.cjs +++ b/packages/twenty-front/.eslintrc.cjs @@ -1,19 +1,22 @@ const path = require('path'); module.exports = { - extends: ['../../.eslintrc.global.cjs', '../../.eslintrc.react.cjs'], + extends: ['../../.eslintrc.react.cjs'], ignorePatterns: [ 'node_modules', 'mockServiceWorker.js', '**/generated*/*', '**/generated/standard-metadata-query-result.ts', - 'tsup.config.ts', 'build', 'coverage', 'storybook-static', '**/*config.js', + 'jest.config.ts', + 'emotion.d.ts', + 'lingui.config.ts', + 'vite.config.ts', + 'setupTests.ts', 'codegen*', - 'tsup.ui.index.tsx', '__mocks__', ], overrides: [ @@ -22,66 +25,6 @@ module.exports = { parserOptions: { project: ['packages/twenty-front/tsconfig.*.json'], }, - // plugins: ['project-structure'], - settings: { - // 'project-structure/folder-structure-config-path': path.join( - // __dirname, - // 'folderStructure.json', - // ), - }, - rules: { - // 'project-structure/folder-structure': 'error', - /* - Uncomment this rule when we have a way to work on - 'lingui/no-unlocalized-strings': [ - 'error', - { - ignore: [ - '^(?![A-Z])\\S+$', - '^[A-Z0-9_-]+$' - ], - ignoreNames: [ - { regex: { pattern: 'className', flags: 'i' } }, - { regex: { pattern: '^[A-Z0-9_-]+$' } }, - 'styleName', - 'src', - 'srcSet', - 'type', - 'id', - 'width', - 'height', - 'displayName', - 'Authorization' - ], - ignoreFunctions: [ - 'cva', - 'cn', - 'track', - 'Error', - 'console.*', - '*headers.set', - '*.addEventListener', - '*.removeEventListener', - '*.postMessage', - '*.getElementById', - '*.dispatch', - '*.commit', - '*.includes', - '*.indexOf', - '*.endsWith', - '*.startsWith', - 'require' - ], - useTsTypes: true, - ignoreMethodsOnTypes: [ - 'Map.get', - 'Map.has', - 'Set.has' - ] - } - ] - */ - }, }, ], }; diff --git a/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptions.ts b/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptions.ts index 01e71a5aa..548b8261e 100644 --- a/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptions.ts +++ b/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptions.ts @@ -1,4 +1,3 @@ -/* eslint-disable @nx/workspace-max-consts-per-file */ import { getTimezoneOffset } from 'date-fns-tz'; import { AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL } from '@/settings/accounts/constants/AvailableTimezoneOptionsByLabel'; @@ -6,7 +5,6 @@ import { AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL } from '@/settings/accounts/consta export const AVAILABLE_TIMEZONE_OPTIONS = Object.values( AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL, ).sort((optionA, optionB) => { - // eslint-disable-next-line @typescript-eslint/naming-convention const difference = getTimezoneOffset(optionA.value) - getTimezoneOffset(optionB.value); diff --git a/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptionsByLabel.ts b/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptionsByLabel.ts index 8e8f3b706..a2108414b 100644 --- a/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptionsByLabel.ts +++ b/packages/twenty-front/src/modules/settings/accounts/constants/AvailableTimezoneOptionsByLabel.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable @nx/workspace-max-consts-per-file */ import { IANA_TIME_ZONES } from '@/localization/constants/IanaTimeZones'; import { formatTimeZoneLabel } from '@/localization/utils/formatTimeZoneLabel'; import { SelectOption } from 'twenty-ui/input'; diff --git a/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentSelect.stories.tsx b/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentSelect.stories.tsx index 914715abd..fbd89654b 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentSelect.stories.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentSelect.stories.tsx @@ -3,7 +3,6 @@ import { Select, SelectValue } from '@/ui/input/components/Select'; import styled from '@emotion/styled'; import { Meta, StoryObj } from '@storybook/react'; import { useState } from 'react'; -import { ComponentDecorator } from 'twenty-ui/testing'; import { IconLanguage, IconLayoutKanban, @@ -12,6 +11,7 @@ import { IconTable, IconUsers, } from 'twenty-ui/display'; +import { ComponentDecorator } from 'twenty-ui/testing'; const StyledContainer = styled.div` width: 480px; diff --git a/packages/twenty-front/src/modules/ui/field/input/components/CurrencyInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/CurrencyInput.tsx index 140d17037..9b64de53c 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/CurrencyInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/CurrencyInput.tsx @@ -1,18 +1,15 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useEffect, useMemo, useRef, useState } from 'react'; -import { IMaskInput, IMaskInputProps } from 'react-imask'; import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents'; import { SETTINGS_FIELD_CURRENCY_CODES } from '@/settings/data-model/constants/SettingsFieldCurrencyCodes'; import { CurrencyPickerDropdownButton } from '@/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton'; +import { IMaskInput } from 'react-imask'; import { IconComponent } from 'twenty-ui/display'; import { TEXT_INPUT_STYLE } from 'twenty-ui/theme'; -type StyledInputProps = React.ComponentProps<'input'> & - IMaskInputProps; - -export const StyledIMaskInput = styled(IMaskInput)` +export const StyledIMaskInput = styled(IMaskInput)` margin: 0; ${TEXT_INPUT_STYLE} width: 100%; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2.ts index ff3f6ab06..0cef67926 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-redeclare */ /* eslint-disable prefer-arrow/prefer-arrow-functions */ import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { ComponentFamilyReadOnlySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyReadOnlySelectorV2'; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilySelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilySelectorV2.ts index 2fc86e752..49f034bd8 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilySelectorV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentFamilySelectorV2.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-redeclare */ /* eslint-disable prefer-arrow/prefer-arrow-functions */ import { selectorFamily, SerializableParam } from 'recoil'; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelectorV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelectorV2.ts index 2dd4358f9..1d3778d53 100644 --- a/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelectorV2.ts +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/utils/createComponentSelectorV2.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-redeclare */ /* eslint-disable prefer-arrow/prefer-arrow-functions */ import { selectorFamily } from 'recoil';