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
+1
View File
@@ -31,6 +31,7 @@
"editor.formatOnSave": true "editor.formatOnSave": true
}, },
"javascript.format.enable": false, "javascript.format.enable": false,
"javascript.preferences.importModuleSpecifier": "non-relative",
"typescript.format.enable": false, "typescript.format.enable": false,
"cSpell.enableFiletypes": [ "cSpell.enableFiletypes": [
"!javascript", "!javascript",
+2 -2
View File
@@ -137,10 +137,10 @@ export default [
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/interface-name-prefix': 'off', '@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/no-empty-interface': [ '@typescript-eslint/no-empty-object-type': [
'error', 'error',
{ {
allowSingleExtends: true, allowInterfaces: 'with-single-extends',
}, },
], ],
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
+7 -2
View File
@@ -521,6 +521,10 @@ export default [
'error', 'error',
{ {
patterns: [ patterns: [
{
group: ['../*'],
message: 'Relative parent imports are not allowed. Use @/ alias instead.',
},
{ {
group: ['@tabler/icons-react'], group: ['@tabler/icons-react'],
message: 'Please import icons from `twenty-ui`', message: 'Please import icons from `twenty-ui`',
@@ -552,10 +556,10 @@ export default [
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/interface-name-prefix': 'off', '@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/no-empty-interface': [ '@typescript-eslint/no-empty-object-type': [
'error', 'error',
{ {
allowSingleExtends: true, allowInterfaces: 'with-single-extends',
}, },
], ],
'@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-empty-function': 'off',
@@ -689,6 +693,7 @@ export default [
}, },
}, },
// JavaScript specific configuration // JavaScript specific configuration
{ {
files: ['*.{js,jsx}'], files: ['*.{js,jsx}'],
@@ -6,11 +6,11 @@ import {
TIPTAP_MARKS_RENDER_ORDER, TIPTAP_MARKS_RENDER_ORDER,
TIPTAP_MARK_TYPES, TIPTAP_MARK_TYPES,
} from 'twenty-shared/utils'; } from 'twenty-shared/utils';
import { bold } from '../marks/bold'; import { bold } from '@/utils/email-renderer/marks/bold';
import { italic } from '../marks/italic'; import { italic } from '@/utils/email-renderer/marks/italic';
import { link } from '../marks/link'; import { link } from '@/utils/email-renderer/marks/link';
import { strike } from '../marks/strike'; import { strike } from '@/utils/email-renderer/marks/strike';
import { underline } from '../marks/underline'; import { underline } from '@/utils/email-renderer/marks/underline';
const MARK_RENDERERS = { const MARK_RENDERERS = {
[TIPTAP_MARK_TYPES.BOLD]: bold, [TIPTAP_MARK_TYPES.BOLD]: bold,
@@ -1,15 +1,15 @@
import { type JSONContent } from '@tiptap/core'; import { type JSONContent } from '@tiptap/core';
import { Fragment, type ReactNode } from 'react'; import { Fragment, type ReactNode } from 'react';
import { TIPTAP_NODE_TYPES, type TipTapNodeType } from 'twenty-shared/utils'; import { TIPTAP_NODE_TYPES, type TipTapNodeType } from 'twenty-shared/utils';
import { bulletList } from '../nodes/bullet-list'; import { bulletList } from '@/utils/email-renderer/nodes/bullet-list';
import { hardBreak } from '../nodes/hard-break'; import { hardBreak } from '@/utils/email-renderer/nodes/hard-break';
import { heading } from '../nodes/heading'; import { heading } from '@/utils/email-renderer/nodes/heading';
import { image } from '../nodes/image'; import { image } from '@/utils/email-renderer/nodes/image';
import { listItem } from '../nodes/list-item'; import { listItem } from '@/utils/email-renderer/nodes/list-item';
import { orderedList } from '../nodes/ordered-list'; import { orderedList } from '@/utils/email-renderer/nodes/ordered-list';
import { paragraph } from '../nodes/paragraph'; import { paragraph } from '@/utils/email-renderer/nodes/paragraph';
import { text } from '../nodes/text'; import { text } from '@/utils/email-renderer/nodes/text';
import { variableTag } from '../nodes/variable-tag'; import { variableTag } from '@/utils/email-renderer/nodes/variable-tag';
const NODE_RENDERERS = { const NODE_RENDERERS = {
[TIPTAP_NODE_TYPES.PARAGRAPH]: paragraph, [TIPTAP_NODE_TYPES.PARAGRAPH]: paragraph,
+31 -31
View File
@@ -1,37 +1,37 @@
import { setupI18n, type I18n, type Messages } from '@lingui/core'; import { setupI18n, type I18n, type Messages } from '@lingui/core';
import { type APP_LOCALES } from 'twenty-shared/translations'; import { type APP_LOCALES } from 'twenty-shared/translations';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { messages as afMessages } from '../locales/generated/af-ZA'; import { messages as afMessages } from '@/locales/generated/af-ZA';
import { messages as arMessages } from '../locales/generated/ar-SA'; import { messages as arMessages } from '@/locales/generated/ar-SA';
import { messages as caMessages } from '../locales/generated/ca-ES'; import { messages as caMessages } from '@/locales/generated/ca-ES';
import { messages as csMessages } from '../locales/generated/cs-CZ'; import { messages as csMessages } from '@/locales/generated/cs-CZ';
import { messages as daMessages } from '../locales/generated/da-DK'; import { messages as daMessages } from '@/locales/generated/da-DK';
import { messages as deMessages } from '../locales/generated/de-DE'; import { messages as deMessages } from '@/locales/generated/de-DE';
import { messages as elMessages } from '../locales/generated/el-GR'; import { messages as elMessages } from '@/locales/generated/el-GR';
import { messages as enMessages } from '../locales/generated/en'; import { messages as enMessages } from '@/locales/generated/en';
import { messages as esMessages } from '../locales/generated/es-ES'; import { messages as esMessages } from '@/locales/generated/es-ES';
import { messages as fiMessages } from '../locales/generated/fi-FI'; import { messages as fiMessages } from '@/locales/generated/fi-FI';
import { messages as frMessages } from '../locales/generated/fr-FR'; import { messages as frMessages } from '@/locales/generated/fr-FR';
import { messages as heMessages } from '../locales/generated/he-IL'; import { messages as heMessages } from '@/locales/generated/he-IL';
import { messages as huMessages } from '../locales/generated/hu-HU'; import { messages as huMessages } from '@/locales/generated/hu-HU';
import { messages as itMessages } from '../locales/generated/it-IT'; import { messages as itMessages } from '@/locales/generated/it-IT';
import { messages as jaMessages } from '../locales/generated/ja-JP'; import { messages as jaMessages } from '@/locales/generated/ja-JP';
import { messages as koMessages } from '../locales/generated/ko-KR'; import { messages as koMessages } from '@/locales/generated/ko-KR';
import { messages as nlMessages } from '../locales/generated/nl-NL'; import { messages as nlMessages } from '@/locales/generated/nl-NL';
import { messages as noMessages } from '../locales/generated/no-NO'; import { messages as noMessages } from '@/locales/generated/no-NO';
import { messages as plMessages } from '../locales/generated/pl-PL'; import { messages as plMessages } from '@/locales/generated/pl-PL';
import { messages as pseudoEnMessages } from '../locales/generated/pseudo-en'; import { messages as pseudoEnMessages } from '@/locales/generated/pseudo-en';
import { messages as ptBRMessages } from '../locales/generated/pt-BR'; import { messages as ptBRMessages } from '@/locales/generated/pt-BR';
import { messages as ptPTMessages } from '../locales/generated/pt-PT'; import { messages as ptPTMessages } from '@/locales/generated/pt-PT';
import { messages as roMessages } from '../locales/generated/ro-RO'; import { messages as roMessages } from '@/locales/generated/ro-RO';
import { messages as ruMessages } from '../locales/generated/ru-RU'; import { messages as ruMessages } from '@/locales/generated/ru-RU';
import { messages as srMessages } from '../locales/generated/sr-Cyrl'; import { messages as srMessages } from '@/locales/generated/sr-Cyrl';
import { messages as svMessages } from '../locales/generated/sv-SE'; import { messages as svMessages } from '@/locales/generated/sv-SE';
import { messages as trMessages } from '../locales/generated/tr-TR'; import { messages as trMessages } from '@/locales/generated/tr-TR';
import { messages as ukMessages } from '../locales/generated/uk-UA'; import { messages as ukMessages } from '@/locales/generated/uk-UA';
import { messages as viMessages } from '../locales/generated/vi-VN'; import { messages as viMessages } from '@/locales/generated/vi-VN';
import { messages as zhHansMessages } from '../locales/generated/zh-CN'; import { messages as zhHansMessages } from '@/locales/generated/zh-CN';
import { messages as zhHantMessages } from '../locales/generated/zh-TW'; import { messages as zhHantMessages } from '@/locales/generated/zh-TW';
const messages: Record<keyof typeof APP_LOCALES, Messages> = { const messages: Record<keyof typeof APP_LOCALES, Messages> = {
en: enMessages, en: enMessages,
+3
View File
@@ -8,6 +8,9 @@
"strict": true, "strict": true,
"types": ["vite/client"], "types": ["vite/client"],
"baseUrl": ".", "baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}, },
"files": [], "files": [],
"include": ["vite.config.ts"], "include": ["vite.config.ts"],
+5 -3
View File
@@ -4,13 +4,15 @@ import { initialize, mswLoader } from 'msw-storybook-addon';
import { useEffect } from 'react'; import { useEffect } from 'react';
//import { useDarkMode } from 'storybook-dark-mode'; //import { useDarkMode } from 'storybook-dark-mode';
// eslint-disable-next-line no-restricted-imports
import { RootDecorator } from '../src/testing/decorators/RootDecorator'; import { RootDecorator } from '../src/testing/decorators/RootDecorator';
// eslint-disable-next-line no-restricted-imports
import { mockedUserJWT } from '../src/testing/mock-data/jwt'; import { mockedUserJWT } from '../src/testing/mock-data/jwt';
import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
import 'react-loading-skeleton/dist/skeleton.css'; import 'react-loading-skeleton/dist/skeleton.css';
import 'twenty-ui/style.css'; import 'twenty-ui/style.css';
import { THEME_LIGHT, ThemeContextProvider } from 'twenty-ui/theme'; import { THEME_LIGHT, ThemeContextProvider } from 'twenty-ui/theme';
// eslint-disable-next-line no-restricted-imports
import { ClickOutsideListenerContext } from '../src/modules/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
initialize({ initialize({
onUnhandledRequest: async (request: Request) => { onUnhandledRequest: async (request: Request) => {
@@ -29,7 +31,7 @@ initialize({
const requestBody = await request.json(); const requestBody = await request.json();
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.warn(`Unhandled ${request.method} request to ${request.url} console.warn(`Unhandled ${request.method} request to ${request.url}
with payload ${JSON.stringify(requestBody)}\n with payload ${JSON.stringify(requestBody)}\n
This request should be mocked with MSW`); This request should be mocked with MSW`);
} catch (error) { } catch (error) {
@@ -5,7 +5,7 @@ import { getActionLabel } from '@/action-menu/utils/getActionLabel';
import { expect, fn, userEvent, within } from '@storybook/test'; import { expect, fn, userEvent, within } from '@storybook/test';
import { type Meta, type StoryObj } from '@storybook/react'; import { type Meta, type StoryObj } from '@storybook/react';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
import { ActionButton } from '../ActionButton'; import { ActionButton } from '@/action-menu/actions/display/components/ActionButton';
const meta: Meta<typeof ActionButton> = { const meta: Meta<typeof ActionButton> = {
title: 'Modules/ActionMenu/Actions/Display/ActionButton', title: 'Modules/ActionMenu/Actions/Display/ActionButton',
@@ -7,7 +7,7 @@ import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-l
import { expect, fn, userEvent, within } from '@storybook/test'; import { expect, fn, userEvent, within } from '@storybook/test';
import { type Meta, type StoryObj } from '@storybook/react'; import { type Meta, type StoryObj } from '@storybook/react';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
import { ActionDisplay } from '../ActionDisplay'; import { ActionDisplay } from '@/action-menu/actions/display/components/ActionDisplay';
type Story = StoryObj<typeof ActionDisplay>; type Story = StoryObj<typeof ActionDisplay>;
@@ -6,7 +6,7 @@ import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-l
import { expect, fn, userEvent, within } from '@storybook/test'; import { expect, fn, userEvent, within } from '@storybook/test';
import { type Meta, type StoryObj } from '@storybook/react'; import { type Meta, type StoryObj } from '@storybook/react';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
import { ActionDropdownItem } from '../ActionDropdownItem'; import { ActionDropdownItem } from '@/action-menu/actions/display/components/ActionDropdownItem';
const meta: Meta<typeof ActionDropdownItem> = { const meta: Meta<typeof ActionDropdownItem> = {
title: 'Modules/ActionMenu/Actions/Display/ActionDropdownItem', title: 'Modules/ActionMenu/Actions/Display/ActionDropdownItem',
@@ -6,7 +6,7 @@ import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-l
import { expect, fn, userEvent, within } from '@storybook/test'; import { expect, fn, userEvent, within } from '@storybook/test';
import { type Meta, type StoryObj } from '@storybook/react'; import { type Meta, type StoryObj } from '@storybook/react';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
import { ActionListItem } from '../ActionListItem'; import { ActionListItem } from '@/action-menu/actions/display/components/ActionListItem';
type Story = StoryObj<typeof ActionListItem>; type Story = StoryObj<typeof ActionListItem>;
@@ -6,7 +6,7 @@ import { ActionScope } from '@/action-menu/actions/types/ActionScope';
import { ActionType } from '@/action-menu/actions/types/ActionType'; import { ActionType } from '@/action-menu/actions/types/ActionType';
import { type DefaultRecordActionConfigKeys } from '@/action-menu/actions/types/DefaultRecordActionConfigKeys'; import { type DefaultRecordActionConfigKeys } from '@/action-menu/actions/types/DefaultRecordActionConfigKeys';
import { IconHeart, IconPlus } from 'twenty-ui/display'; import { IconHeart, IconPlus } from 'twenty-ui/display';
import { inheritActionsFromDefaultConfig } from '../inheritActionsFromDefaultConfig'; import { inheritActionsFromDefaultConfig } from '@/action-menu/actions/record-actions/utils/inheritActionsFromDefaultConfig';
const MockComponent = <div>Mock Component</div>; const MockComponent = <div>Mock Component</div>;
@@ -3,7 +3,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
import { renderHook } from '@testing-library/react'; import { renderHook } from '@testing-library/react';
import { type ReactNode } from 'react'; import { type ReactNode } from 'react';
import { RecoilRoot } from 'recoil'; import { RecoilRoot } from 'recoil';
import { useRelatedRecordActions } from '../useRelatedRecordActions'; import { useRelatedRecordActions } from '@/action-menu/actions/record-agnostic-actions/hooks/useRelatedRecordActions';
jest.mock('@/object-metadata/hooks/useObjectMetadataItems', () => ({ jest.mock('@/object-metadata/hooks/useObjectMetadataItems', () => ({
useObjectMetadataItems: () => ({ useObjectMetadataItems: () => ({
@@ -1,4 +1,4 @@
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '../getRightDrawerActionMenuDropdownIdFromActionMenuId'; import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
describe('getRightDrawerActionMenuDropdownIdFromActionMenuId', () => { describe('getRightDrawerActionMenuDropdownIdFromActionMenuId', () => {
it('should return the right drawer action menu dropdown id', () => { it('should return the right drawer action menu dropdown id', () => {
@@ -1,6 +1,6 @@
import { BlockNoteSchema, defaultBlockSpecs } from '@blocknote/core'; import { BlockNoteSchema, defaultBlockSpecs } from '@blocknote/core';
import { FileBlock } from '../components/FileBlock'; import { FileBlock } from '@/activities/blocks/components/FileBlock';
export const BLOCK_SCHEMA = BlockNoteSchema.create({ export const BLOCK_SCHEMA = BlockNoteSchema.create({
blockSpecs: { blockSpecs: {
@@ -2,7 +2,7 @@ import { getDefaultReactSlashMenuItems } from '@blocknote/react';
import { type SuggestionItem } from '@/ui/input/editor/components/CustomSlashMenu'; import { type SuggestionItem } from '@/ui/input/editor/components/CustomSlashMenu';
import { type BLOCK_SCHEMA } from '../constants/Schema'; import { type BLOCK_SCHEMA } from '@/activities/blocks/constants/Schema';
import { import {
IconBlockquote, IconBlockquote,
IconCode, IconCode,
@@ -1,6 +1,6 @@
import { addDays, addHours, subDays, subHours } from 'date-fns'; import { addDays, addHours, subDays, subHours } from 'date-fns';
import { hasCalendarEventEnded } from '../hasCalendarEventEnded'; import { hasCalendarEventEnded } from '@/activities/calendar/utils/hasCalendarEventEnded';
describe('hasCalendarEventEnded', () => { describe('hasCalendarEventEnded', () => {
describe('Event with end date', () => { describe('Event with end date', () => {
@@ -1,6 +1,6 @@
import { addHours, subHours } from 'date-fns'; import { addHours, subHours } from 'date-fns';
import { hasCalendarEventStarted } from '../hasCalendarEventStarted'; import { hasCalendarEventStarted } from '@/activities/calendar/utils/hasCalendarEventStarted';
describe('hasCalendarEventStarted', () => { describe('hasCalendarEventStarted', () => {
it('returns true for an event with a past start date', () => { it('returns true for an event with a past start date', () => {
@@ -3,7 +3,7 @@ import { addHours } from 'date-fns';
import { import {
sortCalendarEventsAsc, sortCalendarEventsAsc,
sortCalendarEventsDesc, sortCalendarEventsDesc,
} from '../sortCalendarEvents'; } from '@/activities/calendar/utils/sortCalendarEvents';
const someDate = new Date(2000, 1, 1); const someDate = new Date(2000, 1, 1);
const someDatePlusOneHour = addHours(someDate, 1); const someDatePlusOneHour = addHours(someDate, 1);
@@ -1,6 +1,6 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { getTimelineThreadsFromCompanyId } from '../getTimelineThreadsFromCompanyId'; import { getTimelineThreadsFromCompanyId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromCompanyId';
jest.mock('@apollo/client', () => ({ jest.mock('@apollo/client', () => ({
gql: jest.fn().mockImplementation((strings) => { gql: jest.fn().mockImplementation((strings) => {
@@ -1,6 +1,6 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { getTimelineThreadsFromPersonId } from '../getTimelineThreadsFromPersonId'; import { getTimelineThreadsFromPersonId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromPersonId';
jest.mock('@apollo/client', () => ({ jest.mock('@apollo/client', () => ({
gql: jest.fn().mockImplementation((strings) => { gql: jest.fn().mockImplementation((strings) => {
@@ -1,7 +1,7 @@
import { type EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant'; import { type EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
import { MessageParticipantRole } from 'twenty-shared/types'; import { MessageParticipantRole } from 'twenty-shared/types';
import { getDisplayNameFromParticipant } from '../getDisplayNameFromParticipant'; import { getDisplayNameFromParticipant } from '@/activities/emails/utils/getDisplayNameFromParticipant';
describe('getDisplayNameFromParticipant', () => { describe('getDisplayNameFromParticipant', () => {
const participantWithName: EmailThreadMessageParticipant = { const participantWithName: EmailThreadMessageParticipant = {
@@ -1,6 +1,6 @@
import { renderHook } from '@testing-library/react'; import { renderHook } from '@testing-library/react';
import { useAttachments } from '../useAttachments'; import { useAttachments } from '@/activities/files/hooks/useAttachments';
jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ jest.mock('@/object-record/hooks/useFindManyRecords', () => ({
useFindManyRecords: jest.fn(), useFindManyRecords: jest.fn(),
@@ -1,4 +1,4 @@
import { downloadFile } from '../downloadFile'; import { downloadFile } from '@/activities/files/utils/downloadFile';
global.fetch = jest.fn(() => global.fetch = jest.fn(() =>
Promise.resolve({ Promise.resolve({
@@ -1,4 +1,4 @@
import { getFileType } from '../getFileType'; import { getFileType } from '@/activities/files/utils/getFileType';
describe('getFileType', () => { describe('getFileType', () => {
it('should return the correct file category for a given file name', () => { it('should return the correct file category for a given file name', () => {
@@ -9,7 +9,7 @@ import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/
import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { type ActivityTargetableObject } from '../../types/ActivityTargetableEntity'; import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
export const useNotes = (targetableObject: ActivityTargetableObject) => { export const useNotes = (targetableObject: ActivityTargetableObject) => {
const notesQueryVariables = useMemo( const notesQueryVariables = useMemo(
@@ -1,4 +1,4 @@
import { type ActivityTargetableObject } from '../types/ActivityTargetableEntity'; import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { createState } from 'twenty-ui/utilities'; import { createState } from 'twenty-ui/utilities';
export const activityTargetableEntityArrayState = createState< export const activityTargetableEntityArrayState = createState<
@@ -15,7 +15,7 @@ import { StopPropagationContainer } from '@/object-record/record-board/record-bo
import { FieldContextProvider } from '@/object-record/record-field/ui/components/FieldContextProvider'; import { FieldContextProvider } from '@/object-record/record-field/ui/components/FieldContextProvider';
import { IconCalendar, OverflowingTextWithTooltip } from 'twenty-ui/display'; import { IconCalendar, OverflowingTextWithTooltip } from 'twenty-ui/display';
import { Checkbox, CheckboxShape } from 'twenty-ui/input'; import { Checkbox, CheckboxShape } from 'twenty-ui/input';
import { useCompleteTask } from '../hooks/useCompleteTask'; import { useCompleteTask } from '@/activities/tasks/hooks/useCompleteTask';
const StyledTaskBody = styled.div` const StyledTaskBody = styled.div`
color: ${({ theme }) => theme.font.color.tertiary}; color: ${({ theme }) => theme.font.color.tertiary};
@@ -1,6 +1,6 @@
import { mockedTimelineActivities } from '~/testing/mock-data/timeline-activities'; import { mockedTimelineActivities } from '~/testing/mock-data/timeline-activities';
import { groupEventsByMonth } from '../groupEventsByMonth'; import { groupEventsByMonth } from '@/activities/timeline-activities/utils/groupEventsByMonth';
describe('groupEventsByMonth', () => { describe('groupEventsByMonth', () => {
it('should group activities by month', () => { it('should group activities by month', () => {
@@ -1,5 +1,5 @@
import { type Attachment } from '@/activities/files/types/Attachment'; import { type Attachment } from '@/activities/files/types/Attachment';
import { filterAttachmentsToRestore } from '../filterAttachmentsToRestore'; import { filterAttachmentsToRestore } from '@/activities/utils/filterAttachmentsToRestore';
describe('filterAttachmentsToRestore', () => { describe('filterAttachmentsToRestore', () => {
it('should not return any ids if there are no attachment paths to restore', () => { it('should not return any ids if there are no attachment paths to restore', () => {
@@ -1,4 +1,4 @@
import { getActivityPreview } from '../getActivityPreview'; import { getActivityPreview } from '@/activities/utils/getActivityPreview';
describe('getActivityPreview', () => { describe('getActivityPreview', () => {
it('should work for empty body', () => { it('should work for empty body', () => {
@@ -1,4 +1,4 @@
import { getActivitySummary } from '../getActivitySummary'; import { getActivitySummary } from '@/activities/utils/getActivitySummary';
describe('getActivitySummary', () => { describe('getActivitySummary', () => {
it('should work for empty body ""', () => { it('should work for empty body ""', () => {
@@ -6,7 +6,7 @@ import { ListKit } from '@tiptap/extension-list';
import { Paragraph } from '@tiptap/extension-paragraph'; import { Paragraph } from '@tiptap/extension-paragraph';
import { Text } from '@tiptap/extension-text'; import { Text } from '@tiptap/extension-text';
import { DEFAULT_SLASH_COMMANDS } from '../DefaultSlashCommands'; import { DEFAULT_SLASH_COMMANDS } from '@/advanced-text-editor/extensions/slash-command/DefaultSlashCommands';
describe('DefaultSlashCommands', () => { describe('DefaultSlashCommands', () => {
let editor: Editor; let editor: Editor;
@@ -6,7 +6,7 @@ import { ListKit } from '@tiptap/extension-list';
import { Paragraph } from '@tiptap/extension-paragraph'; import { Paragraph } from '@tiptap/extension-paragraph';
import { Text } from '@tiptap/extension-text'; import { Text } from '@tiptap/extension-text';
import { SlashCommand } from '../SlashCommand'; import { SlashCommand } from '@/advanced-text-editor/extensions/slash-command/SlashCommand';
describe('SlashCommand', () => { describe('SlashCommand', () => {
let editor: Editor; let editor: Editor;
@@ -3,8 +3,8 @@ import { Document } from '@tiptap/extension-document';
import { Paragraph } from '@tiptap/extension-paragraph'; import { Paragraph } from '@tiptap/extension-paragraph';
import { Text } from '@tiptap/extension-text'; import { Text } from '@tiptap/extension-text';
import { type SlashCommandItem } from '../SlashCommand'; import { type SlashCommandItem } from '@/advanced-text-editor/extensions/slash-command/SlashCommand';
import { SlashCommandRenderer } from '../SlashCommandRenderer'; import { SlashCommandRenderer } from '@/advanced-text-editor/extensions/slash-command/SlashCommandRenderer';
describe('SlashCommandRenderer', () => { describe('SlashCommandRenderer', () => {
let editor: Editor; let editor: Editor;
@@ -1,5 +1,5 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { AGENT_FRAGMENT } from '../fragments/agentFragment'; import { AGENT_FRAGMENT } from '@/ai/graphql/fragments/agentFragment';
export const CREATE_ONE_AGENT = gql` export const CREATE_ONE_AGENT = gql`
${AGENT_FRAGMENT} ${AGENT_FRAGMENT}
@@ -1,5 +1,5 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { AGENT_FRAGMENT } from '../fragments/agentFragment'; import { AGENT_FRAGMENT } from '@/ai/graphql/fragments/agentFragment';
export const DELETE_ONE_AGENT = gql` export const DELETE_ONE_AGENT = gql`
${AGENT_FRAGMENT} ${AGENT_FRAGMENT}
@@ -1,5 +1,5 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { AGENT_FRAGMENT } from '../fragments/agentFragment'; import { AGENT_FRAGMENT } from '@/ai/graphql/fragments/agentFragment';
export const UPDATE_ONE_AGENT = gql` export const UPDATE_ONE_AGENT = gql`
${AGENT_FRAGMENT} ${AGENT_FRAGMENT}
@@ -1,5 +1,5 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { AGENT_FRAGMENT } from '../fragments/agentFragment'; import { AGENT_FRAGMENT } from '@/ai/graphql/fragments/agentFragment';
export const FIND_MANY_AGENTS = gql` export const FIND_MANY_AGENTS = gql`
${AGENT_FRAGMENT} ${AGENT_FRAGMENT}
@@ -1,5 +1,5 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { AGENT_FRAGMENT } from '../fragments/agentFragment'; import { AGENT_FRAGMENT } from '@/ai/graphql/fragments/agentFragment';
export const FIND_ONE_AGENT = gql` export const FIND_ONE_AGENT = gql`
${AGENT_FRAGMENT} ${AGENT_FRAGMENT}
@@ -15,8 +15,8 @@ import { type ExtendedUIMessage } from 'twenty-shared/ai';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { REACT_APP_SERVER_BASE_URL } from '~/config';
import { cookieStorage } from '~/utils/cookie-storage'; import { cookieStorage } from '~/utils/cookie-storage';
import { REST_API_BASE_URL } from '../../apollo/constant/rest-api-base-url'; import { REST_API_BASE_URL } from '@/apollo/constant/rest-api-base-url';
import { agentChatInputState } from '../states/agentChatInputState'; import { agentChatInputState } from '@/ai/states/agentChatInputState';
export const useAgentChat = (uiMessages: ExtendedUIMessage[]) => { export const useAgentChat = (uiMessages: ExtendedUIMessage[]) => {
const setTokenPair = useSetRecoilState(tokenPairState); const setTokenPair = useSetRecoilState(tokenPairState);
@@ -1,4 +1,4 @@
import { getFieldIcon } from '../getFieldIcon'; import { getFieldIcon } from '@/ai/utils/getFieldIcon';
describe('getFieldIcon', () => { describe('getFieldIcon', () => {
describe('supported field types', () => { describe('supported field types', () => {
@@ -1,5 +1,5 @@
import { type AgentChatThread } from '~/generated-metadata/graphql'; import { type AgentChatThread } from '~/generated-metadata/graphql';
import { groupThreadsByDate } from '../groupThreadsByDate'; import { groupThreadsByDate } from '@/ai/utils/groupThreadsByDate';
describe('groupThreadsByDate', () => { describe('groupThreadsByDate', () => {
const baseThread: Omit<AgentChatThread, 'createdAt' | 'id'> = { const baseThread: Omit<AgentChatThread, 'createdAt' | 'id'> = {
@@ -5,7 +5,10 @@ import { act, renderHook, waitFor } from '@testing-library/react';
import { type ReactNode } from 'react'; import { type ReactNode } from 'react';
import { RecoilRoot } from 'recoil'; import { RecoilRoot } from 'recoil';
import { ANALYTICS_COOKIE_NAME, useEventTracker } from '../useEventTracker'; import {
ANALYTICS_COOKIE_NAME,
useEventTracker,
} from '@/analytics/hooks/useEventTracker';
import { AnalyticsType } from '~/generated/graphql'; import { AnalyticsType } from '~/generated/graphql';
// Mock document.cookie // Mock document.cookie
@@ -5,7 +5,7 @@ import { MemoryRouter, useLocation } from 'react-router-dom';
import { RecoilRoot } from 'recoil'; import { RecoilRoot } from 'recoil';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext'; import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
import { useApolloFactory } from '../useApolloFactory'; import { useApolloFactory } from '@/apollo/hooks/useApolloFactory';
enableFetchMocks(); enableFetchMocks();
@@ -17,7 +17,7 @@ import { appVersionState } from '@/client-config/states/appVersionState';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { AppPath } from 'twenty-shared/types'; import { AppPath } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { ApolloFactory, type Options } from '../services/apollo.factory'; import { ApolloFactory, type Options } from '@/apollo/services/apollo.factory';
export const useApolloFactory = (options: Partial<Options<any>> = {}) => { export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
// eslint-disable-next-line @nx/workspace-no-state-useref // eslint-disable-next-line @nx/workspace-no-state-useref
@@ -1,6 +1,6 @@
import { type RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { type RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode';
import { doesRecordBelongToGroup } from '../doesRecordBelongToGroup'; import { doesRecordBelongToGroup } from '@/apollo/optimistic-effect/group-by/utils/doesRecordBelongToGroup';
describe('doesRecordBelongToGroup', () => { describe('doesRecordBelongToGroup', () => {
it('should return true when groupByConfig is undefined', () => { it('should return true when groupByConfig is undefined', () => {
@@ -1,4 +1,4 @@
import { normalizeGroupByDimensionValue } from '../normalizeGroupByDimensionValue'; import { normalizeGroupByDimensionValue } from '@/apollo/optimistic-effect/group-by/utils/normalizeGroupByDimensionValue';
describe('normalizeGroupByDimensionValue', () => { describe('normalizeGroupByDimensionValue', () => {
it('should convert string to string', () => { it('should convert string to string', () => {
@@ -8,7 +8,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
import { type RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; import { type RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge';
import { type RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { type RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode';
import { processGroupByConnectionWithRecords } from '../processGroupByConnectionWithRecords'; import { processGroupByConnectionWithRecords } from '@/apollo/optimistic-effect/group-by/utils/processGroupByConnectionWithRecords';
describe('processGroupByConnectionWithRecords', () => { describe('processGroupByConnectionWithRecords', () => {
const mockObjectMetadataItem: ObjectMetadataItem = { const mockObjectMetadataItem: ObjectMetadataItem = {
@@ -3,7 +3,7 @@ import { type ApolloCache } from '@apollo/client';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { type RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { type RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode';
import { triggerUpdateGroupByQueriesOptimisticEffect } from '../triggerUpdateGroupByQueriesOptimisticEffect'; import { triggerUpdateGroupByQueriesOptimisticEffect } from '@/apollo/optimistic-effect/group-by/utils/triggerUpdateGroupByQueriesOptimisticEffect';
describe('triggerUpdateGroupByQueriesOptimisticEffect', () => { describe('triggerUpdateGroupByQueriesOptimisticEffect', () => {
const mockObjectMetadataItem: ObjectMetadataItem = { const mockObjectMetadataItem: ObjectMetadataItem = {
@@ -5,7 +5,7 @@ import { DEFAULT_FAST_MODEL } from '@/ai/constants/DefaultFastModel';
import { DEFAULT_SMART_MODEL } from '@/ai/constants/DefaultSmartModel'; import { DEFAULT_SMART_MODEL } from '@/ai/constants/DefaultSmartModel';
import { CUSTOM_WORKSPACE_APPLICATION_MOCK } from '@/object-metadata/hooks/__tests__/constants/CustomWorkspaceApplicationMock.test.constant'; import { CUSTOM_WORKSPACE_APPLICATION_MOCK } from '@/object-metadata/hooks/__tests__/constants/CustomWorkspaceApplicationMock.test.constant';
import { WorkspaceActivationStatus } from '~/generated/graphql'; import { WorkspaceActivationStatus } from '~/generated/graphql';
import { ApolloFactory, type Options } from '../apollo.factory'; import { ApolloFactory, type Options } from '@/apollo/services/apollo.factory';
enableFetchMocks(); enableFetchMocks();
@@ -35,9 +35,9 @@ import isEmpty from 'lodash.isempty';
import { getGenericOperationName, isDefined } from 'twenty-shared/utils'; import { getGenericOperationName, isDefined } from 'twenty-shared/utils';
import { cookieStorage } from '~/utils/cookie-storage'; import { cookieStorage } from '~/utils/cookie-storage';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
import { type ApolloManager } from '../types/apolloManager.interface'; import { type ApolloManager } from '@/apollo/types/apolloManager.interface';
import { loggerLink } from '../utils/loggerLink'; import { loggerLink } from '@/apollo/utils/loggerLink';
import { StreamingRestLink } from '../utils/streamingRestLink'; import { StreamingRestLink } from '@/apollo/utils/streamingRestLink';
const logger = loggerLink(() => 'Twenty'); const logger = loggerLink(() => 'Twenty');
@@ -1,6 +1,6 @@
import { OperationType } from '@/apollo/types/operation-type'; import { OperationType } from '@/apollo/types/operation-type';
import formatTitle from '../formatTitle'; import formatTitle from '@/apollo/utils/formatTitle';
describe('formatTitle', () => { describe('formatTitle', () => {
it('should correctly format the title', () => { it('should correctly format the title', () => {
@@ -1,5 +1,5 @@
import { cookieStorage } from '~/utils/cookie-storage'; import { cookieStorage } from '~/utils/cookie-storage';
import { getTokenPair } from '../getTokenPair'; import { getTokenPair } from '@/apollo/utils/getTokenPair';
jest.mock('~/utils/cookie-storage', () => ({ jest.mock('~/utils/cookie-storage', () => ({
cookieStorage: { cookieStorage: {
@@ -1,5 +1,5 @@
import { getTokenPair } from '../getTokenPair'; import { getTokenPair } from '@/apollo/utils/getTokenPair';
import { hasTokenPair } from '../hasTokenPair'; import { hasTokenPair } from '@/apollo/utils/hasTokenPair';
jest.mock('../getTokenPair'); jest.mock('../getTokenPair');
@@ -1,6 +1,6 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { type Operation } from '@apollo/client/core'; import { type Operation } from '@apollo/client/core';
import { StreamingRestLink } from '../streamingRestLink'; import { StreamingRestLink } from '@/apollo/utils/streamingRestLink';
global.fetch = jest.fn(); global.fetch = jest.fn();
describe('StreamingRestLink', () => { describe('StreamingRestLink', () => {
@@ -1,4 +1,4 @@
import { OperationType } from '../types/operation-type'; import { OperationType } from '@/apollo/types/operation-type';
const operationTypeColors = { const operationTypeColors = {
// eslint-disable-next-line @nx/workspace-no-hardcoded-colors // eslint-disable-next-line @nx/workspace-no-hardcoded-colors
@@ -1,5 +1,5 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { APPLICATION_FRAGMENT } from '../fragments/applicationFragment'; import { APPLICATION_FRAGMENT } from '@/applications/graphql/fragments/applicationFragment';
export const FIND_ONE_APPLICATION = gql` export const FIND_ONE_APPLICATION = gql`
${APPLICATION_FRAGMENT} ${APPLICATION_FRAGMENT}
@@ -1,7 +1,7 @@
import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { AUTH_MODAL_ID } from '../constants/AuthModalId'; import { AUTH_MODAL_ID } from '@/auth/constants/AuthModalId';
// TODO: Remove this component when we refactor the auth modal to open it directly in the PageChangeEffect // TODO: Remove this component when we refactor the auth modal to open it directly in the PageChangeEffect
export const AuthModalMountEffect = () => { export const AuthModalMountEffect = () => {
@@ -16,7 +16,7 @@ import { useRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { useNavigateApp } from '~/hooks/useNavigateApp'; import { useNavigateApp } from '~/hooks/useNavigateApp';
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl'; import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
import { EmailVerificationSent } from '../sign-in-up/components/EmailVerificationSent'; import { EmailVerificationSent } from '@/auth/sign-in-up/components/EmailVerificationSent';
export const VerifyEmailEffect = () => { export const VerifyEmailEffect = () => {
const { const {
@@ -5,7 +5,7 @@ import {
RecoilRootDecorator, RecoilRootDecorator,
RouterDecorator, RouterDecorator,
} from 'twenty-ui/testing'; } from 'twenty-ui/testing';
import { Logo } from '../Logo'; import { Logo } from '@/auth/components/Logo';
const logoUrl = 'https://picsum.photos/192/192'; const logoUrl = 'https://picsum.photos/192/192';
@@ -1,13 +1,13 @@
import { type Meta, type StoryObj } from '@storybook/react'; import { type Meta, type StoryObj } from '@storybook/react';
import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { RecoilRoot } from 'recoil'; import { RecoilRoot } from 'recoil';
import { type VerifyEmailEffect } from '../VerifyEmailEffect'; import { type VerifyEmailEffect } from '@/auth/components/VerifyEmailEffect';
// Mock component that just renders the error state of VerifyEmailEffect directly // Mock component that just renders the error state of VerifyEmailEffect directly
// (since normal VerifyEmailEffect has async logic that's hard to test in Storybook) // (since normal VerifyEmailEffect has async logic that's hard to test in Storybook)
import { Modal } from '@/ui/layout/modal/components/Modal'; import { Modal } from '@/ui/layout/modal/components/Modal';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { EmailVerificationSent } from '../../sign-in-up/components/EmailVerificationSent'; import { EmailVerificationSent } from '@/auth/sign-in-up/components/EmailVerificationSent';
const VerifyEmailEffectErrorState = ({ email = 'user@example.com' }) => { const VerifyEmailEffectErrorState = ({ email = 'user@example.com' }) => {
return ( return (
@@ -16,7 +16,13 @@ import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manage
import { renderHook } from '@testing-library/react'; import { renderHook } from '@testing-library/react';
import { iconsState } from 'twenty-ui/display'; import { iconsState } from 'twenty-ui/display';
import { SupportDriver } from '~/generated/graphql'; import { SupportDriver } from '~/generated/graphql';
import { email, mocks, password, results, token } from '../__mocks__/useAuth'; import {
email,
mocks,
password,
results,
token,
} from '@/auth/hooks/__mocks__/useAuth';
const redirectSpy = jest.fn(); const redirectSpy = jest.fn();
@@ -6,8 +6,8 @@ import { RecoilRoot } from 'recoil';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { AppPath } from 'twenty-shared/types'; import { AppPath } from 'twenty-shared/types';
import { useNavigateApp } from '~/hooks/useNavigateApp'; import { useNavigateApp } from '~/hooks/useNavigateApp';
import { useAuth } from '../useAuth'; import { useAuth } from '@/auth/hooks/useAuth';
import { useVerifyLogin } from '../useVerifyLogin'; import { useVerifyLogin } from '@/auth/hooks/useVerifyLogin';
import { SOURCE_LOCALE } from 'twenty-shared/translations'; import { SOURCE_LOCALE } from 'twenty-shared/translations';
import { dynamicActivate } from '~/utils/i18n/dynamicActivate'; import { dynamicActivate } from '~/utils/i18n/dynamicActivate';
@@ -27,7 +27,7 @@ import {
} from '~/generated-metadata/graphql'; } from '~/generated-metadata/graphql';
import { isDeveloperDefaultSignInPrefilledState } from '@/client-config/states/isDeveloperDefaultSignInPrefilledState'; import { isDeveloperDefaultSignInPrefilledState } from '@/client-config/states/isDeveloperDefaultSignInPrefilledState';
import { tokenPairState } from '../states/tokenPairState'; import { tokenPairState } from '@/auth/states/tokenPairState';
import { isAppEffectRedirectEnabledState } from '@/app/states/isAppEffectRedirectEnabledState'; import { isAppEffectRedirectEnabledState } from '@/app/states/isAppEffectRedirectEnabledState';
import { useSignUpInNewWorkspace } from '@/auth/sign-in-up/hooks/useSignUpInNewWorkspace'; import { useSignUpInNewWorkspace } from '@/auth/sign-in-up/hooks/useSignUpInNewWorkspace';
@@ -66,7 +66,7 @@ import { iconsState } from 'twenty-ui/display';
import { type AuthToken } from '~/generated/graphql'; import { type AuthToken } from '~/generated/graphql';
import { cookieStorage } from '~/utils/cookie-storage'; import { cookieStorage } from '~/utils/cookie-storage';
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl'; import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
import { loginTokenState } from '../states/loginTokenState'; import { loginTokenState } from '@/auth/states/loginTokenState';
export const useAuth = () => { export const useAuth = () => {
const setTokenPair = useSetRecoilState(tokenPairState); const setTokenPair = useSetRecoilState(tokenPairState);
@@ -1,6 +1,6 @@
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { tokenPairState } from '../states/tokenPairState'; import { tokenPairState } from '@/auth/states/tokenPairState';
export const useIsLogged = (): boolean => { export const useIsLogged = (): boolean => {
const [tokenPair] = useRecoilState(tokenPairState); const [tokenPair] = useRecoilState(tokenPairState);
@@ -3,7 +3,7 @@ import { type Meta, type StoryObj } from '@storybook/react';
import { Modal } from '@/ui/layout/modal/components/Modal'; import { Modal } from '@/ui/layout/modal/components/Modal';
import { ComponentDecorator } from 'twenty-ui/testing'; import { ComponentDecorator } from 'twenty-ui/testing';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { EmailVerificationSent } from '../EmailVerificationSent'; import { EmailVerificationSent } from '@/auth/sign-in-up/components/EmailVerificationSent';
// Wrap the component in Modal.Content to reflect how it's used in the app // Wrap the component in Modal.Content to reflect how it's used in the app
const RenderWithModal = ( const RenderWithModal = (
@@ -21,7 +21,7 @@ import { AppPath } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { buildAppPathWithQueryParams } from '~/utils/buildAppPathWithQueryParams'; import { buildAppPathWithQueryParams } from '~/utils/buildAppPathWithQueryParams';
import { isMatchingLocation } from '~/utils/isMatchingLocation'; import { isMatchingLocation } from '~/utils/isMatchingLocation';
import { useAuth } from '../../hooks/useAuth'; import { useAuth } from '@/auth/hooks/useAuth';
export const useSignInUp = (form: UseFormReturn<Form>) => { export const useSignInUp = (form: UseFormReturn<Form>) => {
const { enqueueErrorSnackBar } = useSnackBar(); const { enqueueErrorSnackBar } = useSnackBar();
@@ -7,7 +7,7 @@ import {
countAvailableWorkspaces, countAvailableWorkspaces,
getAvailableWorkspacePathAndSearchParams, getAvailableWorkspacePathAndSearchParams,
getFirstAvailableWorkspaces, getFirstAvailableWorkspaces,
} from '../availableWorkspacesUtils'; } from '@/auth/utils/availableWorkspacesUtils';
const createMockAvailableWorkspace = ( const createMockAvailableWorkspace = (
overrides: Partial<AvailableWorkspace> = {}, overrides: Partial<AvailableWorkspace> = {},
@@ -1,6 +1,6 @@
import { CaptchaDriverType } from '~/generated/graphql'; import { CaptchaDriverType } from '~/generated/graphql';
import { getCaptchaUrlByProvider } from '../getCaptchaUrlByProvider'; import { getCaptchaUrlByProvider } from '@/captcha/utils/getCaptchaUrlByProvider';
describe('getCaptchaUrlByProvider', () => { describe('getCaptchaUrlByProvider', () => {
it('handles GoogleRecaptcha', async () => { it('handles GoogleRecaptcha', async () => {
@@ -1,5 +1,5 @@
import { matchPath } from 'react-router-dom'; import { matchPath } from 'react-router-dom';
import { CAPTCHA_PROTECTED_PATHS } from '../constants/CaptchaProtectedPaths'; import { CAPTCHA_PROTECTED_PATHS } from '@/captcha/constants/CaptchaProtectedPaths';
export const isCaptchaRequiredForPath = (pathname: string): boolean => export const isCaptchaRequiredForPath = (pathname: string): boolean =>
CAPTCHA_PROTECTED_PATHS.some((path) => CAPTCHA_PROTECTED_PATHS.some((path) =>
@@ -26,8 +26,8 @@ import { type ClientConfig } from '@/client-config/types/ClientConfig';
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState'; import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useRecoilState, useSetRecoilState } from 'recoil'; import { useRecoilState, useSetRecoilState } from 'recoil';
import { clientConfigApiStatusState } from '../states/clientConfigApiStatusState'; import { clientConfigApiStatusState } from '@/client-config/states/clientConfigApiStatusState';
import { getClientConfig } from '../utils/getClientConfig'; import { getClientConfig } from '@/client-config/utils/getClientConfig';
type UseClientConfigResult = { type UseClientConfigResult = {
data: { clientConfig: ClientConfig } | undefined; data: { clientConfig: ClientConfig } | undefined;
@@ -1,5 +1,5 @@
import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { REACT_APP_SERVER_BASE_URL } from '~/config';
import { getClientConfig } from '../getClientConfig'; import { getClientConfig } from '@/client-config/utils/getClientConfig';
global.fetch = jest.fn(); global.fetch = jest.fn();
@@ -4,7 +4,7 @@ import { useRecoilValue } from 'recoil';
import { import {
COMMAND_MENU_WIDTH_VAR, COMMAND_MENU_WIDTH_VAR,
commandMenuWidthState, commandMenuWidthState,
} from '../states/commandMenuWidthState'; } from '@/command-menu/states/commandMenuWidthState';
export const CommandMenuWidthEffect = () => { export const CommandMenuWidthEffect = () => {
const commandMenuWidth = useRecoilValue(commandMenuWidthState); const commandMenuWidth = useRecoilValue(commandMenuWidthState);
@@ -32,7 +32,7 @@ import { HttpResponse, graphql } from 'msw';
import { IconDotsVertical } from 'twenty-ui/display'; import { IconDotsVertical } from 'twenty-ui/display';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter'; import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter';
import { type CommandMenu } from '../CommandMenu'; import { type CommandMenu } from '@/command-menu/components/CommandMenu';
const openTimeout = 50; const openTimeout = 50;
@@ -3,7 +3,7 @@ import { renderHook } from '@testing-library/react';
import { act } from 'react'; import { act } from 'react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { RecoilRoot, useRecoilValue } from 'recoil'; import { RecoilRoot, useRecoilValue } from 'recoil';
import { useCommandMenuOnItemClick } from '../useCommandMenuOnItemClick'; import { useCommandMenuOnItemClick } from '@/command-menu/hooks/useCommandMenuOnItemClick';
const Wrapper = ({ children }: { children: React.ReactNode }) => ( const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot> <RecoilRoot>
@@ -3,7 +3,7 @@ import { ActionScope } from '@/action-menu/actions/types/ActionScope';
import { ActionType } from '@/action-menu/actions/types/ActionType'; import { ActionType } from '@/action-menu/actions/types/ActionType';
import { renderHook } from '@testing-library/react'; import { renderHook } from '@testing-library/react';
import { IconPlus } from 'twenty-ui/display'; import { IconPlus } from 'twenty-ui/display';
import { useFilterActionsWithCommandMenuSearch } from '../useFilterActionsWithCommandMenuSearch'; import { useFilterActionsWithCommandMenuSearch } from '@/command-menu/hooks/useFilterActionsWithCommandMenuSearch';
const MockComponent = <div>Mock Component</div>; const MockComponent = <div>Mock Component</div>;
@@ -20,7 +20,7 @@ import { act } from 'react';
import { IconBolt, IconSettingsAutomation, useIcons } from 'twenty-ui/display'; import { IconBolt, IconSettingsAutomation, useIcons } from 'twenty-ui/display';
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems'; import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
import { useWorkflowCommandMenu } from '../useWorkflowCommandMenu'; import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
jest.mock('uuid', () => ({ jest.mock('uuid', () => ({
v4: jest.fn().mockReturnValue('mocked-uuid'), v4: jest.fn().mockReturnValue('mocked-uuid'),
@@ -13,7 +13,7 @@ import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { IconDotsVertical } from 'twenty-ui/display'; import { IconDotsVertical } from 'twenty-ui/display';
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState'; import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
export const useCommandMenu = () => { export const useCommandMenu = () => {
const { navigateCommandMenu } = useNavigateCommandMenu(); const { navigateCommandMenu } = useNavigateCommandMenu();
@@ -10,7 +10,7 @@ import {
import { MessageParticipantRole } from 'twenty-shared/types'; import { MessageParticipantRole } from 'twenty-shared/types';
import { generateEmptyJestRecordNode } from '~/testing/jest/generateEmptyJestRecordNode'; import { generateEmptyJestRecordNode } from '~/testing/jest/generateEmptyJestRecordNode';
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import { useEmailThreadInCommandMenu } from '../useEmailThreadInCommandMenu'; import { useEmailThreadInCommandMenu } from '@/command-menu/pages/message-thread/hooks/useEmailThreadInCommandMenu';
const mocks = [ const mocks = [
{ {
@@ -14,7 +14,7 @@ import {
GraphOrderBy, GraphOrderBy,
GraphType, GraphType,
} from '~/generated-metadata/graphql'; } from '~/generated-metadata/graphql';
import { useChartSettingsValues } from '../useChartSettingsValues'; import { useChartSettingsValues } from '@/command-menu/pages/page-layout/hooks/useChartSettingsValues';
const mockObjectMetadataItem: ObjectMetadataItem = { const mockObjectMetadataItem: ObjectMetadataItem = {
id: 'obj-1', id: 'obj-1',
@@ -5,7 +5,7 @@ import {
GraphOrderBy, GraphOrderBy,
type PieChartConfiguration, type PieChartConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { buildChartGroupByFieldConfigUpdate } from '../buildChartGroupByFieldConfigUpdate'; import { buildChartGroupByFieldConfigUpdate } from '@/command-menu/pages/page-layout/utils/buildChartGroupByFieldConfigUpdate';
describe('buildChartGroupByFieldConfigUpdate', () => { describe('buildChartGroupByFieldConfigUpdate', () => {
it('sets default orderBy and dateGranularity for primary axis', () => { it('sets default orderBy and dateGranularity for primary axis', () => {
@@ -19,7 +19,7 @@ import { SORT_BY_GROUP_BY_FIELD_SETTING } from '@/command-menu/pages/page-layout
import { STACKED_BARS_SETTING } from '@/command-menu/pages/page-layout/constants/settings/StackedBarsSetting'; import { STACKED_BARS_SETTING } from '@/command-menu/pages/page-layout/constants/settings/StackedBarsSetting';
import { IconAxisX, IconAxisY } from 'twenty-ui/display'; import { IconAxisX, IconAxisY } from 'twenty-ui/display';
import { GraphType } from '~/generated-metadata/graphql'; import { GraphType } from '~/generated-metadata/graphql';
import { getBarChartSettings } from '../getBarChartSettings'; import { getBarChartSettings } from '@/command-menu/pages/page-layout/utils/getBarChartSettings';
describe('getBarChartSettings', () => { describe('getBarChartSettings', () => {
describe('Vertical bar chart', () => { describe('Vertical bar chart', () => {
@@ -2,7 +2,7 @@ import {
type AggregateChartConfiguration, type AggregateChartConfiguration,
type BarChartConfiguration, type BarChartConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isAggregateChartConfiguration } from '../isAggregateChartConfiguration'; import { isAggregateChartConfiguration } from '@/command-menu/pages/page-layout/utils/isAggregateChartConfiguration';
describe('isAggregateChartConfiguration', () => { describe('isAggregateChartConfiguration', () => {
it('should return true for AggregateChartConfiguration', () => { it('should return true for AggregateChartConfiguration', () => {
@@ -2,7 +2,7 @@ import {
type BarChartConfiguration, type BarChartConfiguration,
type LineChartConfiguration, type LineChartConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isBarChartConfiguration } from '../isBarChartConfiguration'; import { isBarChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarChartConfiguration';
describe('isBarChartConfiguration', () => { describe('isBarChartConfiguration', () => {
it('should return true for BarChartConfiguration', () => { it('should return true for BarChartConfiguration', () => {
@@ -3,7 +3,7 @@ import {
type LineChartConfiguration, type LineChartConfiguration,
type PieChartConfiguration, type PieChartConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isBarOrLineChartConfiguration } from '../isBarOrLineChartConfiguration'; import { isBarOrLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isBarOrLineChartConfiguration';
describe('isBarOrLineChartConfiguration', () => { describe('isBarOrLineChartConfiguration', () => {
it('should return true for BarChartConfiguration', () => { it('should return true for BarChartConfiguration', () => {
@@ -7,7 +7,7 @@ import {
type PieChartConfiguration, type PieChartConfiguration,
type StandaloneRichTextConfiguration, type StandaloneRichTextConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isChartConfiguration } from '../isChartConfiguration'; import { isChartConfiguration } from '@/command-menu/pages/page-layout/utils/isChartConfiguration';
describe('isChartConfiguration', () => { describe('isChartConfiguration', () => {
it('should return true for BarChartConfiguration', () => { it('should return true for BarChartConfiguration', () => {
@@ -1,6 +1,6 @@
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { FieldMetadataType } from 'twenty-shared/types'; import { FieldMetadataType } from 'twenty-shared/types';
import { isFieldOrRelationNestedFieldDateKind } from '../isFieldOrNestedFieldDateKind'; import { isFieldOrRelationNestedFieldDateKind } from '@/command-menu/pages/page-layout/utils/isFieldOrNestedFieldDateKind';
describe('isFieldOrNestedFieldDateKind', () => { describe('isFieldOrNestedFieldDateKind', () => {
it('returns false when fieldId is null', () => { it('returns false when fieldId is null', () => {
@@ -2,7 +2,7 @@ import {
type BarChartConfiguration, type BarChartConfiguration,
type GaugeChartConfiguration, type GaugeChartConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isGaugeChartConfiguration } from '../isGaugeChartConfiguration'; import { isGaugeChartConfiguration } from '@/command-menu/pages/page-layout/utils/isGaugeChartConfiguration';
describe('isGaugeChartConfiguration', () => { describe('isGaugeChartConfiguration', () => {
it('should return true for GaugeChartConfiguration', () => { it('should return true for GaugeChartConfiguration', () => {
@@ -2,7 +2,7 @@ import {
type BarChartConfiguration, type BarChartConfiguration,
type IframeConfiguration, type IframeConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isIframeConfiguration } from '../isIframeConfiguration'; import { isIframeConfiguration } from '@/command-menu/pages/page-layout/utils/isIframeConfiguration';
describe('isIframeConfiguration', () => { describe('isIframeConfiguration', () => {
it('should return true for IframeConfiguration', () => { it('should return true for IframeConfiguration', () => {
@@ -2,7 +2,7 @@ import {
type BarChartConfiguration, type BarChartConfiguration,
type LineChartConfiguration, type LineChartConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isLineChartConfiguration } from '../isLineChartConfiguration'; import { isLineChartConfiguration } from '@/command-menu/pages/page-layout/utils/isLineChartConfiguration';
describe('isLineChartConfiguration', () => { describe('isLineChartConfiguration', () => {
it('should return true for LineChartConfiguration', () => { it('should return true for LineChartConfiguration', () => {
@@ -2,7 +2,7 @@ import {
type BarChartConfiguration, type BarChartConfiguration,
type PieChartConfiguration, type PieChartConfiguration,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isPieChartConfiguration } from '../isPieChartConfiguration'; import { isPieChartConfiguration } from '@/command-menu/pages/page-layout/utils/isPieChartConfiguration';
describe('isPieChartConfiguration', () => { describe('isPieChartConfiguration', () => {
it('should return true for PieChartConfiguration', () => { it('should return true for PieChartConfiguration', () => {
@@ -5,7 +5,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
import { msg } from '@lingui/core/macro'; import { msg } from '@lingui/core/macro';
import { FieldMetadataType } from 'twenty-shared/types'; import { FieldMetadataType } from 'twenty-shared/types';
import { IconChartBar } from 'twenty-ui/display'; import { IconChartBar } from 'twenty-ui/display';
import { shouldHideChartSetting } from '../shouldHideChartSetting'; import { shouldHideChartSetting } from '@/command-menu/pages/page-layout/utils/shouldHideChartSetting';
describe('shouldHideChartSetting', () => { describe('shouldHideChartSetting', () => {
const mockItemWithoutDependencies: ChartSettingsItem = { const mockItemWithoutDependencies: ChartSettingsItem = {
@@ -5,7 +5,7 @@ import styled from '@emotion/styled';
import { lazy, Suspense } from 'react'; import { lazy, Suspense } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { viewableRichTextComponentState } from '../states/viewableRichTextComponentState'; import { viewableRichTextComponentState } from '@/command-menu/pages/rich-text-page/states/viewableRichTextComponentState';
const ActivityRichTextEditor = lazy(() => const ActivityRichTextEditor = lazy(() =>
import('@/activities/components/ActivityRichTextEditor').then((module) => ({ import('@/activities/components/ActivityRichTextEditor').then((module) => ({
@@ -1,4 +1,4 @@
import { getForeignDataWrapperType } from '../getForeignDataWrapperType'; import { getForeignDataWrapperType } from '@/databases/utils/getForeignDataWrapperType';
describe('getForeignDataWrapperType', () => { describe('getForeignDataWrapperType', () => {
it('should handle postgres', () => { it('should handle postgres', () => {
@@ -13,7 +13,7 @@ import {
mockId, mockId,
mockWorkspaceMember, mockWorkspaceMember,
mocks, mocks,
} from '../__mocks__/useFavorites'; } from '@/favorites/hooks/__mocks__/useFavorites';
jest.mock('uuid', () => ({ jest.mock('uuid', () => ({
v4: () => mockId, v4: () => mockId,
@@ -11,7 +11,7 @@ import {
initialFavorites, initialFavorites,
mockWorkspaceMember, mockWorkspaceMember,
mocks, mocks,
} from '../__mocks__/useFavorites'; } from '@/favorites/hooks/__mocks__/useFavorites';
jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ jest.mock('@/object-record/hooks/useFindManyRecords', () => ({
useFindManyRecords: () => ({ records: initialFavorites }), useFindManyRecords: () => ({ records: initialFavorites }),
@@ -12,7 +12,7 @@ import {
initialFavorites, initialFavorites,
mockWorkspaceMember, mockWorkspaceMember,
sortedFavorites, sortedFavorites,
} from '../__mocks__/useFavorites'; } from '@/favorites/hooks/__mocks__/useFavorites';
const Wrapper = getJestMetadataAndApolloMocksWrapper({ const Wrapper = getJestMetadataAndApolloMocksWrapper({
apolloMocks: [], apolloMocks: [],
@@ -17,7 +17,7 @@ import {
initialFavorites, initialFavorites,
mockWorkspaceMember, mockWorkspaceMember,
mocks, mocks,
} from '../__mocks__/useFavorites'; } from '@/favorites/hooks/__mocks__/useFavorites';
jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ jest.mock('@/object-record/hooks/useFindManyRecords', () => ({
useFindManyRecords: () => ({ records: initialFavorites }), useFindManyRecords: () => ({ records: initialFavorites }),

Some files were not shown because too many files have changed in this diff Show More