From fe2555733776eaef95cebeb2ed2381b940e3a212 Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Wed, 21 May 2025 11:02:04 +0200 Subject: [PATCH] Fix send email connected account (#12149) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/twentyhq/twenty/issues/12144 Account owner id is not fetched anymore by default in find many connected accounts. This is coming from the relation migration, since account owner id is not a basic field anymore. Enforcing the fetch of account owner id + adding tests Capture d’écran 2025-05-20 à 18 23 44 --- .../WorkflowEditActionSendEmail.tsx | 7 + .../WorkflowEditActionSendEmail.stories.tsx | 143 ++++++++++++++++++ .../testing/mock-data/connected-accounts.ts | 28 ++++ 3 files changed, 178 insertions(+) create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionSendEmail.stories.tsx create mode 100644 packages/twenty-front/src/testing/mock-data/connected-accounts.ts diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail.tsx index bfb6efd0e..d003ff379 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail.tsx @@ -171,6 +171,13 @@ export const WorkflowEditActionSendEmail = ({ const { records: accounts, loading } = useFindManyRecords({ objectNameSingular: 'connectedAccount', filter, + recordGqlFields: { + id: true, + handle: true, + provider: true, + scopes: true, + accountOwnerId: true, + }, }); let emptyOption: SelectOption = { label: 'None', value: null }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionSendEmail.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionSendEmail.stories.tsx new file mode 100644 index 000000000..a2dde7fb5 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionSendEmail.stories.tsx @@ -0,0 +1,143 @@ +import { WorkflowSendEmailAction } from '@/workflow/types/Workflow'; +import { Meta, StoryObj } from '@storybook/react'; +import { expect, fn, within } from '@storybook/test'; +import { graphql, HttpResponse } from 'msw'; +import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; +import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; +import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; +import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; +import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator'; +import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator'; +import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator'; +import { graphqlMocks } from '~/testing/graphqlMocks'; +import { + getMockedConnectedAccount, + mockedConnectedAccounts, +} from '~/testing/mock-data/connected-accounts'; +import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow'; +import { WorkflowEditActionSendEmail } from '../WorkflowEditActionSendEmail'; + +const DEFAULT_ACTION: WorkflowSendEmailAction = { + id: getWorkflowNodeIdMock(), + name: 'Send Email', + type: 'SEND_EMAIL', + valid: false, + settings: { + input: { + connectedAccountId: '', + email: '', + subject: '', + body: '', + }, + outputSchema: {}, + errorHandlingOptions: { + retryOnFailure: { + value: false, + }, + continueOnFailure: { + value: false, + }, + }, + }, +}; + +const CONFIGURED_ACTION: WorkflowSendEmailAction = { + id: getWorkflowNodeIdMock(), + name: 'Send Welcome Email', + type: 'SEND_EMAIL', + valid: true, + settings: { + input: { + connectedAccountId: mockedConnectedAccounts[0].accountOwnerId, + email: 'test@twenty.com', + subject: 'Welcome to Twenty!', + body: 'Dear Tim,\n\nWelcome to Twenty! We are excited to have you on board.\n\nBest regards,\nThe Team', + }, + outputSchema: {}, + errorHandlingOptions: { + retryOnFailure: { + value: true, + }, + continueOnFailure: { + value: false, + }, + }, + }, +}; + +const meta: Meta = { + title: 'Modules/Workflow/WorkflowEditActionSendEmail', + component: WorkflowEditActionSendEmail, + parameters: { + msw: { + handlers: [ + ...graphqlMocks.handlers, + graphql.query('FindManyConnectedAccounts', () => { + return HttpResponse.json({ + data: { + connectedAccounts: getMockedConnectedAccount(), + }, + }); + }), + ], + }, + }, + args: { + action: DEFAULT_ACTION, + }, + decorators: [ + WorkflowStepActionDrawerDecorator, + WorkflowStepDecorator, + ComponentDecorator, + ObjectMetadataItemsDecorator, + SnackBarDecorator, + RouterDecorator, + WorkspaceDecorator, + I18nFrontDecorator, + ], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + actionOptions: { + onActionUpdate: fn(), + }, + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + expect(await canvas.findByText('Send Email')).toBeVisible(); + + expect(await canvas.findByText('Account')).toBeVisible(); + expect(await canvas.findByText('Subject')).toBeVisible(); + expect(await canvas.findByText('Body')).toBeVisible(); + }, +}; + +export const Configured: Story = { + args: { + action: CONFIGURED_ACTION, + actionOptions: { + onActionUpdate: fn(), + }, + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + expect(await canvas.findByText('Send Welcome Email')).toBeVisible(); + + expect(await canvas.findByText('Account')).toBeVisible(); + expect(await canvas.findByText('Subject')).toBeVisible(); + expect(await canvas.findByText('Body')).toBeVisible(); + + const emailInput = await canvas.findByText('tim@twenty.com'); + expect(emailInput).toBeVisible(); + + const subjectInput = await canvas.findByText('Welcome to Twenty!'); + expect(subjectInput).toBeVisible(); + }, +}; diff --git a/packages/twenty-front/src/testing/mock-data/connected-accounts.ts b/packages/twenty-front/src/testing/mock-data/connected-accounts.ts new file mode 100644 index 000000000..9f76973d5 --- /dev/null +++ b/packages/twenty-front/src/testing/mock-data/connected-accounts.ts @@ -0,0 +1,28 @@ +export const mockedConnectedAccounts = [ + { + id: '8619ace5-1814-4e56-8439-553eab32a5cc', + handle: 'tim@twenty.com', + provider: 'gmail', + scopes: ['https://www.googleapis.com/auth/gmail.readonly'], + accountOwnerId: '56561b12-cbad-49db-a6bc-00e6b153ec80', + }, +]; + +export const getMockedConnectedAccount = () => { + return { + edges: [ + { + node: { + ...mockedConnectedAccounts[0], + }, + cursor: null, + }, + ], + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + startCursor: null, + endCursor: null, + }, + }; +};