diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index f9c872e89ba3..21449776727e 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -551,7 +551,7 @@ export type Mutation = { challenge: LoginToken; checkoutSession: SessionEntity; computeStepOutputSchema: Scalars['JSON']['output']; - createDraftFromWorkflowVersion: Scalars['Boolean']['output']; + createDraftFromWorkflowVersion: WorkflowVersion; createOIDCIdentityProvider: SetupSsoOutput; createOneAppToken: AppToken; createOneField: Field; @@ -1711,6 +1711,11 @@ export type WorkflowRun = { workflowRunId: Scalars['UUID']['output']; }; +export type WorkflowVersion = { + __typename?: 'WorkflowVersion'; + workflowVersionId: Scalars['UUID']['output']; +}; + export type Workspace = { __typename?: 'Workspace'; activationStatus: WorkspaceActivationStatus; diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index 2560b6b2a1fe..5eecd24e0810 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -477,7 +477,7 @@ export type Mutation = { challenge: LoginToken; checkoutSession: SessionEntity; computeStepOutputSchema: Scalars['JSON']; - createDraftFromWorkflowVersion: Scalars['Boolean']; + createDraftFromWorkflowVersion: WorkflowVersion; createOIDCIdentityProvider: SetupSsoOutput; createOneAppToken: AppToken; createOneField: Field; @@ -1508,6 +1508,11 @@ export type WorkflowRun = { workflowRunId: Scalars['UUID']; }; +export type WorkflowVersion = { + __typename?: 'WorkflowVersion'; + id: Scalars['UUID']; +}; + export type Workspace = { __typename?: 'Workspace'; activationStatus: WorkspaceActivationStatus; @@ -2131,6 +2136,13 @@ export type ComputeStepOutputSchemaMutationVariables = Exact<{ export type ComputeStepOutputSchemaMutation = { __typename?: 'Mutation', computeStepOutputSchema: any }; +export type CreateDraftFromWorkflowVersionMutationVariables = Exact<{ + input: CreateDraftFromWorkflowVersionInput; +}>; + + +export type CreateDraftFromWorkflowVersionMutation = { __typename?: 'Mutation', createDraftFromWorkflowVersion: { __typename?: 'WorkflowVersion', id: any } }; + export type CreateWorkflowVersionStepMutationVariables = Exact<{ input: CreateWorkflowVersionStepInput; }>; @@ -2152,13 +2164,6 @@ export type DeleteWorkflowVersionStepMutationVariables = Exact<{ export type DeleteWorkflowVersionStepMutation = { __typename?: 'Mutation', deleteWorkflowVersionStep: { __typename?: 'WorkflowAction', id: any, name: string, type: string, settings: any, valid: boolean } }; -export type CreateDraftFromWorkflowVersionMutationVariables = Exact<{ - input: CreateDraftFromWorkflowVersionInput; -}>; - - -export type CreateDraftFromWorkflowVersionMutation = { __typename?: 'Mutation', createDraftFromWorkflowVersion: boolean }; - export type RunWorkflowVersionMutationVariables = Exact<{ input: RunWorkflowVersionInput; }>; @@ -4092,6 +4097,39 @@ export function useComputeStepOutputSchemaMutation(baseOptions?: Apollo.Mutation export type ComputeStepOutputSchemaMutationHookResult = ReturnType; export type ComputeStepOutputSchemaMutationResult = Apollo.MutationResult; export type ComputeStepOutputSchemaMutationOptions = Apollo.BaseMutationOptions; +export const CreateDraftFromWorkflowVersionDocument = gql` + mutation CreateDraftFromWorkflowVersion($input: CreateDraftFromWorkflowVersionInput!) { + createDraftFromWorkflowVersion(input: $input) { + id + } +} + `; +export type CreateDraftFromWorkflowVersionMutationFn = Apollo.MutationFunction; + +/** + * __useCreateDraftFromWorkflowVersionMutation__ + * + * To run a mutation, you first call `useCreateDraftFromWorkflowVersionMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreateDraftFromWorkflowVersionMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [createDraftFromWorkflowVersionMutation, { data, loading, error }] = useCreateDraftFromWorkflowVersionMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useCreateDraftFromWorkflowVersionMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(CreateDraftFromWorkflowVersionDocument, options); + } +export type CreateDraftFromWorkflowVersionMutationHookResult = ReturnType; +export type CreateDraftFromWorkflowVersionMutationResult = Apollo.MutationResult; +export type CreateDraftFromWorkflowVersionMutationOptions = Apollo.BaseMutationOptions; export const CreateWorkflowVersionStepDocument = gql` mutation CreateWorkflowVersionStep($input: CreateWorkflowVersionStepInput!) { createWorkflowVersionStep(input: $input) { @@ -4197,37 +4235,6 @@ export function useDeleteWorkflowVersionStepMutation(baseOptions?: Apollo.Mutati export type DeleteWorkflowVersionStepMutationHookResult = ReturnType; export type DeleteWorkflowVersionStepMutationResult = Apollo.MutationResult; export type DeleteWorkflowVersionStepMutationOptions = Apollo.BaseMutationOptions; -export const CreateDraftFromWorkflowVersionDocument = gql` - mutation CreateDraftFromWorkflowVersion($input: CreateDraftFromWorkflowVersionInput!) { - createDraftFromWorkflowVersion(input: $input) -} - `; -export type CreateDraftFromWorkflowVersionMutationFn = Apollo.MutationFunction; - -/** - * __useCreateDraftFromWorkflowVersionMutation__ - * - * To run a mutation, you first call `useCreateDraftFromWorkflowVersionMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useCreateDraftFromWorkflowVersionMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [createDraftFromWorkflowVersionMutation, { data, loading, error }] = useCreateDraftFromWorkflowVersionMutation({ - * variables: { - * input: // value for 'input' - * }, - * }); - */ -export function useCreateDraftFromWorkflowVersionMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(CreateDraftFromWorkflowVersionDocument, options); - } -export type CreateDraftFromWorkflowVersionMutationHookResult = ReturnType; -export type CreateDraftFromWorkflowVersionMutationResult = Apollo.MutationResult; -export type CreateDraftFromWorkflowVersionMutationOptions = Apollo.BaseMutationOptions; export const RunWorkflowVersionDocument = gql` mutation RunWorkflowVersion($input: RunWorkflowVersionInput!) { runWorkflowVersion(input: $input) { diff --git a/packages/twenty-front/src/modules/workflow/graphql/mutations/overrideWorkflowDraftVersion.ts b/packages/twenty-front/src/modules/workflow/graphql/mutations/createDraftFromWorkflowVersion.ts similarity index 54% rename from packages/twenty-front/src/modules/workflow/graphql/mutations/overrideWorkflowDraftVersion.ts rename to packages/twenty-front/src/modules/workflow/graphql/mutations/createDraftFromWorkflowVersion.ts index 10f5e4464721..3c64c0c49092 100644 --- a/packages/twenty-front/src/modules/workflow/graphql/mutations/overrideWorkflowDraftVersion.ts +++ b/packages/twenty-front/src/modules/workflow/graphql/mutations/createDraftFromWorkflowVersion.ts @@ -1,9 +1,11 @@ import { gql } from '@apollo/client'; -export const OVERRIDE_WORKFLOW_DRAFT_VERSION = gql` +export const CREATE_DRAFT_FROM_WORKFLOW_VERSION = gql` mutation CreateDraftFromWorkflowVersion( $input: CreateDraftFromWorkflowVersionInput! ) { - createDraftFromWorkflowVersion(input: $input) + createDraftFromWorkflowVersion(input: $input) { + id + } } `; diff --git a/packages/twenty-front/src/modules/workflow/hooks/__tests__/useCreateNewWorkflowVersion.test.ts b/packages/twenty-front/src/modules/workflow/hooks/__tests__/useCreateNewWorkflowVersion.test.ts deleted file mode 100644 index cdf59bf359c8..000000000000 --- a/packages/twenty-front/src/modules/workflow/hooks/__tests__/useCreateNewWorkflowVersion.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; -import { WorkflowVersion } from '@/workflow/types/Workflow'; -import { renderHook } from '@testing-library/react'; -import { useCreateNewWorkflowVersion } from '../useCreateNewWorkflowVersion'; - -jest.mock('@/object-record/hooks/useCreateOneRecord', () => ({ - useCreateOneRecord: jest.fn(), -})); - -describe('useCreateNewWorkflowVersion', () => { - it('should create workflow version', async () => { - const mockCreateOneRecord = jest.fn(); - (useCreateOneRecord as jest.Mock).mockImplementation(() => ({ - createOneRecord: mockCreateOneRecord, - })); - - const workflowVersionData = { - workflowId: '123', - name: 'Test Version', - status: 'draft', - trigger: { type: 'manual' }, - steps: [], - }; - - const { result } = renderHook(() => useCreateNewWorkflowVersion()); - await result.current.createNewWorkflowVersion( - workflowVersionData as unknown as WorkflowVersion, - ); - - expect(useCreateOneRecord).toHaveBeenCalledWith({ - objectNameSingular: CoreObjectNameSingular.WorkflowVersion, - }); - expect(mockCreateOneRecord).toHaveBeenCalledWith(workflowVersionData); - }); -}); 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 295de8110b32..5d808743b75b 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 @@ -2,21 +2,11 @@ import { renderHook } from '@testing-library/react'; import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; -const mockCreateNewWorkflowVersion = jest.fn().mockResolvedValue({ - id: '457', - name: 'toto', - createdAt: '2024-07-03T20:03:35.064Z', - updatedAt: '2024-07-03T20:03:35.064Z', - workflowId: '123', - __typename: 'WorkflowVersion', - status: 'DRAFT', - steps: [], - trigger: null, -}); +const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457'); -jest.mock('@/workflow/hooks/useCreateNewWorkflowVersion', () => ({ - useCreateNewWorkflowVersion: () => ({ - createNewWorkflowVersion: mockCreateNewWorkflowVersion, +jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({ + useCreateDraftFromWorkflowVersion: () => ({ + createDraftFromWorkflowVersion: mockCreateDraftFromWorkflowVersion, }), })); @@ -44,19 +34,19 @@ describe('useGetUpdatableWorkflowVersion', () => { it('should not create workflow version if draft version exists', async () => { const { result } = renderHook(() => useGetUpdatableWorkflowVersion()); - const workflowVersion = await result.current.getUpdatableWorkflowVersion( + const workflowVersionId = await result.current.getUpdatableWorkflowVersion( mockWorkflow('DRAFT'), ); - expect(mockCreateNewWorkflowVersion).not.toHaveBeenCalled(); - expect(workflowVersion.id === '456'); + expect(mockCreateDraftFromWorkflowVersion).not.toHaveBeenCalled(); + expect(workflowVersionId).toEqual('456'); }); it('should create workflow version if no draft version exists', async () => { const { result } = renderHook(() => useGetUpdatableWorkflowVersion()); - const workflowVersion = await result.current.getUpdatableWorkflowVersion( + const workflowVersionId = await result.current.getUpdatableWorkflowVersion( mockWorkflow('ACTIVE'), ); - expect(mockCreateNewWorkflowVersion).toHaveBeenCalled(); - expect(workflowVersion.id === '457'); + expect(mockCreateDraftFromWorkflowVersion).toHaveBeenCalled(); + expect(workflowVersionId).toEqual('457'); }); }); diff --git a/packages/twenty-front/src/modules/workflow/hooks/useCreateDraftFromWorkflowVersion.ts b/packages/twenty-front/src/modules/workflow/hooks/useCreateDraftFromWorkflowVersion.ts index 56579cb139e4..97cab36a6531 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useCreateDraftFromWorkflowVersion.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useCreateDraftFromWorkflowVersion.ts @@ -28,7 +28,7 @@ export const useCreateDraftFromWorkflowVersion = () => { const createDraftFromWorkflowVersion = async ( input: CreateDraftFromWorkflowVersionInput, ) => { - await mutate({ + const result = await mutate({ variables: { input }, awaitRefetchQueries: true, refetchQueries: [ @@ -40,6 +40,8 @@ export const useCreateDraftFromWorkflowVersion = () => { }, ], }); + + return result?.data?.createDraftFromWorkflowVersion.id; }; return { diff --git a/packages/twenty-front/src/modules/workflow/hooks/useCreateNewWorkflowVersion.ts b/packages/twenty-front/src/modules/workflow/hooks/useCreateNewWorkflowVersion.ts deleted file mode 100644 index c09614a1358a..000000000000 --- a/packages/twenty-front/src/modules/workflow/hooks/useCreateNewWorkflowVersion.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; -import { WorkflowVersion } from '@/workflow/types/Workflow'; - -export const useCreateNewWorkflowVersion = () => { - const { createOneRecord: createOneWorkflowVersion } = - useCreateOneRecord({ - objectNameSingular: CoreObjectNameSingular.WorkflowVersion, - }); - - const createNewWorkflowVersion = async ( - workflowVersionData: Pick< - WorkflowVersion, - 'workflowId' | 'name' | 'status' | 'trigger' | 'steps' - >, - ) => { - return await createOneWorkflowVersion(workflowVersionData); - }; - - return { - createNewWorkflowVersion, - }; -}; diff --git a/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersion.ts b/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersion.ts index f2a0c59e18e8..69c101df17c2 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersion.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useGetUpdatableWorkflowVersion.ts @@ -1,21 +1,18 @@ import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; -import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion'; +import { useCreateDraftFromWorkflowVersion } from '@/workflow/hooks/useCreateDraftFromWorkflowVersion'; export const useGetUpdatableWorkflowVersion = () => { - const { createNewWorkflowVersion } = useCreateNewWorkflowVersion(); + const { createDraftFromWorkflowVersion } = + useCreateDraftFromWorkflowVersion(); const getUpdatableWorkflowVersion = async ( workflow: WorkflowWithCurrentVersion, ) => { if (workflow.currentVersion.status === 'DRAFT') { - return workflow.currentVersion; + return workflow.currentVersion.id; } - - return await createNewWorkflowVersion({ + return await createDraftFromWorkflowVersion({ workflowId: workflow.id, - name: `v${workflow.versions.length + 1}`, - status: 'DRAFT', - trigger: workflow.currentVersion.trigger, - steps: workflow.currentVersion.steps, + workflowVersionIdToCopy: workflow.currentVersion.id, }); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts index fde2dc6c479b..2430830145b4 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts @@ -3,7 +3,7 @@ import { renderHook } from '@testing-library/react'; import { useCreateStep } from '../useCreateStep'; const mockOpenRightDrawer = jest.fn(); -const mockCreateNewWorkflowVersion = jest.fn(); +const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457'); const mockCreateWorkflowVersionStep = jest.fn().mockResolvedValue({ data: { createWorkflowVersionStep: { id: '1' } }, }); @@ -29,9 +29,9 @@ jest.mock( }), ); -jest.mock('@/workflow/hooks/useCreateNewWorkflowVersion', () => ({ - useCreateNewWorkflowVersion: () => ({ - createNewWorkflowVersion: mockCreateNewWorkflowVersion, +jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({ + useCreateDraftFromWorkflowVersion: () => ({ + createDraftFromWorkflowVersion: mockCreateDraftFromWorkflowVersion, }), })); 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 7e9513a63675..90aa98275fa7 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 @@ -4,9 +4,9 @@ import { renderHook } from '@testing-library/react'; import { RecoilRoot } from 'recoil'; const mockCloseRightDrawer = jest.fn(); -const mockCreateNewWorkflowVersion = jest.fn(); const mockDeleteWorkflowVersionStep = jest.fn(); const updateOneRecordMock = jest.fn(); +const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457'); jest.mock('@/object-record/hooks/useUpdateOneRecord', () => ({ useUpdateOneRecord: () => ({ @@ -26,9 +26,9 @@ jest.mock('@/workflow/hooks/useDeleteWorkflowVersionStep', () => ({ }), })); -jest.mock('@/workflow/hooks/useCreateNewWorkflowVersion', () => ({ - useCreateNewWorkflowVersion: () => ({ - createNewWorkflowVersion: mockCreateNewWorkflowVersion, +jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({ + useCreateDraftFromWorkflowVersion: () => ({ + createDraftFromWorkflowVersion: mockCreateDraftFromWorkflowVersion, }), })); 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 4c4cd220233c..3ae9c9b747c3 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 @@ -2,8 +2,8 @@ import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep'; import { renderHook } from '@testing-library/react'; -const mockCreateNewWorkflowVersion = jest.fn(); const mockUpdateWorkflowVersionStep = jest.fn(); +const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457'); jest.mock('recoil', () => ({ useRecoilValue: () => 'parent-step-id', @@ -20,9 +20,9 @@ jest.mock( }), ); -jest.mock('@/workflow/hooks/useCreateNewWorkflowVersion', () => ({ - useCreateNewWorkflowVersion: () => ({ - createNewWorkflowVersion: mockCreateNewWorkflowVersion, +jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({ + useCreateDraftFromWorkflowVersion: () => ({ + createDraftFromWorkflowVersion: mockCreateDraftFromWorkflowVersion, }), })); 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 330b89e111ce..89a4f76a1033 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 @@ -35,11 +35,11 @@ export const useCreateStep = ({ throw new Error('Select a step to create a new step from first.'); } - const workflowVersion = await getUpdatableWorkflowVersion(workflow); + const workflowVersionId = await getUpdatableWorkflowVersion(workflow); const createdStep = ( await createWorkflowVersionStep({ - workflowVersionId: workflowVersion.id, + workflowVersionId, stepType: newStepType, }) )?.data?.createWorkflowVersionStep; 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 dea73a14a00b..bb5008497b7f 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 @@ -28,10 +28,10 @@ export const useDeleteStep = ({ const deleteStep = async (stepId: string) => { closeRightDrawer(); closeCommandMenu(); - const workflowVersion = await getUpdatableWorkflowVersion(workflow); + const workflowVersionId = await getUpdatableWorkflowVersion(workflow); if (stepId === TRIGGER_STEP_ID) { await updateOneWorkflowVersion({ - idToUpdate: workflowVersion.id, + idToUpdate: workflowVersionId, updateOneRecordInput: { trigger: null, }, @@ -39,7 +39,7 @@ export const useDeleteStep = ({ return; } await deleteWorkflowVersionStep({ - workflowVersionId: workflowVersion.id, + workflowVersionId, stepId, }); }; 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 e38e334aeaf9..b24d7e24622e 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 @@ -19,9 +19,10 @@ export const useUpdateStep = ({ throw new Error('Can not update an undefined workflow version.'); } - const workflowVersion = await getUpdatableWorkflowVersion(workflow); + const workflowVersionId = await getUpdatableWorkflowVersion(workflow); + await updateWorkflowVersionStep({ - workflowVersionId: workflowVersion.id, + workflowVersionId, step: updatedStep, }); }; 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 f6cf98abfed5..783bad350b5a 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 @@ -28,7 +28,7 @@ export const useUpdateWorkflowVersionTrigger = ({ throw new Error('Can not update an undefined workflow version.'); } - const workflowVersion = await getUpdatableWorkflowVersion(workflow); + const workflowVersionId = await getUpdatableWorkflowVersion(workflow); const outputSchema = ( await computeStepOutputSchema({ @@ -42,7 +42,7 @@ export const useUpdateWorkflowVersionTrigger = ({ }; await updateOneWorkflowVersion({ - idToUpdate: workflowVersion.id, + idToUpdate: workflowVersionId, updateOneRecordInput: { trigger: updatedTrigger, }, diff --git a/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/delete-variables.factory.ts b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/delete-variables.factory.ts index a1a5a40bd221..09c0473606cd 100644 --- a/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/delete-variables.factory.ts +++ b/packages/twenty-server/src/engine/api/rest/core/query-builder/factories/delete-variables.factory.ts @@ -6,7 +6,7 @@ import { QueryVariables } from 'src/engine/api/rest/core/types/query-variables.t export class DeleteVariablesFactory { create(id: string): QueryVariables { return { - id: id, + id, }; } } diff --git a/packages/twenty-server/src/engine/core-modules/workflow/dtos/workflow-version.dto.ts b/packages/twenty-server/src/engine/core-modules/workflow/dtos/workflow-version.dto.ts new file mode 100644 index 000000000000..7442b6e7350c --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/workflow/dtos/workflow-version.dto.ts @@ -0,0 +1,9 @@ +import { Field, ObjectType } from '@nestjs/graphql'; + +import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; + +@ObjectType('WorkflowVersion') +export class WorkflowVersionDTO { + @Field(() => UUIDScalarType) + id: string; +} diff --git a/packages/twenty-server/src/engine/core-modules/workflow/resolvers/workflow-version-step.resolver.ts b/packages/twenty-server/src/engine/core-modules/workflow/resolvers/workflow-version-step.resolver.ts index 2a2257e7c0f9..1ca41f569396 100644 --- a/packages/twenty-server/src/engine/core-modules/workflow/resolvers/workflow-version-step.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/workflow/resolvers/workflow-version-step.resolver.ts @@ -12,6 +12,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat import { UserAuthGuard } from 'src/engine/guards/user-auth.guard'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-step.workspace-service'; +import { WorkflowVersionDTO } from 'src/engine/core-modules/workflow/dtos/workflow-version.dto'; @Resolver() @UseGuards(WorkspaceAuthGuard, UserAuthGuard) @@ -60,7 +61,7 @@ export class WorkflowVersionStepResolver { }); } - @Mutation(() => Boolean) + @Mutation(() => WorkflowVersionDTO) async createDraftFromWorkflowVersion( @AuthWorkspace() { id: workspaceId }: Workspace, @Args('input') @@ -68,15 +69,15 @@ export class WorkflowVersionStepResolver { workflowId, workflowVersionIdToCopy, }: CreateDraftFromWorkflowVersionInput, - ) { - await this.workflowVersionStepWorkspaceService.createDraftFromWorkflowVersion( - { - workspaceId, - workflowId, - workflowVersionIdToCopy, - }, - ); - - return true; + ): Promise { + return { + id: await this.workflowVersionStepWorkspaceService.createDraftFromWorkflowVersion( + { + workspaceId, + workflowId, + workflowVersionIdToCopy, + }, + ), + }; } } diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts index fe0c7f1e05f3..66cc4d0f1606 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts @@ -58,6 +58,29 @@ export class ServerlessFunctionService { return this.serverlessFunctionRepository.findBy(where); } + async findOneOrFail({ + workspaceId, + id, + }: { + workspaceId: string; + id: string; + }) { + const serverlessFunction = + await this.serverlessFunctionRepository.findOneBy({ + id, + workspaceId, + }); + + if (!serverlessFunction) { + throw new ServerlessFunctionException( + `Function does not exist`, + ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_NOT_FOUND, + ); + } + + return serverlessFunction; + } + async hasServerlessFunctionPublishedVersion(serverlessFunctionId: string) { return await this.serverlessFunctionRepository.exists({ where: { @@ -72,18 +95,10 @@ export class ServerlessFunctionService { id: string, version: string, ): Promise<{ [filePath: string]: string } | undefined> { - const serverlessFunction = - await this.serverlessFunctionRepository.findOneBy({ - id, - workspaceId, - }); - - if (!serverlessFunction) { - throw new ServerlessFunctionException( - `Function does not exist`, - ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_NOT_FOUND, - ); - } + const serverlessFunction = await this.findOneOrFail({ + id, + workspaceId, + }); try { const folderPath = getServerlessFolder({ @@ -121,19 +136,10 @@ export class ServerlessFunctionService { ): Promise { await this.throttleExecution(workspaceId); - const functionToExecute = await this.serverlessFunctionRepository.findOneBy( - { - id, - workspaceId, - }, - ); - - if (!functionToExecute) { - throw new ServerlessFunctionException( - `Function does not exist`, - ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_NOT_FOUND, - ); - } + const functionToExecute = await this.findOneOrFail({ + id, + workspaceId, + }); const resultServerlessFunction = await this.serverlessService.execute( functionToExecute, @@ -163,15 +169,10 @@ export class ServerlessFunctionService { } async publishOneServerlessFunction(id: string, workspaceId: string) { - const existingServerlessFunction = - await this.serverlessFunctionRepository.findOneBy({ id, workspaceId }); - - if (!existingServerlessFunction) { - throw new ServerlessFunctionException( - `Function does not exist`, - ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_NOT_FOUND, - ); - } + const existingServerlessFunction = await this.findOneOrFail({ + id, + workspaceId, + }); if (isDefined(existingServerlessFunction.latestVersion)) { const latestCode = await this.getServerlessFunctionSourceCode( @@ -223,18 +224,10 @@ export class ServerlessFunctionService { workspaceId: string; isHardDeletion?: boolean; }) { - const existingServerlessFunction = - await this.serverlessFunctionRepository.findOneBy({ - id, - workspaceId, - }); - - if (!existingServerlessFunction) { - throw new ServerlessFunctionException( - `Function does not exist`, - ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_NOT_FOUND, - ); - } + const existingServerlessFunction = await this.findOneOrFail({ + id, + workspaceId, + }); if (isHardDeletion) { await this.serverlessFunctionRepository.delete(id); @@ -254,18 +247,10 @@ export class ServerlessFunctionService { serverlessFunctionInput: UpdateServerlessFunctionInput, workspaceId: string, ) { - const existingServerlessFunction = - await this.serverlessFunctionRepository.findOneBy({ - id: serverlessFunctionInput.id, - workspaceId, - }); - - if (!existingServerlessFunction) { - throw new ServerlessFunctionException( - `Function does not exist`, - ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_NOT_FOUND, - ); - } + const existingServerlessFunction = await this.findOneOrFail({ + id: serverlessFunctionInput.id, + workspaceId, + }); await this.serverlessFunctionRepository.update( existingServerlessFunction.id, @@ -367,67 +352,40 @@ export class ServerlessFunctionService { }); } - async copyOneServerlessFunction({ - serverlessFunctionToCopyId, - serverlessFunctionToCopyVersion, + async usePublishedVersionAsDraft({ + id, + version, workspaceId, }: { - serverlessFunctionToCopyId: string; - serverlessFunctionToCopyVersion: string; + id: string; + version: string; workspaceId: string; }) { - const serverlessFunctionToCopy = - await this.serverlessFunctionRepository.findOneBy({ - workspaceId, - id: serverlessFunctionToCopyId, - latestVersion: serverlessFunctionToCopyVersion, - }); - - if (!serverlessFunctionToCopy) { - throw new ServerlessFunctionException( - 'Function does not exist', - ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_NOT_FOUND, - ); - } - - const serverlessFunctionToCreate = this.serverlessFunctionRepository.create( - { - name: serverlessFunctionToCopy?.name, - description: serverlessFunctionToCopy?.description, - timeoutSeconds: serverlessFunctionToCopy?.timeoutSeconds, - workspaceId, - layerVersion: LAST_LAYER_VERSION, - }, - ); - - const copiedServerlessFunction = - await this.serverlessFunctionRepository.save(serverlessFunctionToCreate); - - const serverlessFunctionToCopyFileFolder = getServerlessFolder({ - serverlessFunction: serverlessFunctionToCopy, - version: 'latest', - }); - const copiedServerlessFunctionFileFolder = getServerlessFolder({ - serverlessFunction: copiedServerlessFunction, - version: 'draft', + const serverlessFunction = await this.findOneOrFail({ + id, + workspaceId, }); await this.fileStorageService.copy({ from: { - folderPath: serverlessFunctionToCopyFileFolder, + folderPath: getServerlessFolder({ + serverlessFunction: serverlessFunction, + version, + }), }, to: { - folderPath: copiedServerlessFunctionFileFolder, + folderPath: getServerlessFolder({ + serverlessFunction: serverlessFunction, + version: 'draft', + }), }, }); await this.buildServerlessFunction({ - serverlessFunctionId: copiedServerlessFunction.id, + serverlessFunctionId: id, serverlessFunctionVersion: 'draft', workspaceId, }); - - return copiedServerlessFunction; } private async throttleExecution(workspaceId: string) { diff --git a/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-version-step.workspace-service.ts b/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-version-step.workspace-service.ts index be3791effd2e..aeb849aa3387 100644 --- a/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-version-step.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-version-step.workspace-service.ts @@ -198,37 +198,27 @@ export class WorkflowVersionStepWorkspaceService { step: WorkflowAction; workspaceId: string; }): Promise { - const newStepId = v4(); - switch (step.type) { case WorkflowActionType.CODE: { - const copiedServerlessFunction = - await this.serverlessFunctionService.copyOneServerlessFunction({ - serverlessFunctionToCopyId: - step.settings.input.serverlessFunctionId, - serverlessFunctionToCopyVersion: - step.settings.input.serverlessFunctionVersion, - workspaceId, - }); + await this.serverlessFunctionService.usePublishedVersionAsDraft({ + id: step.settings.input.serverlessFunctionId, + version: step.settings.input.serverlessFunctionVersion, + workspaceId, + }); return { ...step, - id: newStepId, settings: { ...step.settings, input: { ...step.settings.input, - serverlessFunctionId: copiedServerlessFunction.id, - serverlessFunctionVersion: copiedServerlessFunction.latestVersion, + serverlessFunctionVersion: 'draft', }, }, }; } default: { - return { - ...step, - id: newStepId, - }; + return step; } } } @@ -473,17 +463,6 @@ export class WorkflowVersionStepWorkspaceService { assertWorkflowVersionIsDraft(draftWorkflowVersion); - if (Array.isArray(draftWorkflowVersion.steps)) { - await Promise.all( - draftWorkflowVersion.steps.map((step) => - this.runWorkflowVersionStepDeletionSideEffects({ - step, - workspaceId, - }), - ), - ); - } - const newWorkflowVersionTrigger = workflowVersionToCopy.trigger; const newWorkflowVersionSteps: WorkflowAction[] = []; @@ -500,6 +479,8 @@ export class WorkflowVersionStepWorkspaceService { steps: newWorkflowVersionSteps, trigger: newWorkflowVersionTrigger, }); + + return draftWorkflowVersion.id; } private async runWorkflowVersionStepDeletionSideEffects({ diff --git a/packages/twenty-server/src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job.ts b/packages/twenty-server/src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job.ts index 365b3e16b9d0..467fd090072a 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job.ts @@ -161,26 +161,30 @@ export class WorkflowStatusesUpdateJob { const newStep = { ...step }; if (step.type === WorkflowActionType.CODE) { - let serverlessFunction; - try { - serverlessFunction = - await this.serverlessFunctionService.publishOneServerlessFunction( - step.settings.input.serverlessFunctionId, - workspaceId, - ); + await this.serverlessFunctionService.publishOneServerlessFunction( + step.settings.input.serverlessFunctionId, + workspaceId, + ); } catch (e) { - serverlessFunction = null; + // publishOneServerlessFunction throws if no change have been + // applied between draft and lastPublished version. + // If no change have been applied, we just use the same + // serverless function version } - if (serverlessFunction) { - const newStepSettings = { ...step.settings }; + const serverlessFunction = + await this.serverlessFunctionService.findOneOrFail({ + id: step.settings.input.serverlessFunctionId, + workspaceId, + }); - newStepSettings.input.serverlessFunctionVersion = - serverlessFunction.latestVersion; + const newStepSettings = { ...step.settings }; - newStep.settings = newStepSettings; - } + newStepSettings.input.serverlessFunctionVersion = + serverlessFunction.latestVersion; + + newStep.settings = newStepSettings; } newSteps.push(newStep); } diff --git a/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx b/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx index f02f385b9ae5..a80a9277e29d 100644 --- a/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx +++ b/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx @@ -24,7 +24,7 @@ export const wrapHeadingsWithAnchor = (children: ReactNode): ReactNode => { .replace(/\s+/g, '-') .toLowerCase(); return cloneElement(child as ReactElement, { - id: id, + id, className: 'anchor', children: {child.props.children}, });