feat: enforce @/ alias for imports and fix all relative parent imports (#16787)

## Summary
This PR enforces the use of `@/` alias for imports instead of relative
parent imports (`../`).

## Changes

### ESLint Configuration
- Added `no-restricted-imports` pattern in `eslint.config.react.mjs` to
block `../*` imports with the message "Relative parent imports are not
allowed. Use @/ alias instead."
- Removed the non-working `import/no-relative-parent-imports` rule
(doesn't work properly in ESLint flat config)

### VS Code Settings
- Added `javascript.preferences.importModuleSpecifier: non-relative` to
`.vscode/settings.json` (TypeScript setting was already there)

### Code Fixes
- Fixed **941 relative parent imports** across **706 files** in
`packages/twenty-front`
- All `../` imports converted to use `@/` alias

## Why
- Consistent import style across the codebase
- Easier to move files without breaking imports
- Better IDE support for auto-imports
- Clearer understanding of where imports come from
This commit is contained in:
Félix Malfait
2025-12-23 22:57:51 +01:00
committed by GitHub
parent 781b96e80b
commit b27a97f2c5
725 changed files with 1114 additions and 1041 deletions
@@ -25,8 +25,8 @@ import {
type IconButtonVariant,
LightIconButton,
} from 'twenty-ui/input';
import { IconPickerScrollEffect } from '../hooks/IconPickerScrollEffect';
import { iconPickerVisibleCountState } from '../states/iconPickerVisibleCountState';
import { IconPickerScrollEffect } from '@/ui/input/hooks/IconPickerScrollEffect';
import { iconPickerVisibleCountState } from '@/ui/input/states/iconPickerVisibleCountState';
export type IconPickerProps = {
disabled?: boolean;
@@ -7,7 +7,10 @@ import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecora
import { sleep } from '~/utils/sleep';
import { ComponentDecorator } from 'twenty-ui/testing';
import { IconPicker, type IconPickerProps } from '../IconPicker';
import {
IconPicker,
type IconPickerProps,
} from '@/ui/input/components/IconPicker';
type RenderProps = IconPickerProps;
const Render = (args: RenderProps) => {
@@ -3,7 +3,7 @@ import { type Meta, type StoryObj } from '@storybook/react';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { workspaceLogoUrl } from '~/testing/mock-data/users';
import { ImageInput } from '../ImageInput';
import { ImageInput } from '@/ui/input/components/ImageInput';
import { ComponentDecorator } from 'twenty-ui/testing';
const meta: Meta<typeof ImageInput> = {
@@ -4,7 +4,7 @@ import { useState } from 'react';
import { IconPlus } from 'twenty-ui/display';
import { ComponentDecorator } from 'twenty-ui/testing';
import { Select, type SelectProps } from '../Select';
import { Select, type SelectProps } from '@/ui/input/components/Select';
type RenderProps = SelectProps<string | number | boolean | null>;
@@ -2,7 +2,7 @@ import { type Meta, type StoryObj } from '@storybook/react';
import { useState } from 'react';
import { expect, userEvent, within } from '@storybook/test';
import { TextArea, type TextAreaProps } from '../TextArea';
import { TextArea, type TextAreaProps } from '@/ui/input/components/TextArea';
import { ComponentDecorator } from 'twenty-ui/testing';
type RenderProps = TextAreaProps;
@@ -3,7 +3,7 @@ import { type Meta, type StoryObj } from '@storybook/react';
import { expect, userEvent, within } from '@storybook/test';
import { Temporal } from 'temporal-polyfill';
import { ComponentDecorator } from 'twenty-ui/testing';
import { DateTimePicker } from '../DateTimePicker';
import { DateTimePicker } from '@/ui/input/components/internal/date/components/DateTimePicker';
const meta: Meta<typeof DateTimePicker> = {
title: 'UI/Input/Internal/InternalDatePicker',
@@ -1,5 +1,5 @@
import type { PartialBlock } from '@blocknote/core';
import { getFirstNonEmptyLineOfRichText } from '../getFirstNonEmptyLineOfRichText';
import { getFirstNonEmptyLineOfRichText } from '@/ui/input/editor/utils/getFirstNonEmptyLineOfRichText';
describe('getFirstNonEmptyLineOfRichText', () => {
it('should return an empty string if the input is null', () => {
@@ -1,4 +1,4 @@
import { parseInitialBlocknote } from '../parseInitialBlocknote';
import { parseInitialBlocknote } from '@/ui/input/editor/utils/parseInitialBlocknote';
describe('parseInitialBlocknote', () => {
it('should parse valid JSON array string', () => {
@@ -1,4 +1,4 @@
import { prepareBodyWithSignedUrls } from '../prepareBodyWithSignedUrls';
import { prepareBodyWithSignedUrls } from '@/ui/input/editor/utils/prepareBodyWithSignedUrls';
describe('prepareBodyWithSignedUrls', () => {
it('should return empty string as-is', () => {
@@ -1,7 +1,7 @@
import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement';
import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { iconPickerVisibleCountState } from '../states/iconPickerVisibleCountState';
import { iconPickerVisibleCountState } from '@/ui/input/states/iconPickerVisibleCountState';
type IconPickerScrollEffectProps = {
sentinelId: string;
@@ -1,6 +1,6 @@
import { useRecoilState } from 'recoil';
import { iconPickerState } from '../states/iconPickerState';
import { iconPickerState } from '@/ui/input/states/iconPickerState';
export const useIconPicker = () => {
const [iconPicker, setIconPicker] = useRecoilState(iconPickerState);