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
@@ -2,7 +2,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
import type { Meta, StoryObj } from '@storybook/react';
import { expect, within } from '@storybook/test';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { WorkflowFieldsMultiSelect } from '../WorkflowEditUpdateEventFieldsMultiSelect';
import { WorkflowFieldsMultiSelect } from '@/workflow/components/WorkflowEditUpdateEventFieldsMultiSelect';
const meta: Meta<typeof WorkflowFieldsMultiSelect> = {
title: 'Modules/Workflow/WorkflowFieldsMultiSelect',
@@ -1,7 +1,7 @@
import { useMutation } from '@apollo/client';
import { renderHook } from '@testing-library/react';
import { type ComputeStepOutputSchemaInput } from '~/generated/graphql';
import { useComputeStepOutputSchema } from '../useComputeStepOutputSchema';
import { useComputeStepOutputSchema } from '@/workflow/hooks/useComputeStepOutputSchema';
jest.mock('@apollo/client');
jest.mock('@/object-metadata/hooks/useApolloCoreClient', () => ({
@@ -1,6 +1,6 @@
import { type WorkflowStep } from '@/workflow/types/Workflow';
import { TRIGGER_STEP_ID } from 'twenty-shared/workflow';
import { findStepPosition } from '../findStepPosition';
import { findStepPosition } from '@/workflow/utils/findStepPosition';
describe('findStepPosition', () => {
const mockSteps: WorkflowStep[] = [
@@ -1,4 +1,4 @@
import { getAgentIdFromStep } from '../getAgentIdFromStep';
import { getAgentIdFromStep } from '@/workflow/utils/getAgentIdFromStep';
describe('getAgentIdFromStep', () => {
it('should return undefined when stepDefinition is undefined', () => {
@@ -3,7 +3,7 @@ import {
type WorkflowTrigger,
} from '@/workflow/types/Workflow';
import { TRIGGER_STEP_ID } from 'twenty-shared/workflow';
import { getStepDefinitionOrThrow } from '../getStepDefinitionOrThrow';
import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow';
describe('getStepDefinitionOrThrow', () => {
const mockTrigger: WorkflowTrigger = {
@@ -1,4 +1,4 @@
import { getStepOutputSchemaFamilyStateKey } from '../getStepOutputSchemaFamilyStateKey';
import { getStepOutputSchemaFamilyStateKey } from '@/workflow/utils/getStepOutputSchemaFamilyStateKey';
describe('getStepOutputSchemaFamilyStateKey', () => {
it('should concatenate workflowVersionId and stepId with a dash', () => {
@@ -1,4 +1,4 @@
import { getWorkflowVisualizerComponentInstanceId } from '../getWorkflowVisualizerComponentInstanceId';
import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
describe('getWorkflowVisualizerComponentInstanceId', () => {
it('should return the same recordId that was passed in', () => {
@@ -1,4 +1,4 @@
import { isStandaloneVariableString } from '../isStandaloneVariableString';
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
it('returns false if the provided value is not a string', () => {
expect(isStandaloneVariableString(42)).toBe(false);
@@ -1,4 +1,4 @@
import { parseAndValidateVariableFriendlyStringifiedJson } from '../parseAndValidateVariableFriendlyStringifiedJson';
import { parseAndValidateVariableFriendlyStringifiedJson } from '@/workflow/utils/parseAndValidateVariableFriendlyStringifiedJson';
describe('parseAndValidateVariableFriendlyStringifiedJson', () => {
describe('Valid JSON with variable-friendly keys', () => {
@@ -1,4 +1,4 @@
import { splitWorkflowTriggerEventName } from '../splitWorkflowTriggerEventName';
import { splitWorkflowTriggerEventName } from '@/workflow/utils/splitWorkflowTriggerEventName';
describe('splitWorkflowTriggerEventName', () => {
it('should split a basic event name into objectType and event', () => {
@@ -7,7 +7,7 @@ import { RecoilRoot } from 'recoil';
import { ComponentDecorator } from 'twenty-ui/testing';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
import { WorkflowDiagramEmptyTriggerEditable } from '../../workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable';
import { WorkflowDiagramEmptyTriggerEditable } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable';
const meta: Meta<typeof WorkflowDiagramEmptyTriggerEditable> = {
title: 'Modules/Workflow/WorkflowDiagramEmptyTriggerEditable',
@@ -9,7 +9,7 @@ import { CatalogDecorator, type CatalogStory } from 'twenty-ui/testing';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { WorkflowDiagramStepNodeEditableContent } from '../../workflow-nodes/components/WorkflowDiagramStepNodeEditableContent';
import { WorkflowDiagramStepNodeEditableContent } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent';
const meta: Meta<typeof WorkflowDiagramStepNodeEditableContent> = {
title: 'Modules/Workflow/WorkflowDiagramStepNodeEditableContent',
@@ -2,7 +2,7 @@ import {
type WorkflowStep,
type WorkflowTrigger,
} from '@/workflow/types/Workflow';
import { generateWorkflowDiagram } from '../generateWorkflowDiagram';
import { generateWorkflowDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowDiagram';
describe('generateWorkflowDiagram', () => {
it('should generate a single trigger node when no step is provided', () => {
@@ -5,7 +5,7 @@ import {
import { FieldMetadataType } from 'twenty-shared/types';
import { StepStatus, type WorkflowRunStepInfos } from 'twenty-shared/workflow';
import { getUuidV4Mock } from '~/testing/utils/getUuidV4Mock';
import { generateWorkflowRunDiagram } from '../generateWorkflowRunDiagram';
import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
jest.mock('uuid', () => ({
v4: getUuidV4Mock(),
@@ -1,5 +1,5 @@
import { type WorkflowTrigger } from '@/workflow/types/Workflow';
import { getWorkflowDiagramTriggerNode } from '../getWorkflowDiagramTriggerNode';
import { getWorkflowDiagramTriggerNode } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramTriggerNode';
describe('getWorkflowDiagramTriggerNode', () => {
describe('MANUAL trigger type', () => {
@@ -1,5 +1,5 @@
import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { getWorkflowNodeIconKey } from '../getWorkflowNodeIconKey';
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
// Mock the getActionIcon function
jest.mock(
@@ -1,5 +1,5 @@
import { getUuidV4Mock } from '~/testing/utils/getUuidV4Mock';
import { getWorkflowVersionDiagram } from '../getWorkflowVersionDiagram';
import { getWorkflowVersionDiagram } from '@/workflow/workflow-diagram/utils/getWorkflowVersionDiagram';
jest.mock('uuid', () => ({
v4: getUuidV4Mock(),
@@ -2,7 +2,7 @@ import {
type WorkflowIteratorAction,
type WorkflowStep,
} from '@/workflow/types/Workflow';
import { isLastStepOfLoop } from '../isLastStepOfLoop';
import { isLastStepOfLoop } from '@/workflow/workflow-diagram/utils/isLastStepOfLoop';
describe('isLastStepOfLoop', () => {
const makeIterator = (
@@ -1,5 +1,5 @@
import { type WorkflowDiagramNode } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { isStepNode } from '../isStepNode';
import { isStepNode } from '@/workflow/workflow-diagram/utils/isStepNode';
describe('isStepNode', () => {
it('should return true for trigger node', () => {
@@ -1,5 +1,5 @@
import { type WorkflowDiagram } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { mergeWorkflowDiagrams } from '../mergeWorkflowDiagrams';
import { mergeWorkflowDiagrams } from '@/workflow/workflow-diagram/utils/mergeWorkflowDiagrams';
it('Preserves the properties defined in the previous version but not in the next one', () => {
const previousDiagram: WorkflowDiagram = {
@@ -1,5 +1,5 @@
import { type WorkflowDiagram } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { selectWorkflowDiagramNode } from '../selectWorkflowDiagramNode';
import { selectWorkflowDiagramNode } from '@/workflow/workflow-diagram/utils/selectWorkflowDiagramNode';
describe('selectWorkflowDiagramNode', () => {
it('should select the specified node', () => {
@@ -1,7 +1,7 @@
import { act, renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { WorkflowVisualizerComponentInstanceContext } from '../../../workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { useCreateStep } from '../useCreateStep';
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { useCreateStep } from '@/workflow/workflow-steps/hooks/useCreateStep';
const mockGetUpdatableWorkflowVersion = jest.fn();
const mockCreateWorkflowVersionStep = jest.fn().mockResolvedValue({
@@ -3,7 +3,7 @@ import React from 'react';
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
import { renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { WorkflowVisualizerComponentInstanceContext } from '../../../workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
const mockDeleteWorkflowVersionStep = jest.fn();
const mockGetUpdatableWorkflowVersion = jest.fn();
@@ -1,7 +1,7 @@
import { useDuplicateStep } from '@/workflow/workflow-steps/hooks/useDuplicateStep';
import { act, renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { WorkflowVisualizerComponentInstanceContext } from '../../../workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
const mockGetUpdatableWorkflowVersion = jest.fn();
const mockDuplicateWorkflowVersionStep = jest.fn().mockResolvedValue({
@@ -1,5 +1,5 @@
import { renderHook } from '@testing-library/react';
import { useUpdateAgentLabel } from '../useUpdateAgentLabel';
import { useUpdateAgentLabel } from '@/workflow/workflow-steps/hooks/useUpdateAgentLabel';
const mockUpdateAgent = jest.fn();
const mockUseFindOneAgentQuery = jest.fn();
@@ -3,7 +3,7 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
import { isDefined } from 'twenty-shared/utils';
import { getStepInfoHistoryItem } from '../utils/getStepInfoHistoryItem';
import { getStepInfoHistoryItem } from '@/workflow/workflow-steps/utils/getStepInfoHistoryItem';
export const useWorkflowRunStepInfo = ({ stepId }: { stepId: string }) => {
const workflowRunId = useWorkflowRunIdOrThrow();
@@ -1,5 +1,5 @@
import { type WorkflowStep } from '@/workflow/types/Workflow';
import { getIsDescendantOfIterator } from '../getIsDescendantOfIterator';
import { getIsDescendantOfIterator } from '@/workflow/workflow-steps/utils/getIsDescendantOfIterator';
describe('getIsDescendantOfIterator', () => {
const iteratorStep: WorkflowStep = {
@@ -1,6 +1,6 @@
import { type WorkflowStep } from '@/workflow/types/Workflow';
import { type WorkflowRunStepInfo, StepStatus } from 'twenty-shared/workflow';
import { getStepInfoHistoryItem } from '../getStepInfoHistoryItem';
import { getStepInfoHistoryItem } from '@/workflow/workflow-steps/utils/getStepInfoHistoryItem';
describe('getStepInfoHistoryItem', () => {
const iteratorStep: WorkflowStep = {
@@ -1,5 +1,5 @@
import { type WorkflowStep } from '@/workflow/types/Workflow';
import { getPreviousSteps } from '../getWorkflowPreviousSteps';
import { getPreviousSteps } from '@/workflow/workflow-steps/utils/getWorkflowPreviousSteps';
describe('getWorkflowPreviousSteps', () => {
describe('using a simple workflow', () => {
@@ -1,6 +1,6 @@
import { type WorkflowRunFlow } from '@/workflow/types/Workflow';
import { StepStatus, TRIGGER_STEP_ID } from 'twenty-shared/workflow';
import { getWorkflowRunStepContext } from '../getWorkflowRunStepContext';
import { getWorkflowRunStepContext } from '@/workflow/workflow-steps/utils/getWorkflowRunStepContext';
const mockFlow = {
trigger: {
@@ -1,4 +1,4 @@
import { getWorkflowRunStepExecutionStatus } from '../getWorkflowRunStepExecutionStatus';
import { getWorkflowRunStepExecutionStatus } from '@/workflow/workflow-steps/utils/getWorkflowRunStepExecutionStatus';
import { StepStatus } from 'twenty-shared/workflow';
describe('getWorkflowRunStepExecutionStatus', () => {
@@ -3,7 +3,7 @@ import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-perm
import { t } from '@lingui/core/macro';
import { type ObjectPermission } from '~/generated/graphql';
import { filterBySearchQuery } from '~/utils/filterBySearchQuery';
import { CRUD_PERMISSIONS } from '../constants/WorkflowAiAgentCrudPermissions';
import { CRUD_PERMISSIONS } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/constants/WorkflowAiAgentCrudPermissions';
import { WorkflowAiAgentPermissionsPermissionRow } from './WorkflowAiAgentPermissionsPermissionRow';
import { StyledLabel, StyledList } from './WorkflowAiAgentPermissionsStyles';
@@ -32,7 +32,7 @@ import {
} from '~/generated-metadata/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { RightDrawerSkeletonLoader } from '~/loading/components/RightDrawerSkeletonLoader';
import { WORKFLOW_AI_AGENT_TAB_LIST_COMPONENT_ID } from '../constants/WorkflowAiAgentTabListComponentId';
import { WORKFLOW_AI_AGENT_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/constants/WorkflowAiAgentTabListComponentId';
import { WorkflowAiAgentPromptTab } from './WorkflowAiAgentPromptTab';
export type WorkflowAiAgentTabId =
@@ -9,7 +9,7 @@ import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorato
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
import { WorkflowEditActionCreateRecord } from '../WorkflowEditActionCreateRecord';
import { WorkflowEditActionCreateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord';
const meta: Meta<typeof WorkflowEditActionCreateRecord> = {
title: 'Modules/Workflow/Actions/CreateRecord/EditAction',
@@ -11,7 +11,7 @@ import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { allMockPersonRecords } from '~/testing/mock-data/people';
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
import { WorkflowEditActionDeleteRecord } from '../WorkflowEditActionDeleteRecord';
import { WorkflowEditActionDeleteRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionDeleteRecord';
const DEFAULT_ACTION = {
id: getWorkflowNodeIdMock(),
@@ -15,7 +15,7 @@ import {
mockedConnectedAccounts,
} from '~/testing/mock-data/connected-accounts';
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
import { WorkflowEditActionSendEmail } from '../WorkflowEditActionSendEmail';
import { WorkflowEditActionSendEmail } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail';
const DEFAULT_ACTION: WorkflowSendEmailAction = {
id: getWorkflowNodeIdMock(),
@@ -11,7 +11,7 @@ import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { allMockPersonRecords } from '~/testing/mock-data/people';
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
import { WorkflowEditActionUpdateRecord } from '../WorkflowEditActionUpdateRecord';
import { WorkflowEditActionUpdateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord';
const DEFAULT_ACTION = {
id: getWorkflowNodeIdMock(),
@@ -9,7 +9,7 @@ import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorato
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
import { WorkflowEditActionFilter } from '../WorkflowEditActionFilter';
import { WorkflowEditActionFilter } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilter';
const DEFAULT_ACTION: WorkflowFilterAction = {
id: getWorkflowNodeIdMock(),
@@ -9,7 +9,7 @@ import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorato
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
import { WorkflowEditActionFilterBody } from '../WorkflowEditActionFilterBody';
import { WorkflowEditActionFilterBody } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody';
const DEFAULT_ACTION: WorkflowFilterAction = {
id: getWorkflowNodeIdMock(),
@@ -8,7 +8,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { WorkflowStepFilterAddFilterRuleSelect } from '../WorkflowStepFilterAddFilterRuleSelect';
import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterAddFilterRuleSelect';
const STEP_FILTER_GROUP: StepFilterGroup = {
id: 'filter-group-1',
@@ -7,7 +7,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { WorkflowStepFilterAddRootStepFilterButton } from '../WorkflowStepFilterAddRootStepFilterButton';
import { WorkflowStepFilterAddRootStepFilterButton } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterAddRootStepFilterButton';
const meta: Meta<typeof WorkflowStepFilterAddRootStepFilterButton> = {
title:
@@ -12,7 +12,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { WorkflowStepFilterColumn } from '../WorkflowStepFilterColumn';
import { WorkflowStepFilterColumn } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterColumn';
const STEP_FILTER_GROUP: StepFilterGroup = {
id: 'filter-group-1',
@@ -7,7 +7,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { WorkflowStepFilterFieldSelect } from '../WorkflowStepFilterFieldSelect';
import { WorkflowStepFilterFieldSelect } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect';
const DEFAULT_STEP_FILTER: StepFilter = {
id: 'filter-1',
@@ -8,7 +8,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { WorkflowStepFilterLogicalOperatorCell } from '../WorkflowStepFilterLogicalOperatorCell';
import { WorkflowStepFilterLogicalOperatorCell } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterLogicalOperatorCell';
const AND_STEP_FILTER_GROUP: StepFilterGroup = {
id: 'filter-group-1',
@@ -8,7 +8,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { WorkflowStepFilterValueInput } from '../WorkflowStepFilterValueInput';
import { WorkflowStepFilterValueInput } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterValueInput';
const TEXT_FILTER: StepFilter = {
id: 'filter-1',
@@ -5,7 +5,7 @@ import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/work
import { useContext } from 'react';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { WorkflowStepFilterContext } from '../states/context/WorkflowStepFilterContext';
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
export const useRemoveStepFilter = () => {
const { onFilterSettingsUpdate } = useContext(WorkflowStepFilterContext);
@@ -6,7 +6,7 @@ import { ComponentDecorator } from 'twenty-ui/testing';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
import { WorkflowEditActionFormFieldSettings } from '../WorkflowEditActionFormFieldSettings';
import { WorkflowEditActionFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFieldSettings';
const meta: Meta<typeof WorkflowEditActionFormFieldSettings> = {
title: 'Modules/Workflow/Actions/Form/WorkflowEditActionFormFieldSettings',
@@ -10,7 +10,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { WorkflowEditActionFormFiller } from '../WorkflowEditActionFormFiller';
import { WorkflowEditActionFormFiller } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller';
const meta: Meta<typeof WorkflowEditActionFormFiller> = {
title: 'Modules/Workflow/Actions/Form/WorkflowEditActionFormFiller',
@@ -1,7 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';
import { expect, within } from '@storybook/test';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { WorkflowFormEmptyMessage } from '../WorkflowFormEmptyMessage';
import { WorkflowFormEmptyMessage } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormEmptyMessage';
const meta: Meta<typeof WorkflowFormEmptyMessage> = {
title: 'Modules/Workflow/Actions/Form/WorkflowFormEmptyMessage',
@@ -1,6 +1,6 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { v4 } from 'uuid';
import { getDefaultFormFieldSettings } from '../getDefaultFormFieldSettings';
import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings';
jest.mock('uuid', () => ({
v4: jest.fn(() => 'test-uuid-123'),
@@ -21,12 +21,12 @@ import { IconPlayerPlay, IconSettings } from 'twenty-ui/display';
import {
HTTP_METHODS,
JSON_RESPONSE_PLACEHOLDER,
} from '../constants/HttpRequest';
import { WORKFLOW_HTTP_REQUEST_TAB_LIST_COMPONENT_ID } from '../constants/WorkflowHttpRequestTabListComponentId';
import { useHttpRequestForm } from '../hooks/useHttpRequestForm';
import { useHttpRequestOutputSchema } from '../hooks/useHttpRequestOutputSchema';
import { useTestHttpRequest } from '../hooks/useTestHttpRequest';
import { WorkflowHttpRequestTabId } from '../types/WorkflowHttpRequestTabId';
} from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/HttpRequest';
import { WORKFLOW_HTTP_REQUEST_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/WorkflowHttpRequestTabListComponentId';
import { useHttpRequestForm } from '@/workflow/workflow-steps/workflow-actions/http-request-action/hooks/useHttpRequestForm';
import { useHttpRequestOutputSchema } from '@/workflow/workflow-steps/workflow-actions/http-request-action/hooks/useHttpRequestOutputSchema';
import { useTestHttpRequest } from '@/workflow/workflow-steps/workflow-actions/http-request-action/hooks/useTestHttpRequest';
import { WorkflowHttpRequestTabId } from '@/workflow/workflow-steps/workflow-actions/http-request-action/types/WorkflowHttpRequestTabId';
import { BodyInput } from './BodyInput';
import { HttpRequestExecutionResult } from './HttpRequestExecutionResult';
import { HttpRequestTestVariableInput } from './HttpRequestTestVariableInput';
@@ -13,7 +13,7 @@ import {
getWorkflowNodeIdMock,
MOCKED_STEP_ID,
} from '~/testing/mock-data/workflow';
import { WorkflowEditActionHttpRequest } from '../WorkflowEditActionHttpRequest';
import { WorkflowEditActionHttpRequest } from '@/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest';
const DEFAULT_ACTION: WorkflowHttpRequestAction = {
id: getWorkflowNodeIdMock(),
@@ -1,6 +1,6 @@
import { type WorkflowHttpRequestAction } from '@/workflow/types/Workflow';
import { act, renderHook } from '@testing-library/react';
import { useHttpRequestForm } from '../useHttpRequestForm';
import { useHttpRequestForm } from '@/workflow/workflow-steps/workflow-actions/http-request-action/hooks/useHttpRequestForm';
describe('useHttpRequestForm', () => {
const mockAction: WorkflowHttpRequestAction = {
@@ -5,7 +5,7 @@ import { act, renderHook } from '@testing-library/react';
import React from 'react';
import { RecoilRoot } from 'recoil';
import { resolveInput } from 'twenty-shared/utils';
import { useTestHttpRequest } from '../useTestHttpRequest';
import { useTestHttpRequest } from '@/workflow/workflow-steps/workflow-actions/http-request-action/hooks/useTestHttpRequest';
// Mock Apollo Client
jest.mock('@apollo/client', () => ({
@@ -5,7 +5,7 @@ import { useDebouncedCallback } from 'use-debounce';
import {
type HttpRequestBody,
type HttpRequestFormData,
} from '../constants/HttpRequest';
} from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/HttpRequest';
export type UseHttpRequestFormParams = {
action: WorkflowHttpRequestAction;
@@ -3,8 +3,8 @@ import { parseAndValidateVariableFriendlyStringifiedJson } from '@/workflow/util
import { isNonEmptyString } from '@sniptt/guards';
import { useState } from 'react';
import { type BaseOutputSchemaV2 } from 'twenty-shared/workflow';
import { convertOutputSchemaToJson } from '../utils/convertOutputSchemaToJson';
import { getHttpRequestOutputSchema } from '../utils/getHttpRequestOutputSchema';
import { convertOutputSchemaToJson } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/convertOutputSchemaToJson';
import { getHttpRequestOutputSchema } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/getHttpRequestOutputSchema';
type UseHttpRequestOutputSchemaProps = {
action: WorkflowHttpRequestAction;
@@ -1,5 +1,5 @@
import { type BaseOutputSchemaV2 } from 'twenty-shared/workflow';
import { convertOutputSchemaToJson } from '../convertOutputSchemaToJson';
import { convertOutputSchemaToJson } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/convertOutputSchemaToJson';
describe('convertOutputSchemaToJson', () => {
it('should convert simple object schema to JSON', () => {
@@ -1,5 +1,5 @@
import { BODY_TYPES } from '../../constants/HttpRequest';
import { getBodyTypeFromHeaders } from '../getBodyTypeFromHeaders';
import { BODY_TYPES } from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/HttpRequest';
import { getBodyTypeFromHeaders } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/getBodyTypeFromHeaders';
describe('getBodyTypeFromHeaders', () => {
describe('when headers is undefined or null', () => {
@@ -1,4 +1,4 @@
import { getHttpRequestOutputSchema } from '../getHttpRequestOutputSchema';
import { getHttpRequestOutputSchema } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/getHttpRequestOutputSchema';
describe('getHttpRequestOutputSchema', () => {
it('should return empty object for null input', () => {
@@ -1,5 +1,5 @@
import { type HttpRequestBody } from '../../constants/HttpRequest';
import { hasNonStringValues } from '../hasNonStringValues';
import { type HttpRequestBody } from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/HttpRequest';
import { hasNonStringValues } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/hasNonStringValues';
describe('hasNonStringValues', () => {
it('should return true for empty object', () => {
@@ -1,5 +1,5 @@
import { type HttpMethodWithBody } from '../../constants/HttpRequest';
import { isMethodWithBody } from '../isMethodWithBody';
import { type HttpMethodWithBody } from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/HttpRequest';
import { isMethodWithBody } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/isMethodWithBody';
describe('isMethodWithBody', () => {
it('should return false for null input', () => {
@@ -1,4 +1,4 @@
import { parseHttpJsonBodyWithoutVariablesOrThrow } from '../parseHttpJsonBodyWithoutVariablesOrThrow';
import { parseHttpJsonBodyWithoutVariablesOrThrow } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/parseHttpJsonBodyWithoutVariablesOrThrow';
describe('parseHttpJsonBodyWithoutVariablesOrThrow', () => {
it('should parse valid JSON without variables', () => {
@@ -1,5 +1,5 @@
import { type HttpRequestBody } from '../../constants/HttpRequest';
import { shouldDisplayRawJsonByDefault } from '../shouldDisplayRawJsonByDefault';
import { type HttpRequestBody } from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/HttpRequest';
import { shouldDisplayRawJsonByDefault } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/shouldDisplayRawJsonByDefault';
describe('shouldDisplayRawJsonByDefault', () => {
describe('when defaultValue is undefined', () => {
@@ -1,4 +1,4 @@
import { AUTO_SET_HEADER_KEYS } from '../constants/AutoSetHeaderKeys';
import { AUTO_SET_HEADER_KEYS } from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/AutoSetHeaderKeys';
export const isAutoSetHeaderKey = (key: string): boolean => {
return AUTO_SET_HEADER_KEYS.includes(key.trim().toLowerCase());
@@ -1,4 +1,4 @@
import { getActionHeaderTypeOrThrow } from '../getActionHeaderTypeOrThrow';
import { getActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionHeaderTypeOrThrow';
describe('getActionHeaderTypeOrThrow', () => {
it('should return "Core" for CODE action type', () => {
@@ -1,8 +1,8 @@
import { AI_ACTIONS } from '../../constants/AiActions';
import { CORE_ACTIONS } from '../../constants/CoreActions';
import { HUMAN_INPUT_ACTIONS } from '../../constants/HumanInputActions';
import { RECORD_ACTIONS } from '../../constants/RecordActions';
import { getActionIcon } from '../getActionIcon';
import { AI_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/AiActions';
import { CORE_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/CoreActions';
import { HUMAN_INPUT_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/HumanInputActions';
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
describe('getActionIcon', () => {
it('should return correct icon for all action types', () => {
@@ -1,7 +1,7 @@
import { type WorkflowActionType } from '@/workflow/types/Workflow';
import { type Theme } from '@emotion/react';
import { COLOR_LIGHT, GRAY_SCALE_LIGHT } from 'twenty-ui/theme';
import { getActionIconColorOrThrow } from '../getActionIconColorOrThrow';
import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow';
const mockTheme: Theme = {
color: {
@@ -1,6 +1,6 @@
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { COMMAND_MENU_DEFAULT_ICON } from '@/workflow/workflow-trigger/constants/CommandMenuDefaultIcon';
import { getManualTriggerDefaultSettings } from '../getManualTriggerDefaultSettings';
import { getManualTriggerDefaultSettings } from '@/workflow/workflow-trigger/utils/getManualTriggerDefaultSettings';
const mockObjectMetadataItems: ObjectMetadataItem[] = [
{
@@ -1,5 +1,5 @@
import { type WorkflowAction } from '@/workflow/types/Workflow';
import { getRootStepIds } from '../getRootStepIds';
import { getRootStepIds } from '@/workflow/workflow-trigger/utils/getRootStepIds';
describe('getRootStepIds', () => {
it('should return empty array for empty steps', () => {
@@ -1,7 +1,7 @@
import { COMMAND_MENU_DEFAULT_ICON } from '@/workflow/workflow-trigger/constants/CommandMenuDefaultIcon';
import { DatabaseTriggerDefaultLabel } from '@/workflow/workflow-trigger/constants/DatabaseTriggerDefaultLabel';
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
import { getTriggerDefaultDefinition } from '../getTriggerDefaultDefinition';
import { getTriggerDefaultDefinition } from '@/workflow/workflow-trigger/utils/getTriggerDefaultDefinition';
describe('getTriggerDefaultDefinition', () => {
it('throws if the activeNonSystemObjectMetadataItems list is empty', () => {
@@ -1,5 +1,5 @@
import { type WorkflowTrigger } from '@/workflow/types/Workflow';
import { getTriggerHeaderType } from '../getTriggerHeaderType';
import { getTriggerHeaderType } from '@/workflow/workflow-trigger/utils/getTriggerHeaderType';
describe('getTriggerHeaderType', () => {
describe('DATABASE_EVENT triggers', () => {
@@ -1,6 +1,6 @@
import { type Theme } from '@emotion/react';
import { COLOR_LIGHT } from 'twenty-ui/theme';
import { getTriggerIconColor } from '../getTriggerIconColor';
import { getTriggerIconColor } from '@/workflow/workflow-trigger/utils/getTriggerIconColor';
describe('getTriggerIconColor', () => {
const mockTheme: Theme = {
@@ -5,7 +5,7 @@ import { getOrdinalNumber } from '~/utils/format/getOrdinalNumber';
import { isListValue } from '~/utils/validation/isListValue';
import { isNumericRange } from '~/utils/validation/isNumericRange';
import { isStepValue } from '~/utils/validation/isStepValue';
import { type CronDescriptionOptions } from '../types/cronDescriptionOptions';
import { type CronDescriptionOptions } from '@/workflow/workflow-trigger/utils/cron-to-human/types/cronDescriptionOptions';
export const getDayOfMonthDescription = (
dayOfMonth: string,
@@ -5,7 +5,7 @@ import { isDefined } from 'twenty-shared/utils';
import { isListValue } from '~/utils/validation/isListValue';
import { isNumericRange } from '~/utils/validation/isNumericRange';
import { isStepValue } from '~/utils/validation/isStepValue';
import { type CronDescriptionOptions } from '../types/cronDescriptionOptions';
import { type CronDescriptionOptions } from '@/workflow/workflow-trigger/utils/cron-to-human/types/cronDescriptionOptions';
const getDayName = (
dayNum: number,
@@ -5,7 +5,7 @@ import { formatTime as formatCronTime } from '~/utils/format/formatTime';
import { isListValue } from '~/utils/validation/isListValue';
import { isNumericRange } from '~/utils/validation/isNumericRange';
import { isStepValue } from '~/utils/validation/isStepValue';
import { type CronDescriptionOptions } from '../types/cronDescriptionOptions';
import { type CronDescriptionOptions } from '@/workflow/workflow-trigger/utils/cron-to-human/types/cronDescriptionOptions';
export const getHoursDescription = (
hours: string,
@@ -4,7 +4,7 @@ import { isDefined } from 'twenty-shared/utils';
import { isListValue } from '~/utils/validation/isListValue';
import { isNumericRange } from '~/utils/validation/isNumericRange';
import { isStepValue } from '~/utils/validation/isStepValue';
import { type CronDescriptionOptions } from '../types/cronDescriptionOptions';
import { type CronDescriptionOptions } from '@/workflow/workflow-trigger/utils/cron-to-human/types/cronDescriptionOptions';
export const getMinutesDescription = (
minutes: string,
@@ -5,7 +5,7 @@ import { isDefined } from 'twenty-shared/utils';
import { isListValue } from '~/utils/validation/isListValue';
import { isNumericRange } from '~/utils/validation/isNumericRange';
import { isStepValue } from '~/utils/validation/isStepValue';
import { type CronDescriptionOptions } from '../types/cronDescriptionOptions';
import { type CronDescriptionOptions } from '@/workflow/workflow-trigger/utils/cron-to-human/types/cronDescriptionOptions';
const getMonthName = (
monthNum: number,
@@ -1,6 +1,6 @@
import { isDefined } from 'twenty-shared/utils';
import { type CronFieldType } from '../types/cronExpressionParts';
import { type CronFieldType } from '@/workflow/workflow-trigger/utils/cron-to-human/types/cronExpressionParts';
type FieldRange = {
min: number;
@@ -21,7 +21,7 @@ import {
useIcons,
} from 'twenty-ui/display';
import { MenuItemSelect } from 'twenty-ui/navigation';
import { useVariableDropdown } from '../hooks/useVariableDropdown';
import { useVariableDropdown } from '@/workflow/workflow-variables/hooks/useVariableDropdown';
type WorkflowVariablesDropdownStepItemsProps = {
step: StepOutputSchemaV2;
@@ -15,10 +15,10 @@ import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { type BaseOutputSchemaV2 } from 'twenty-shared/workflow';
import { useIcons } from 'twenty-ui/display';
import { isBaseOutputSchemaV2 } from '../types/guards/isBaseOutputSchemaV2';
import { isLinkOutputSchema } from '../types/guards/isLinkOutputSchema';
import { isRecordOutputSchemaV2 } from '../types/guards/isRecordOutputSchemaV2';
import { getCurrentSubStepFromPath } from '../utils/getCurrentSubStepFromPath';
import { isBaseOutputSchemaV2 } from '@/workflow/workflow-variables/types/guards/isBaseOutputSchemaV2';
import { isLinkOutputSchema } from '@/workflow/workflow-variables/types/guards/isLinkOutputSchema';
import { isRecordOutputSchemaV2 } from '@/workflow/workflow-variables/types/guards/isRecordOutputSchemaV2';
import { getCurrentSubStepFromPath } from '@/workflow/workflow-variables/utils/getCurrentSubStepFromPath';
type UseVariableDropdownProps = {
step: StepOutputSchemaV2;
@@ -3,7 +3,7 @@ import {
type WorkflowTriggerType,
} from '@/workflow/types/Workflow';
import { type OutputSchemaV2 } from '@/workflow/workflow-variables/types/StepOutputSchemaV2';
import { type IteratorOutputSchema } from '../IteratorOutputSchema';
import { type IteratorOutputSchema } from '@/workflow/workflow-variables/types/IteratorOutputSchema';
export const isIteratorOutputSchema = (
stepType: WorkflowActionType | WorkflowTriggerType,
@@ -1,7 +1,7 @@
import { type RecordOutputSchemaV2 } from '@/workflow/workflow-variables/types/RecordOutputSchemaV2';
import { FieldMetadataType } from 'twenty-shared/types';
import { type BaseOutputSchemaV2 } from 'twenty-shared/workflow';
import { filterOutputSchema } from '../filterOutputSchema';
import { filterOutputSchema } from '@/workflow/workflow-variables/utils/filterOutputSchema';
describe('filterOutputSchema', () => {
const createRecordSchema = (
@@ -1,4 +1,4 @@
import { getInitialEditorContent } from '../getInitialEditorContent';
import { getInitialEditorContent } from '@/workflow/workflow-variables/utils/getInitialEditorContent';
describe('getInitialEditorContent', () => {
it('should handle single line text', () => {
@@ -1,5 +1,5 @@
import type { JSONContent } from '@tiptap/react';
import { parseEditorContent } from '../parseEditorContent';
import { parseEditorContent } from '@/workflow/workflow-variables/utils/parseEditorContent';
describe('parseEditorContent', () => {
it('should parse empty doc', () => {