Execute variables in action input (#7715)
- send context from all previous steps rather than unique payload - wrap input data in settings into input field - add email into send email action settings - update output shape <img width="553" alt="Capture d’écran 2024-10-15 à 15 21 32" src="https://github.com/user-attachments/assets/0f5ed004-0d6e-4a59-969b-a5710f3f3985"> <img width="761" alt="Capture d’écran 2024-10-15 à 15 20 09" src="https://github.com/user-attachments/assets/ac140846-c383-483b-968a-eab469b76785">
This commit is contained in:
@ -1,21 +1,21 @@
|
||||
import { GMAIL_SEND_SCOPE } from '@/accounts/constants/GmailSendScope';
|
||||
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import { Select, SelectOption } from '@/ui/input/components/Select';
|
||||
import { TextArea } from '@/ui/input/components/TextArea';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { WorkflowEditActionFormBase } from '@/workflow/components/WorkflowEditActionFormBase';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
import { WorkflowSendEmailStep } from '@/workflow/types/Workflow';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { IconMail, IconPlus, isDefined } from 'twenty-ui';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import { Select, SelectOption } from '@/ui/input/components/Select';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
import { GMAIL_SEND_SCOPE } from '@/accounts/constants/GmailSendScope';
|
||||
|
||||
const StyledTriggerSettings = styled.div`
|
||||
padding: ${({ theme }) => theme.spacing(6)};
|
||||
@ -37,6 +37,7 @@ type WorkflowEditActionFormSendEmailProps =
|
||||
|
||||
type SendEmailFormData = {
|
||||
connectedAccountId: string;
|
||||
email: string;
|
||||
subject: string;
|
||||
body: string;
|
||||
};
|
||||
@ -53,6 +54,7 @@ export const WorkflowEditActionFormSendEmail = (
|
||||
const form = useForm<SendEmailFormData>({
|
||||
defaultValues: {
|
||||
connectedAccountId: '',
|
||||
email: '',
|
||||
subject: '',
|
||||
body: '',
|
||||
},
|
||||
@ -83,10 +85,11 @@ export const WorkflowEditActionFormSendEmail = (
|
||||
useEffect(() => {
|
||||
form.setValue(
|
||||
'connectedAccountId',
|
||||
props.action.settings.connectedAccountId ?? '',
|
||||
props.action.settings.input.connectedAccountId ?? '',
|
||||
);
|
||||
form.setValue('subject', props.action.settings.subject ?? '');
|
||||
form.setValue('body', props.action.settings.body ?? '');
|
||||
form.setValue('email', props.action.settings.input.email ?? '');
|
||||
form.setValue('subject', props.action.settings.input.subject ?? '');
|
||||
form.setValue('body', props.action.settings.input.body ?? '');
|
||||
}, [props.action.settings, form]);
|
||||
|
||||
const saveAction = useDebouncedCallback(
|
||||
@ -99,9 +102,12 @@ export const WorkflowEditActionFormSendEmail = (
|
||||
...props.action,
|
||||
settings: {
|
||||
...props.action.settings,
|
||||
connectedAccountId: formData.connectedAccountId,
|
||||
subject: formData.subject,
|
||||
body: formData.body,
|
||||
input: {
|
||||
connectedAccountId: formData.connectedAccountId,
|
||||
email: formData.email,
|
||||
subject: formData.subject,
|
||||
body: formData.body,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -134,12 +140,12 @@ export const WorkflowEditActionFormSendEmail = (
|
||||
};
|
||||
|
||||
if (
|
||||
isDefined(props.action.settings.connectedAccountId) &&
|
||||
props.action.settings.connectedAccountId !== ''
|
||||
isDefined(props.action.settings.input.connectedAccountId) &&
|
||||
props.action.settings.input.connectedAccountId !== ''
|
||||
) {
|
||||
filter.or.push({
|
||||
id: {
|
||||
eq: props.action.settings.connectedAccountId,
|
||||
eq: props.action.settings.input.connectedAccountId,
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -198,6 +204,21 @@ export const WorkflowEditActionFormSendEmail = (
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="email"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<TextInput
|
||||
label="Email"
|
||||
placeholder="Enter receiver email (use {{variable}} for dynamic content)"
|
||||
value={field.value}
|
||||
onChange={(email) => {
|
||||
field.onChange(email);
|
||||
handleSave();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="subject"
|
||||
control={form.control}
|
||||
|
||||
@ -54,7 +54,7 @@ export const WorkflowEditActionFormServerlessFunction = (
|
||||
dropdownId="workflow-edit-action-function"
|
||||
label="Function"
|
||||
fullWidth
|
||||
value={props.action.settings.serverlessFunctionId}
|
||||
value={props.action.settings.input.serverlessFunctionId}
|
||||
options={availableFunctions}
|
||||
disabled={props.readonly}
|
||||
onChange={(updatedFunction) => {
|
||||
@ -66,7 +66,9 @@ export const WorkflowEditActionFormServerlessFunction = (
|
||||
...props.action,
|
||||
settings: {
|
||||
...props.action.settings,
|
||||
serverlessFunctionId: updatedFunction,
|
||||
input: {
|
||||
serverlessFunctionId: updatedFunction,
|
||||
},
|
||||
},
|
||||
});
|
||||
}}
|
||||
|
||||
@ -10,13 +10,18 @@ type BaseWorkflowStepSettings = {
|
||||
};
|
||||
|
||||
export type WorkflowCodeStepSettings = BaseWorkflowStepSettings & {
|
||||
serverlessFunctionId: string;
|
||||
input: {
|
||||
serverlessFunctionId: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type WorkflowSendEmailStepSettings = BaseWorkflowStepSettings & {
|
||||
connectedAccountId: string;
|
||||
subject?: string;
|
||||
body?: string;
|
||||
input: {
|
||||
connectedAccountId: string;
|
||||
email: string;
|
||||
subject?: string;
|
||||
body?: string;
|
||||
};
|
||||
};
|
||||
|
||||
type BaseWorkflowStep = {
|
||||
|
||||
@ -21,7 +21,9 @@ describe('addCreateStepNodes', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -34,7 +36,9 @@ describe('addCreateStepNodes', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@ -42,7 +42,9 @@ describe('generateWorkflowDiagram', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -55,7 +57,9 @@ describe('generateWorkflowDiagram', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
@ -96,7 +100,9 @@ describe('generateWorkflowDiagram', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -109,7 +115,9 @@ describe('generateWorkflowDiagram', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@ -80,7 +80,9 @@ describe('getWorkflowVersionDiagram', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
|
||||
@ -25,7 +25,9 @@ describe('insertStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -63,7 +65,9 @@ describe('insertStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -95,7 +99,9 @@ describe('insertStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -108,7 +114,9 @@ describe('insertStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -129,7 +137,9 @@ describe('insertStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -165,7 +175,9 @@ describe('insertStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -178,7 +190,9 @@ describe('insertStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -199,7 +213,9 @@ describe('insertStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
|
||||
@ -10,7 +10,9 @@ it('returns a deep copy of the provided steps array instead of mutating it', ()
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'first',
|
||||
input: {
|
||||
serverlessFunctionId: 'first',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -47,7 +49,9 @@ it('removes a step in a non-empty steps array', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -67,7 +71,9 @@ it('removes a step in a non-empty steps array', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -81,7 +87,9 @@ it('removes a step in a non-empty steps array', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
|
||||
@ -11,7 +11,9 @@ describe('replaceStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'first',
|
||||
input: {
|
||||
serverlessFunctionId: 'first',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -39,7 +41,9 @@ describe('replaceStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'second',
|
||||
input: {
|
||||
serverlessFunctionId: 'second',
|
||||
},
|
||||
},
|
||||
},
|
||||
stepId: stepToBeReplaced.id,
|
||||
@ -57,7 +61,9 @@ describe('replaceStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -77,7 +83,9 @@ describe('replaceStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
@ -91,7 +99,9 @@ describe('replaceStep', () => {
|
||||
retryOnFailure: { value: true },
|
||||
continueOnFailure: { value: false },
|
||||
},
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
input: {
|
||||
serverlessFunctionId: 'a5434be2-c10b-465c-acec-46492782a997',
|
||||
},
|
||||
},
|
||||
type: 'CODE',
|
||||
valid: true,
|
||||
|
||||
@ -14,7 +14,9 @@ export const getStepDefaultDefinition = (
|
||||
type: 'CODE',
|
||||
valid: false,
|
||||
settings: {
|
||||
serverlessFunctionId: '',
|
||||
input: {
|
||||
serverlessFunctionId: '',
|
||||
},
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
value: false,
|
||||
@ -33,9 +35,12 @@ export const getStepDefaultDefinition = (
|
||||
type: 'SEND_EMAIL',
|
||||
valid: false,
|
||||
settings: {
|
||||
connectedAccountId: '',
|
||||
subject: '',
|
||||
body: '',
|
||||
input: {
|
||||
connectedAccountId: '',
|
||||
email: '',
|
||||
subject: '',
|
||||
body: '',
|
||||
},
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
value: false,
|
||||
|
||||
Reference in New Issue
Block a user