diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx index 27e8892734..3c6b671df1 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx @@ -25,7 +25,7 @@ export const CommandMenuWorkflowEditStep = () => { - + ); diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx index ef7fbbbc1a..7590731958 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx @@ -1,6 +1,5 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; -import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep'; @@ -14,20 +13,14 @@ const StyledContainer = styled.div` height: 100%; `; -export const CommandMenuWorkflowEditStepContent = ({ - workflow, -}: { - workflow: WorkflowWithCurrentVersion; -}) => { +export const CommandMenuWorkflowEditStepContent = () => { const flow = useFlowOrThrow(); const workflowSelectedNode = useRecoilComponentValue( workflowSelectedNodeComponentState, ); - const { updateTrigger } = useUpdateWorkflowVersionTrigger({ workflow }); - const { updateStep } = useUpdateStep({ - workflow, - }); + const { updateTrigger } = useUpdateWorkflowVersionTrigger(); + const { updateStep } = useUpdateStep(); if (!isDefined(workflowSelectedNode)) { return null; diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx index b55084b4ac..7c405bfb59 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx @@ -24,7 +24,7 @@ export const CommandMenuWorkflowSelectTriggerTypeContent = ({ workflow: WorkflowWithCurrentVersion; }) => { const { getIcon } = useIcons(); - const { updateTrigger } = useUpdateWorkflowVersionTrigger({ workflow }); + const { updateTrigger } = useUpdateWorkflowVersionTrigger(); const { activeNonSystemObjectMetadataItems } = useFilteredObjectMetadataItems(); diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx index 6a407fca56..956f658a07 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx @@ -158,7 +158,7 @@ export const CardComponents: Record = { > }> - + ); diff --git a/packages/twenty-front/src/modules/serverless-functions/components/ServerlessFunctionExecutionResult.tsx b/packages/twenty-front/src/modules/serverless-functions/components/ServerlessFunctionExecutionResult.tsx index 40c3ddb3ab..65182f635d 100644 --- a/packages/twenty-front/src/modules/serverless-functions/components/ServerlessFunctionExecutionResult.tsx +++ b/packages/twenty-front/src/modules/serverless-functions/components/ServerlessFunctionExecutionResult.tsx @@ -2,7 +2,7 @@ import { type ExecutionStatus, WorkflowStepExecutionResult, } from '@/workflow/components/WorkflowStepExecutionResult'; -import { type ServerlessFunctionTestData } from '@/workflow/states/serverlessFunctionTestDataFamilyState'; +import { type ServerlessFunctionTestData } from '@/workflow/workflow-steps/workflow-actions/code-action/states/serverlessFunctionTestDataFamilyState'; import { ServerlessFunctionExecutionStatus } from '~/generated-metadata/graphql'; export const ServerlessFunctionExecutionResult = ({ diff --git a/packages/twenty-front/src/modules/serverless-functions/hooks/useTestServerlessFunction.ts b/packages/twenty-front/src/modules/serverless-functions/hooks/useTestServerlessFunction.ts index 585f619666..04c208aa1b 100644 --- a/packages/twenty-front/src/modules/serverless-functions/hooks/useTestServerlessFunction.ts +++ b/packages/twenty-front/src/modules/serverless-functions/hooks/useTestServerlessFunction.ts @@ -1,9 +1,9 @@ import { useExecuteOneServerlessFunction } from '@/settings/serverless-functions/hooks/useExecuteOneServerlessFunction'; -import { serverlessFunctionTestDataFamilyState } from '@/workflow/states/serverlessFunctionTestDataFamilyState'; +import { serverlessFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/serverlessFunctionTestDataFamilyState'; import { useState } from 'react'; import { useRecoilState } from 'recoil'; -import { sleep } from '~/utils/sleep'; import { isDefined } from 'twenty-shared/utils'; +import { sleep } from '~/utils/sleep'; export const useTestServerlessFunction = ({ serverlessFunctionId, diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab.tsx index e32f219051..b40aa951da 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab.tsx +++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTestTab.tsx @@ -1,5 +1,5 @@ import { ServerlessFunctionExecutionResult } from '@/serverless-functions/components/ServerlessFunctionExecutionResult'; -import { serverlessFunctionTestDataFamilyState } from '@/workflow/states/serverlessFunctionTestDataFamilyState'; +import { serverlessFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/serverlessFunctionTestDataFamilyState'; import styled from '@emotion/styled'; import { useRecoilState } from 'recoil'; import { H2Title, IconPlayerPlay } from 'twenty-ui/display'; diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts index 09bd194356..f77bcc2b7f 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts +++ b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts @@ -2,7 +2,7 @@ import { INDEX_FILE_PATH } from '@/serverless-functions/constants/IndexFilePath' import { getFunctionInputFromSourceCode } from '@/serverless-functions/utils/getFunctionInputFromSourceCode'; import { useGetOneServerlessFunction } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunction'; import { useGetOneServerlessFunctionSourceCode } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode'; -import { serverlessFunctionTestDataFamilyState } from '@/workflow/states/serverlessFunctionTestDataFamilyState'; +import { serverlessFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/serverlessFunctionTestDataFamilyState'; import { type Dispatch, type SetStateAction, useState } from 'react'; import { useRecoilState } from 'recoil'; import { type FindOneServerlessFunctionSourceCodeQuery } from '~/generated-metadata/graphql'; diff --git a/packages/twenty-front/src/modules/workflow/hooks/__tests__/useGetUpdatableWorkflowVersion.test.ts b/packages/twenty-front/src/modules/workflow/hooks/__tests__/useGetUpdatableWorkflowVersion.test.ts index 036444ae22..92c93f2ae9 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/__tests__/useGetUpdatableWorkflowVersion.test.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/__tests__/useGetUpdatableWorkflowVersion.test.ts @@ -1,8 +1,16 @@ -import { renderHook } from '@testing-library/react'; -import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; +import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; +import { renderHook } from '@testing-library/react'; const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457'); +const mockWorkflowId = '123'; +const mockWorkflow = { + id: mockWorkflowId, + currentVersion: { + id: '456', + status: 'DRAFT', + }, +} as WorkflowWithCurrentVersion; jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({ useCreateDraftFromWorkflowVersion: () => ({ @@ -10,43 +18,75 @@ jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({ }), })); -describe('useGetUpdatableWorkflowVersion', () => { - const mockWorkflow = (status: 'ACTIVE' | 'DRAFT') => - ({ - id: '123', - __typename: 'Workflow', - statuses: [], - lastPublishedVersionId: '1', - name: 'toto', - versions: [], - currentVersion: { - id: '456', - name: 'toto', - createdAt: '2024-07-03T20:03:35.064Z', - updatedAt: '2024-07-03T20:03:35.064Z', - workflowId: '123', - __typename: 'WorkflowVersion', - status, - steps: [], - trigger: null, - }, - }) as WorkflowWithCurrentVersion; +jest.mock( + '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue', + () => ({ + useRecoilComponentValue: jest.fn(() => mockWorkflowId), + }), +); - it('should not create workflow version if draft version exists', async () => { - const { result } = renderHook(() => useGetUpdatableWorkflowVersion()); - const workflowVersionId = await result.current.getUpdatableWorkflowVersion( - mockWorkflow('DRAFT'), +jest.mock('@/workflow/hooks/useWorkflowWithCurrentVersion', () => ({ + useWorkflowWithCurrentVersion: jest.fn((workflowId) => + workflowId === mockWorkflowId ? mockWorkflow : undefined, + ), +})); + +describe('useGetUpdatableWorkflowVersionOrThrow', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return draft version id when current version is draft', async () => { + const { result } = renderHook(() => + useGetUpdatableWorkflowVersionOrThrow(), ); + const workflowVersionId = + await result.current.getUpdatableWorkflowVersion(); + expect(mockCreateDraftFromWorkflowVersion).not.toHaveBeenCalled(); expect(workflowVersionId).toEqual('456'); }); - it('should create workflow version if no draft version exists', async () => { - const { result } = renderHook(() => useGetUpdatableWorkflowVersion()); - const workflowVersionId = await result.current.getUpdatableWorkflowVersion( - mockWorkflow('ACTIVE'), + it('should create draft from active version when current version is active', async () => { + // Mock the workflow to have an active version + const mockActiveWorkflow = { + ...mockWorkflow, + currentVersion: { + ...mockWorkflow.currentVersion, + status: 'ACTIVE', + }, + } as WorkflowWithCurrentVersion; + + const { + useWorkflowWithCurrentVersion, + } = require('@/workflow/hooks/useWorkflowWithCurrentVersion'); + useWorkflowWithCurrentVersion.mockReturnValue(mockActiveWorkflow); + + const { result } = renderHook(() => + useGetUpdatableWorkflowVersionOrThrow(), ); - expect(mockCreateDraftFromWorkflowVersion).toHaveBeenCalled(); + const workflowVersionId = + await result.current.getUpdatableWorkflowVersion(); + + expect(mockCreateDraftFromWorkflowVersion).toHaveBeenCalledWith({ + workflowId: mockWorkflowId, + workflowVersionIdToCopy: '456', + }); expect(workflowVersionId).toEqual('457'); }); + + it('should throw an error when workflow is not found', async () => { + const { + useWorkflowWithCurrentVersion, + } = require('@/workflow/hooks/useWorkflowWithCurrentVersion'); + useWorkflowWithCurrentVersion.mockReturnValue(undefined); + + const { result } = renderHook(() => + useGetUpdatableWorkflowVersionOrThrow(), + ); + + await expect(result.current.getUpdatableWorkflowVersion()).rejects.toThrow( + 'Failed to get updatable workflow version', + ); + }); }); diff --git a/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersion.ts b/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersion.ts deleted file mode 100644 index 327cdd043f..0000000000 --- a/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersion.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; -import { useCreateDraftFromWorkflowVersion } from '@/workflow/hooks/useCreateDraftFromWorkflowVersion'; - -export const useGetUpdatableWorkflowVersion = () => { - const { createDraftFromWorkflowVersion } = - useCreateDraftFromWorkflowVersion(); - const getUpdatableWorkflowVersion = async ( - workflow: WorkflowWithCurrentVersion, - ) => { - if (workflow.currentVersion.status === 'DRAFT') { - return workflow.currentVersion.id; - } - return await createDraftFromWorkflowVersion({ - workflowId: workflow.id, - workflowVersionIdToCopy: workflow.currentVersion.id, - }); - }; - - return { getUpdatableWorkflowVersion }; -}; diff --git a/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts b/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts new file mode 100644 index 0000000000..7e1eac57bf --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow.ts @@ -0,0 +1,37 @@ +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useCreateDraftFromWorkflowVersion } from '@/workflow/hooks/useCreateDraftFromWorkflowVersion'; +import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; +import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; +import { isDefined } from 'twenty-shared/utils'; + +export const useGetUpdatableWorkflowVersionOrThrow = () => { + const { createDraftFromWorkflowVersion } = + useCreateDraftFromWorkflowVersion(); + const workflowVisualizerWorkflowId = useRecoilComponentValue( + workflowVisualizerWorkflowIdComponentState, + ); + const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId); + + const getUpdatableWorkflowVersion = async (): Promise => { + if (!isDefined(workflowVisualizerWorkflowId) || !isDefined(workflow)) { + throw new Error('Failed to get updatable workflow version'); + } + + if (workflow.currentVersion.status === 'DRAFT') { + return workflow.currentVersion.id; + } + + const draftVersionId = await createDraftFromWorkflowVersion({ + workflowId: workflowVisualizerWorkflowId, + workflowVersionIdToCopy: workflow.currentVersion.id, + }); + + if (!isDefined(draftVersionId)) { + throw new Error('Failed to create draft version'); + } + + return draftVersionId; + }; + + return { getUpdatableWorkflowVersion }; +}; diff --git a/packages/twenty-front/src/modules/workflow/utils/__tests__/assertWorkflowWithCurrentVersionIsDefined.test.ts b/packages/twenty-front/src/modules/workflow/utils/__tests__/assertWorkflowWithCurrentVersionIsDefined.test.ts deleted file mode 100644 index af417e2801..0000000000 --- a/packages/twenty-front/src/modules/workflow/utils/__tests__/assertWorkflowWithCurrentVersionIsDefined.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; -import { assertWorkflowWithCurrentVersionIsDefined } from '../assertWorkflowWithCurrentVersionIsDefined'; - -it('throws when provided workflow is undefined', () => { - expect(() => { - assertWorkflowWithCurrentVersionIsDefined(undefined); - }).toThrow(); -}); - -it("throws when provided workflow's current version is undefined", () => { - expect(() => { - assertWorkflowWithCurrentVersionIsDefined( - {} as unknown as WorkflowWithCurrentVersion, - ); - }).toThrow(); -}); diff --git a/packages/twenty-front/src/modules/workflow/utils/assertWorkflowWithCurrentVersionIsDefined.ts b/packages/twenty-front/src/modules/workflow/utils/assertWorkflowWithCurrentVersionIsDefined.ts deleted file mode 100644 index 4e3350815c..0000000000 --- a/packages/twenty-front/src/modules/workflow/utils/assertWorkflowWithCurrentVersionIsDefined.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { - type Workflow, - type WorkflowVersion, - type WorkflowWithCurrentVersion, -} from '@/workflow/types/Workflow'; -import { isDefined } from 'twenty-shared/utils'; - -// eslint-disable-next-line prefer-arrow/prefer-arrow-functions -export function assertWorkflowWithCurrentVersionIsDefined( - workflow: WorkflowWithCurrentVersion | undefined, -): asserts workflow is Workflow & { currentVersion: WorkflowVersion } { - if (!isDefined(workflow) || !isDefined(workflow.currentVersion)) { - throw new Error('Expected workflow and its current version to be defined'); - } -} diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable.tsx index d006ba26b7..a7651b61c2 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable.tsx @@ -1,5 +1,7 @@ +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; +import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; +import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { WorkflowDiagramBlankEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramBlankEdge'; import { WorkflowDiagramCanvasBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase'; import { WorkflowDiagramCanvasEditableEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditableEffect'; @@ -23,14 +25,14 @@ import { addEdge, type Connection, ReactFlowProvider } from '@xyflow/react'; import React from 'react'; import { isDefined } from 'twenty-shared/utils'; -export const WorkflowDiagramCanvasEditable = ({ - workflowWithCurrentVersion, -}: { - workflowWithCurrentVersion: WorkflowWithCurrentVersion; -}) => { - const tagProps = getWorkflowVersionStatusTagProps({ - workflowVersionStatus: workflowWithCurrentVersion.currentVersion.status, - }); +export const WorkflowDiagramCanvasEditable = () => { + const workflowVisualizerWorkflowId = useRecoilComponentValue( + workflowVisualizerWorkflowIdComponentState, + ); + + const workflowWithCurrentVersion = useWorkflowWithCurrentVersion( + workflowVisualizerWorkflowId, + ); const setWorkflowDiagram = useSetRecoilComponentState( workflowDiagramComponentState, @@ -40,21 +42,13 @@ export const WorkflowDiagramCanvasEditable = ({ workflowDiagramRightClickMenuPositionState, ); - const { createEdge } = useCreateEdge({ - workflow: workflowWithCurrentVersion, - }); + const { createEdge } = useCreateEdge(); - const { deleteEdge } = useDeleteEdge({ - workflow: workflowWithCurrentVersion, - }); + const { deleteEdge } = useDeleteEdge(); - const { updateStep } = useUpdateStep({ - workflow: workflowWithCurrentVersion, - }); + const { updateStep } = useUpdateStep(); - const { updateTrigger } = useUpdateWorkflowVersionTrigger({ - workflow: workflowWithCurrentVersion, - }); + const { updateTrigger } = useUpdateWorkflowVersionTrigger(); const onConnect = (edgeConnect: Connection) => { setWorkflowDiagram((diagram) => { @@ -107,6 +101,14 @@ export const WorkflowDiagramCanvasEditable = ({ } }; + if (!isDefined(workflowWithCurrentVersion)) { + return null; + } + + const tagProps = getWorkflowVersionStatusTagProps({ + workflowVersionStatus: workflowWithCurrentVersion.currentVersion.status, + }); + const handlePaneContextMenu = ({ x, y }: { x: number; y: number }) => { setWorkflowDiagramRightClickMenuPosition({ x, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeEditable.tsx index efbf80695b..cd1fa29ae0 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeEditable.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeEditable.tsx @@ -61,7 +61,7 @@ export const WorkflowDiagramDefaultEdgeEditable = ({ const { createStep } = useCreateStep({ workflow }); - const { deleteEdge } = useDeleteEdge({ workflow }); + const { deleteEdge } = useDeleteEdge(); const { startNodeCreation, isNodeCreationStarted } = useStartNodeCreation(); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx index e3e50e2f4b..b1dfbddea0 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx @@ -1,13 +1,13 @@ import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; +import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { flowComponentState } from '@/workflow/states/flowComponentState'; import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState'; -import { - type WorkflowVersion, - type WorkflowWithCurrentVersion, -} from '@/workflow/types/Workflow'; +import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; +import { type WorkflowVersion } from '@/workflow/types/Workflow'; import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState'; import { getWorkflowVersionDiagram } from '@/workflow/workflow-diagram/utils/getWorkflowVersionDiagram'; @@ -18,11 +18,15 @@ import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { FeatureFlagKey } from '~/generated/graphql'; -export const WorkflowDiagramEffect = ({ - workflowWithCurrentVersion, -}: { - workflowWithCurrentVersion: WorkflowWithCurrentVersion | undefined; -}) => { +export const WorkflowDiagramEffect = () => { + const workflowVisualizerWorkflowId = useRecoilComponentValue( + workflowVisualizerWorkflowIdComponentState, + ); + + const workflowWithCurrentVersion = useWorkflowWithCurrentVersion( + workflowVisualizerWorkflowId, + ); + const workflowDiagramState = useRecoilComponentCallbackState( workflowDiagramComponentState, ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeEditable.tsx index 3ee717c3ca..558731e9ef 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeEditable.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeEditable.tsx @@ -9,8 +9,6 @@ import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; -import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { WorkflowDiagramBaseEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramBaseEdge'; import { WorkflowDiagramEdgeButtonGroup } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeButtonGroup'; import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2Container'; @@ -107,15 +105,10 @@ export const WorkflowDiagramFilterEdgeEditable = ({ targetY, }); - const workflowVisualizerWorkflowId = useRecoilComponentValue( - workflowVisualizerWorkflowIdComponentState, - ); - const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId); - const { isInRightDrawer } = useContext(ActionMenuContext); - const { deleteStep } = useDeleteStep({ workflow }); - const { deleteEdge } = useDeleteEdge({ workflow }); + const { deleteStep } = useDeleteStep(); + const { deleteEdge } = useDeleteEdge(); const { startNodeCreation, isNodeCreationStarted } = useStartNodeCreation(); const setCommandMenuNavigationStack = useSetRecoilState( diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx index 0f9880920c..0c1e729a9d 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu.tsx @@ -1,6 +1,4 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; -import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { useCloseRightClickMenu } from '@/workflow/workflow-diagram/hooks/useCloseRightClickMenu'; import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation'; import { useWorkflowDiagramScreenToFlowPosition } from '@/workflow/workflow-diagram/hooks/useWorkflowDiagramScreenToFlowPosition'; @@ -43,17 +41,7 @@ export const WorkflowDiagramRightClickCommandMenu = () => { workflowDiagramRightClickMenuPositionState, ); - const workflowVisualizerWorkflowId = useRecoilComponentValue( - workflowVisualizerWorkflowIdComponentState, - ); - - const workflowWithCurrentVersion = useWorkflowWithCurrentVersion( - workflowVisualizerWorkflowId, - ); - - const { tidyUpWorkflowVersion } = useTidyUpWorkflowVersion({ - workflow: workflowWithCurrentVersion, - }); + const { tidyUpWorkflowVersion } = useTidyUpWorkflowVersion(); const handleReorderWorkflowDiagram = async () => { await tidyUpWorkflowVersion(); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx index 7455dea9e9..1559eca3a5 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx @@ -3,9 +3,7 @@ import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandM import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; -import { assertWorkflowWithCurrentVersionIsDefined } from '@/workflow/utils/assertWorkflowWithCurrentVersionIsDefined'; import { WorkflowDiagramStepNodeEditableContent } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditableContent'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram'; @@ -31,14 +29,7 @@ export const WorkflowDiagramStepNodeEditable = ({ workflowVisualizerWorkflowIdComponentState, ); - const workflowWithCurrentVersion = useWorkflowWithCurrentVersion( - workflowVisualizerWorkflowId, - ); - assertWorkflowWithCurrentVersionIsDefined(workflowWithCurrentVersion); - - const { deleteStep } = useDeleteStep({ - workflow: workflowWithCurrentVersion, - }); + const { deleteStep } = useDeleteStep(); const setWorkflowSelectedNode = useSetRecoilComponentState( workflowSelectedNodeComponentState, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizer.tsx index 16b1418b62..531ec6f69b 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizer.tsx @@ -1,24 +1,11 @@ -import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { WorkflowDiagramCanvasEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable'; import { WorkflowDiagramEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramEffect'; -import '@xyflow/react/dist/style.css'; -import { isDefined } from 'twenty-shared/utils'; - -export const WorkflowVisualizer = ({ workflowId }: { workflowId: string }) => { - const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId); - - if (!isDefined(workflowWithCurrentVersion)) { - return null; - } +export const WorkflowVisualizer = () => { return ( <> - - + + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.tsx index 622849b79e..234064845e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.tsx @@ -4,7 +4,7 @@ import { RecoilRoot } from 'recoil'; import { WorkflowVisualizerComponentInstanceContext } from '../../../workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; import { useCreateStep } from '../useCreateStep'; -const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457'); +const mockGetUpdatableWorkflowVersion = jest.fn(); const mockCreateWorkflowVersionStep = jest.fn().mockResolvedValue({ data: { createWorkflowVersionStep: { createdStep: { id: '1', type: 'CODE' } }, @@ -20,9 +20,9 @@ jest.mock( }), ); -jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({ - useCreateDraftFromWorkflowVersion: () => ({ - createDraftFromWorkflowVersion: mockCreateDraftFromWorkflowVersion, +jest.mock('@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow', () => ({ + useGetUpdatableWorkflowVersionOrThrow: () => ({ + getUpdatableWorkflowVersion: mockGetUpdatableWorkflowVersion, }), })); @@ -55,7 +55,14 @@ describe('useCreateStep', () => { versions: [], }; - it('should create step in draft version', async () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should create step in workflow version', async () => { + const mockWorkflowVersionId = 'version-123'; + mockGetUpdatableWorkflowVersion.mockResolvedValue(mockWorkflowVersionId); + const { result } = renderHook( () => useCreateStep({ @@ -74,6 +81,13 @@ describe('useCreateStep', () => { }); }); - expect(mockCreateWorkflowVersionStep).toHaveBeenCalled(); + expect(mockGetUpdatableWorkflowVersion).toHaveBeenCalled(); + expect(mockCreateWorkflowVersionStep).toHaveBeenCalledWith({ + workflowVersionId: mockWorkflowVersionId, + stepType: 'CODE', + parentStepId: 'parent-step-id', + nextStepId: undefined, + position: undefined, + }); }); }); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useDeleteStep.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useDeleteStep.test.ts index 994b70b023..3fb8f43f1f 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useDeleteStep.test.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useDeleteStep.test.ts @@ -1,17 +1,10 @@ -import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep'; import { renderHook } from '@testing-library/react'; -import { RecoilRoot } from 'recoil'; const mockDeleteWorkflowVersionStep = jest.fn(); -const updateOneRecordMock = jest.fn(); -const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457'); - -jest.mock('@/object-record/hooks/useUpdateOneRecord', () => ({ - useUpdateOneRecord: () => ({ - updateOneRecord: updateOneRecordMock, - }), -})); +const mockGetUpdatableWorkflowVersion = jest.fn(); +const mockDeleteStepsOutputSchema = jest.fn(); +const mockCloseCommandMenu = jest.fn(); jest.mock('@/workflow/hooks/useDeleteWorkflowVersionStep', () => ({ useDeleteWorkflowVersionStep: () => ({ @@ -19,34 +12,51 @@ jest.mock('@/workflow/hooks/useDeleteWorkflowVersionStep', () => ({ }), })); -jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({ - useCreateDraftFromWorkflowVersion: () => ({ - createDraftFromWorkflowVersion: mockCreateDraftFromWorkflowVersion, +jest.mock('@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow', () => ({ + useGetUpdatableWorkflowVersionOrThrow: () => ({ + getUpdatableWorkflowVersion: mockGetUpdatableWorkflowVersion, + }), +})); + +jest.mock('@/workflow/hooks/useStepsOutputSchema', () => ({ + useStepsOutputSchema: () => ({ + deleteStepsOutputSchema: mockDeleteStepsOutputSchema, + }), +})); + +jest.mock('@/command-menu/hooks/useCommandMenu', () => ({ + useCommandMenu: () => ({ + closeCommandMenu: mockCloseCommandMenu, }), })); describe('useDeleteStep', () => { - const mockWorkflow = { - id: '123', - currentVersion: { - id: '456', - status: 'DRAFT', - steps: [], - trigger: { type: 'manual' }, - }, - versions: [], - }; + beforeEach(() => { + jest.clearAllMocks(); + }); - it('should delete step in draft version', async () => { - const { result } = renderHook( - () => - useDeleteStep({ - workflow: mockWorkflow as unknown as WorkflowWithCurrentVersion, - }), - { wrapper: RecoilRoot }, - ); - await result.current.deleteStep('1'); + it('should delete step and clean up dependencies', async () => { + const mockWorkflowVersionId = 'version-123'; + const mockStepId = 'step-1'; + const mockDeletedStepIds = ['step-1', 'step-2']; - expect(mockDeleteWorkflowVersionStep).toHaveBeenCalled(); + mockGetUpdatableWorkflowVersion.mockResolvedValue(mockWorkflowVersionId); + mockDeleteWorkflowVersionStep.mockResolvedValue({ + deletedStepIds: mockDeletedStepIds, + }); + + const { result } = renderHook(() => useDeleteStep()); + await result.current.deleteStep(mockStepId); + + expect(mockGetUpdatableWorkflowVersion).toHaveBeenCalled(); + expect(mockDeleteWorkflowVersionStep).toHaveBeenCalledWith({ + workflowVersionId: mockWorkflowVersionId, + stepId: mockStepId, + }); + expect(mockCloseCommandMenu).toHaveBeenCalled(); + expect(mockDeleteStepsOutputSchema).toHaveBeenCalledWith({ + stepIds: mockDeletedStepIds, + workflowVersionId: mockWorkflowVersionId, + }); }); }); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useUpdateStep.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useUpdateStep.test.ts index 98fcfb4120..ac68bf0f12 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useUpdateStep.test.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useUpdateStep.test.ts @@ -1,15 +1,8 @@ -import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep'; import { renderHook } from '@testing-library/react'; const mockUpdateWorkflowVersionStep = jest.fn(); -const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457'); - -jest.mock('recoil', () => ({ - useRecoilValue: () => 'parent-step-id', - useSetRecoilState: () => jest.fn(), - atom: (params: any) => params, -})); +const mockGetUpdatableWorkflowVersion = jest.fn(); jest.mock( '@/workflow/workflow-steps/hooks/useUpdateWorkflowVersionStep', @@ -20,35 +13,24 @@ jest.mock( }), ); -jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({ - useCreateDraftFromWorkflowVersion: () => ({ - createDraftFromWorkflowVersion: mockCreateDraftFromWorkflowVersion, +jest.mock('@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow', () => ({ + useGetUpdatableWorkflowVersionOrThrow: () => ({ + getUpdatableWorkflowVersion: mockGetUpdatableWorkflowVersion, }), })); describe('useUpdateStep', () => { - const mockWorkflow = { - id: '123', - currentVersion: { - id: '456', - status: 'DRAFT', - steps: [], - trigger: { type: 'manual' }, - }, - versions: [], - }; + beforeEach(() => { + jest.clearAllMocks(); + }); - it('should update step in draft version', async () => { - const { result } = renderHook(() => - useUpdateStep({ - workflow: mockWorkflow as unknown as WorkflowWithCurrentVersion, - }), - ); - await result.current.updateStep({ + it('should update step in workflow version', async () => { + const mockWorkflowVersionId = 'version-123'; + const mockStep = { id: '1', name: 'name', valid: true, - type: 'CODE', + type: 'CODE' as const, settings: { input: { serverlessFunctionId: 'id', @@ -65,8 +47,17 @@ describe('useUpdateStep', () => { }, }, }, - }); + }; - expect(mockUpdateWorkflowVersionStep).toHaveBeenCalled(); + mockGetUpdatableWorkflowVersion.mockResolvedValue(mockWorkflowVersionId); + + const { result } = renderHook(() => useUpdateStep()); + await result.current.updateStep(mockStep); + + expect(mockGetUpdatableWorkflowVersion).toHaveBeenCalled(); + expect(mockUpdateWorkflowVersionStep).toHaveBeenCalledWith({ + workflowVersionId: mockWorkflowVersionId, + step: mockStep, + }); }); }); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateEdge.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateEdge.ts index 2e4ff77e67..d7f44ab018 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateEdge.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateEdge.ts @@ -1,20 +1,15 @@ -import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; -import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; +import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; +import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagramEdge'; import { useCreateWorkflowVersionEdge } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionEdge'; import { useState } from 'react'; -import { isDefined } from 'twenty-shared/utils'; -import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagramEdge'; -export const useCreateEdge = ({ - workflow, -}: { - workflow: WorkflowWithCurrentVersion; -}) => { +export const useCreateEdge = () => { const [isLoading, setIsLoading] = useState(false); const { createWorkflowVersionEdge } = useCreateWorkflowVersionEdge(); - const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); + const { getUpdatableWorkflowVersion } = + useGetUpdatableWorkflowVersionOrThrow(); const createEdge = async ({ source, target }: WorkflowDiagramEdge) => { if (isLoading) { @@ -24,11 +19,7 @@ export const useCreateEdge = ({ setIsLoading(true); try { - const workflowVersionId = await getUpdatableWorkflowVersion(workflow); - - if (!isDefined(workflowVersionId)) { - throw new Error('Cannot find a workflow version to update'); - } + const workflowVersionId = await getUpdatableWorkflowVersion(); const createdEdge = ( await createWorkflowVersionEdge({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts index c49bd68426..0cccd36021 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts @@ -1,5 +1,5 @@ import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; +import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState'; import { type WorkflowStepType, @@ -24,7 +24,8 @@ export const useCreateStep = ({ workflowLastCreatedStepIdComponentState, ); - const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); + const { getUpdatableWorkflowVersion } = + useGetUpdatableWorkflowVersionOrThrow(); if (!isDefined(workflow)) { return { @@ -50,11 +51,7 @@ export const useCreateStep = ({ setIsLoading(true); try { - const workflowVersionId = await getUpdatableWorkflowVersion(workflow); - - if (!isDefined(workflowVersionId)) { - throw new Error("Couldn't get updatable workflow version"); - } + const workflowVersionId = await getUpdatableWorkflowVersion(); const workflowVersionStepChanges = ( await createWorkflowVersionStep({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteEdge.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteEdge.ts index aa4bfd6045..58cdf986a6 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteEdge.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteEdge.ts @@ -1,25 +1,17 @@ -import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; -import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; -import { assertWorkflowWithCurrentVersionIsDefined } from '@/workflow/utils/assertWorkflowWithCurrentVersionIsDefined'; +import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagramEdge'; import { useDeleteWorkflowVersionEdge } from '@/workflow/workflow-steps/hooks/useDeleteWorkflowVersionEdge'; import { useState } from 'react'; -import { isDefined } from 'twenty-shared/utils'; -export const useDeleteEdge = ({ - workflow, -}: { - workflow: WorkflowWithCurrentVersion | undefined; -}) => { +export const useDeleteEdge = () => { const [isLoading, setIsLoading] = useState(false); const { deleteWorkflowVersionEdge } = useDeleteWorkflowVersionEdge(); - const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); + const { getUpdatableWorkflowVersion } = + useGetUpdatableWorkflowVersionOrThrow(); const deleteEdge = async ({ source, target }: WorkflowDiagramEdge) => { - assertWorkflowWithCurrentVersionIsDefined(workflow); - if (isLoading) { return; } @@ -27,11 +19,7 @@ export const useDeleteEdge = ({ setIsLoading(true); try { - const workflowVersionId = await getUpdatableWorkflowVersion(workflow); - - if (!isDefined(workflowVersionId)) { - throw new Error('Cannot find a workflow version to update'); - } + const workflowVersionId = await getUpdatableWorkflowVersion(); const deletedEdge = ( await deleteWorkflowVersionEdge({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts index dcb72cc87b..5c9e3d0f61 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts @@ -1,30 +1,18 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { useDeleteWorkflowVersionStep } from '@/workflow/hooks/useDeleteWorkflowVersionStep'; -import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; +import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; -import { type WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; -import { assertWorkflowWithCurrentVersionIsDefined } from '@/workflow/utils/assertWorkflowWithCurrentVersionIsDefined'; -import { isDefined } from 'twenty-shared/utils'; -export const useDeleteStep = ({ - workflow, -}: { - workflow: WorkflowWithCurrentVersion | undefined; -}) => { +export const useDeleteStep = () => { const { deleteWorkflowVersionStep } = useDeleteWorkflowVersionStep(); const { deleteStepsOutputSchema } = useStepsOutputSchema(); - const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); + const { getUpdatableWorkflowVersion } = + useGetUpdatableWorkflowVersionOrThrow(); const { closeCommandMenu } = useCommandMenu(); const deleteStep = async (stepId: string) => { - assertWorkflowWithCurrentVersionIsDefined(workflow); - - const workflowVersionId = await getUpdatableWorkflowVersion(workflow); - - if (!isDefined(workflowVersionId)) { - throw new Error('Could not find workflow version'); - } + const workflowVersionId = await getUpdatableWorkflowVersion(); const workflowVersionStepChanges = await deleteWorkflowVersionStep({ workflowVersionId, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useUpdateStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useUpdateStep.ts index 94d65d2f99..486947af70 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useUpdateStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useUpdateStep.ts @@ -1,29 +1,14 @@ -import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; -import { - type WorkflowStep, - type WorkflowWithCurrentVersion, -} from '@/workflow/types/Workflow'; +import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; +import { type WorkflowStep } from '@/workflow/types/Workflow'; import { useUpdateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useUpdateWorkflowVersionStep'; -import { isDefined } from 'twenty-shared/utils'; -export const useUpdateStep = ({ - workflow, -}: { - workflow: WorkflowWithCurrentVersion; -}) => { - const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); +export const useUpdateStep = () => { + const { getUpdatableWorkflowVersion } = + useGetUpdatableWorkflowVersionOrThrow(); const { updateWorkflowVersionStep } = useUpdateWorkflowVersionStep(); const updateStep = async (updatedStep: T) => { - if (!isDefined(workflow.currentVersion)) { - throw new Error('Could not find current workflow version'); - } - - const workflowVersionId = await getUpdatableWorkflowVersion(workflow); - - if (!isDefined(workflowVersionId)) { - throw new Error('Workflow version not found'); - } + const workflowVersionId = await getUpdatableWorkflowVersion(); await updateWorkflowVersionStep({ workflowVersionId, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx index 4be8bc14ff..2a5c56c656 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx @@ -8,7 +8,7 @@ import { Breadcrumb, type BreadcrumbProps, } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; -import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; +import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { type WorkflowCodeAction } from '@/workflow/types/Workflow'; @@ -30,11 +30,11 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTab import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { serverlessFunctionTestDataFamilyState } from '@/workflow/states/serverlessFunctionTestDataFamilyState'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowEditActionServerlessFunctionFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunctionFields'; import { WorkflowServerlessFunctionCodeEditor } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowServerlessFunctionCodeEditor'; import { WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowServerlessFunctionTabListComponentId'; +import { serverlessFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/serverlessFunctionTestDataFamilyState'; import { WorkflowServerlessFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowServerlessFunctionTabId'; import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers'; import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow'; @@ -140,7 +140,8 @@ export const WorkflowEditActionServerlessFunction = ({ ); const { updateOneServerlessFunction } = useUpdateOneServerlessFunction(serverlessFunctionId); - const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); + const { getUpdatableWorkflowVersion } = + useGetUpdatableWorkflowVersionOrThrow(); const workflowVisualizerWorkflowId = useRecoilComponentValue( workflowVisualizerWorkflowIdComponentState, @@ -323,7 +324,7 @@ export const WorkflowEditActionServerlessFunction = ({ if (actionOptions.readonly === true || !isDefined(workflow)) { return; } - await getUpdatableWorkflowVersion(workflow); + await getUpdatableWorkflowVersion(); await onCodeChange(value); }; diff --git a/packages/twenty-front/src/modules/workflow/states/serverlessFunctionTestDataFamilyState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/states/serverlessFunctionTestDataFamilyState.ts similarity index 100% rename from packages/twenty-front/src/modules/workflow/states/serverlessFunctionTestDataFamilyState.ts rename to packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/states/serverlessFunctionTestDataFamilyState.ts diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/hooks/__tests__/useUpdateWorkflowVersionTrigger.test.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/hooks/__tests__/useUpdateWorkflowVersionTrigger.test.ts index 1b68d46a7a..17474e8c28 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/hooks/__tests__/useUpdateWorkflowVersionTrigger.test.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/hooks/__tests__/useUpdateWorkflowVersionTrigger.test.ts @@ -1,9 +1,6 @@ -import { act, renderHook } from '@testing-library/react'; +import { type WorkflowTrigger } from '@/workflow/types/Workflow'; import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger'; -import { - type WorkflowTrigger, - type WorkflowWithCurrentVersion, -} from '@/workflow/types/Workflow'; +import { act, renderHook } from '@testing-library/react'; const mockUpdateOneRecord = jest.fn(); const mockGetUpdatableWorkflowVersion = jest.fn(); @@ -15,8 +12,8 @@ jest.mock('@/object-record/hooks/useUpdateOneRecord', () => ({ })), })); -jest.mock('@/workflow/hooks/useGetUpdatableWorkflowVersion', () => ({ - useGetUpdatableWorkflowVersion: jest.fn(() => ({ +jest.mock('@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow', () => ({ + useGetUpdatableWorkflowVersionOrThrow: jest.fn(() => ({ getUpdatableWorkflowVersion: mockGetUpdatableWorkflowVersion, })), })); @@ -28,11 +25,6 @@ jest.mock('@/workflow/hooks/useComputeStepOutputSchema', () => ({ })); describe('useUpdateWorkflowVersionTrigger', () => { - const mockWorkflow = { - id: 'workflow-id', - currentVersion: { id: 'version-id' }, - } as WorkflowWithCurrentVersion; - const trigger: WorkflowTrigger = { name: 'Company created', type: 'DATABASE_EVENT', @@ -53,15 +45,13 @@ describe('useUpdateWorkflowVersionTrigger', () => { data: { computeStepOutputSchema: { field1: 'string' } }, }); - const { result } = renderHook(() => - useUpdateWorkflowVersionTrigger({ workflow: mockWorkflow }), - ); + const { result } = renderHook(() => useUpdateWorkflowVersionTrigger()); await act(async () => { await result.current.updateTrigger(trigger); }); - expect(mockGetUpdatableWorkflowVersion).toHaveBeenCalledWith(mockWorkflow); + expect(mockGetUpdatableWorkflowVersion).toHaveBeenCalled(); expect(mockComputeStepOutputSchema).toHaveBeenCalledWith({ step: trigger }); expect(mockUpdateOneRecord).toHaveBeenCalledWith({ idToUpdate: 'version-id', @@ -77,9 +67,7 @@ describe('useUpdateWorkflowVersionTrigger', () => { it('skips output schema computation when disabled', async () => { mockGetUpdatableWorkflowVersion.mockResolvedValue('version-id'); - const { result } = renderHook(() => - useUpdateWorkflowVersionTrigger({ workflow: mockWorkflow }), - ); + const { result } = renderHook(() => useUpdateWorkflowVersionTrigger()); await act(async () => { await result.current.updateTrigger(trigger, { diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger.ts index 9fdf691222..684b063f1c 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger.ts @@ -1,25 +1,20 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { useComputeStepOutputSchema } from '@/workflow/hooks/useComputeStepOutputSchema'; -import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; +import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; import { type WorkflowTrigger, type WorkflowVersion, - type WorkflowWithCurrentVersion, } from '@/workflow/types/Workflow'; -import { isDefined } from 'twenty-shared/utils'; -export const useUpdateWorkflowVersionTrigger = ({ - workflow, -}: { - workflow: WorkflowWithCurrentVersion; -}) => { +export const useUpdateWorkflowVersionTrigger = () => { const { updateOneRecord: updateOneWorkflowVersion } = useUpdateOneRecord({ objectNameSingular: CoreObjectNameSingular.WorkflowVersion, }); - const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); + const { getUpdatableWorkflowVersion } = + useGetUpdatableWorkflowVersionOrThrow(); const { computeStepOutputSchema } = useComputeStepOutputSchema(); @@ -27,11 +22,7 @@ export const useUpdateWorkflowVersionTrigger = ({ updatedTrigger: WorkflowTrigger, options: { computeOutputSchema: boolean } = { computeOutputSchema: true }, ) => { - if (!isDefined(workflow.currentVersion)) { - throw new Error('Cannot find current workflow version'); - } - - const workflowVersionId = await getUpdatableWorkflowVersion(workflow); + const workflowVersionId = await getUpdatableWorkflowVersion(); if (options.computeOutputSchema) { const outputSchema = ( @@ -46,10 +37,6 @@ export const useUpdateWorkflowVersionTrigger = ({ }; } - if (!isDefined(workflowVersionId)) { - throw new Error('Workflow version not found'); - } - await updateOneWorkflowVersion({ idToUpdate: workflowVersionId, updateOneRecordInput: { diff --git a/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUpWorkflowVersion.ts b/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUpWorkflowVersion.ts index f4afd83687..8bd2d8570c 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUpWorkflowVersion.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-version/hooks/useTidyUpWorkflowVersion.ts @@ -1,8 +1,5 @@ -import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; -import { - type WorkflowVersion, - type WorkflowWithCurrentVersion, -} from '@/workflow/types/Workflow'; +import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow'; +import { type WorkflowVersion } from '@/workflow/types/Workflow'; import { useMutation } from '@apollo/client'; import { isDefined } from 'twenty-shared/utils'; import { @@ -23,11 +20,7 @@ import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/state import { getOrganizedDiagram } from '@/workflow/workflow-diagram/utils/getOrganizedDiagram'; import { UPDATE_WORKFLOW_VERSION_POSITIONS } from '@/workflow/workflow-version/graphql/mutations/updateWorkflowVersionPositions'; -export const useTidyUpWorkflowVersion = ({ - workflow, -}: { - workflow?: WorkflowWithCurrentVersion; -}) => { +export const useTidyUpWorkflowVersion = () => { const [workflowDiagram, setWorkflowDiagram] = useRecoilComponentState( workflowDiagramComponentState, ); @@ -49,20 +42,13 @@ export const useTidyUpWorkflowVersion = ({ UpdateWorkflowVersionPositionsMutationVariables >(UPDATE_WORKFLOW_VERSION_POSITIONS, { client: apolloCoreClient }); - const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); + const { getUpdatableWorkflowVersion } = + useGetUpdatableWorkflowVersionOrThrow(); const updateWorkflowVersionPosition = async ( positions: { id: string; position: { x: number; y: number } }[], ) => { - if (!isDefined(workflow)) { - throw new Error('Cannot find a workflow to update'); - } - - const workflowVersionId = await getUpdatableWorkflowVersion(workflow); - - if (!isDefined(workflowVersionId)) { - throw new Error('Cannot find a workflow version to update'); - } + const workflowVersionId = await getUpdatableWorkflowVersion(); await mutate({ variables: { input: { workflowVersionId, positions } } }); @@ -115,7 +101,7 @@ export const useTidyUpWorkflowVersion = ({ }; const tidyUpWorkflowVersion = async () => { - if (!isDefined(workflowDiagram) || !isDefined(workflow?.currentVersion)) { + if (!isDefined(workflowDiagram)) { return; }