diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowCreateRecordBody.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowCreateRecordBody.tsx new file mode 100644 index 00000000000..4065d11a73c --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowCreateRecordBody.tsx @@ -0,0 +1,239 @@ +import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; +import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; +import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition'; +import { FormFieldInput } from '@/object-record/record-field/ui/components/FormFieldInput'; +import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation'; +import { Select } from '@/ui/input/components/Select'; +import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; +import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOrDefaultViewFromPrefetchedViews'; +import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; +import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField'; +import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; +import { useTheme } from '@emotion/react'; +import { useEffect, useState } from 'react'; +import { isDefined } from 'twenty-shared/utils'; +import { canObjectBeManagedByWorkflow } from 'twenty-shared/workflow'; +import { HorizontalSeparator, useIcons } from 'twenty-ui/display'; +import { type SelectOption } from 'twenty-ui/input'; +import { type JsonValue } from 'type-fest'; +import { useDebouncedCallback } from 'use-debounce'; +import { RelationType } from '~/generated-metadata/graphql'; + +type RelationManyToOneField = { + id: string; +}; + +export type CreateRecordFormData = { + objectName: string; + [field: string]: RelationManyToOneField | JsonValue; +}; + +type WorkflowCreateRecordBodyProps = { + defaultObjectName: string; + defaultObjectRecord: Record; + readonly: boolean; + actionType: 'CREATE_RECORD' | 'UPSERT_RECORD'; + onUpdate: (formData: CreateRecordFormData) => void; +}; + +const sortByViewFieldPosition = ( + a: { viewFieldPosition?: number }, + b: { viewFieldPosition?: number }, +) => { + if (isDefined(a.viewFieldPosition) && isDefined(b.viewFieldPosition)) { + return a.viewFieldPosition - b.viewFieldPosition; + } + + if (isDefined(a.viewFieldPosition)) { + return -1; + } + + if (isDefined(b.viewFieldPosition)) { + return 1; + } + + return 0; +}; + +export const WorkflowCreateRecordBody = ({ + defaultObjectName, + defaultObjectRecord, + readonly, + actionType, + onUpdate, +}: WorkflowCreateRecordBodyProps) => { + const theme = useTheme(); + + const { getIcon } = useIcons(); + + const { activeNonSystemObjectMetadataItems } = + useFilteredObjectMetadataItems(); + + const availableMetadata: Array> = + activeNonSystemObjectMetadataItems + .filter((objectMetadataItem) => + canObjectBeManagedByWorkflow({ + nameSingular: objectMetadataItem.nameSingular, + isSystem: objectMetadataItem.isSystem, + }), + ) + .map((item) => ({ + Icon: getIcon(item.icon), + label: item.labelPlural, + value: item.nameSingular, + })); + + const [formData, setFormData] = useState({ + objectName: defaultObjectName, + ...defaultObjectRecord, + }); + + const objectNameSingular = formData.objectName; + + const { objectMetadataItems } = useObjectMetadataItems(); + + const objectMetadataItem = objectMetadataItems.find( + (item) => item.nameSingular === objectNameSingular, + ); + + const { view: indexView } = useViewOrDefaultViewFromPrefetchedViews({ + objectMetadataItemId: objectMetadataItem?.id ?? '', + }); + + const viewFields = indexView?.viewFields ?? []; + + const inlineFieldMetadataItems = objectMetadataItem?.fields + .filter((fieldMetadataItem) => + shouldDisplayFormField({ fieldMetadataItem, actionType }), + ) + .map((fieldMetadataItem) => { + const viewField = viewFields.find( + (viewField) => viewField.fieldMetadataId === fieldMetadataItem.id, + ); + return { + ...fieldMetadataItem, + viewFieldPosition: viewField?.position, + }; + }) + .sort(sortByViewFieldPosition); + + const inlineFieldDefinitions = isDefined(objectMetadataItem) + ? inlineFieldMetadataItems?.map((fieldMetadataItem) => + formatFieldMetadataItemAsFieldDefinition({ + field: fieldMetadataItem, + objectMetadataItem, + showLabel: true, + labelWidth: 90, + }), + ) + : []; + + const handleFieldChange = ( + fieldName: keyof CreateRecordFormData, + updatedValue: JsonValue, + ) => { + const fieldDefinition = inlineFieldDefinitions?.find( + (definition) => definition.metadata.fieldName === fieldName, + ); + + if (!isDefined(fieldDefinition)) { + return; + } + + const isFieldRelationManyToOne = + isFieldRelation(fieldDefinition) && + fieldDefinition.metadata.relationType === RelationType.MANY_TO_ONE; + + const fieldValue = isFieldRelationManyToOne + ? { + id: updatedValue, + } + : updatedValue; + + const newFormData: CreateRecordFormData = { + ...formData, + [fieldName]: fieldValue, + }; + + setFormData(newFormData); + + saveAction(newFormData); + }; + + const saveAction = useDebouncedCallback( + async (formData: CreateRecordFormData) => { + if (readonly === true) { + return; + } + + const { objectName: updatedObjectName, ...updatedOtherFields } = formData; + + onUpdate({ + objectName: updatedObjectName, + ...updatedOtherFields, + }); + }, + 1_000, + ); + + useEffect(() => { + return () => { + saveAction.flush(); + }; + }, [saveAction]); + + return ( + + { - const newFormData: CreateRecordFormData = { - objectName: updatedObjectName, - }; - - setFormData(newFormData); - - saveAction(newFormData); - }} - withSearchInput - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} - dropdownWidth={GenericDropdownContentWidth.ExtraLarge} - /> - - - - {inlineFieldDefinitions?.map((fieldDefinition) => { - const isFieldRelationManyToOne = - isFieldRelation(fieldDefinition) && - fieldDefinition.metadata.relationType === RelationType.MANY_TO_ONE; - - const currentValue = isFieldRelationManyToOne - ? ( - formData[ - fieldDefinition.metadata.fieldName - ] as RelationManyToOneField - )?.id - : (formData[fieldDefinition.metadata.fieldName] as JsonValue); - - return ( - { - handleFieldChange(fieldDefinition.metadata.fieldName, value); - }} - VariablePicker={WorkflowVariablePicker} - readonly={isFormDisabled} - /> - ); - })} - + {!actionOptions.readonly && } ); 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 71ab500d757..785cf850159 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 @@ -2,11 +2,13 @@ import { GMAIL_SEND_SCOPE } from '@/accounts/constants/GmailSendScope'; import { MICROSOFT_SEND_SCOPE } from '@/accounts/constants/MicrosoftSendScope'; import { type ConnectedAccount } from '@/accounts/types/ConnectedAccount'; import { useUploadAttachmentFile } from '@/activities/files/hooks/useUploadAttachmentFile'; +import { WorkflowSendEmailAttachments } from '@/advanced-text-editor/components/WorkflowSendEmailAttachments'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { SidePanelHeader } from '@/command-menu/components/SidePanelHeader'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { FormAdvancedTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormAdvancedTextFieldInput'; import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormTextFieldInput'; import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; @@ -16,6 +18,7 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; import { type WorkflowSendEmailAction } from '@/workflow/types/Workflow'; +import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; import { SEND_EMAIL_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/SendEmailAction'; import { useWorkflowActionHeader } from '@/workflow/workflow-steps/workflow-actions/hooks/useWorkflowActionHeader'; @@ -31,9 +34,6 @@ import { type SelectOption } from 'twenty-ui/input'; import { type JsonValue } from 'type-fest'; import { useDebouncedCallback } from 'use-debounce'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; -import { WorkflowSendEmailAttachments } from '@/advanced-text-editor/components/WorkflowSendEmailAttachments'; -import { FormAdvancedTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormAdvancedTextFieldInput'; -import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; const EMAIL_EDITOR_MIN_HEIGHT = 340; @@ -331,13 +331,6 @@ export const WorkflowEditActionSendEmail = ({ }} VariablePicker={WorkflowVariablePicker} /> - { - handleFieldChange('files', files); - }} - /> + { + handleFieldChange('files', files); + }} + /> {!actionOptions.readonly && } diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord.tsx index b194863278f..1b8fdc07e49 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord.tsx @@ -1,12 +1,29 @@ import { SidePanelHeader } from '@/command-menu/components/SidePanelHeader'; +import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; +import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition'; +import { FormFieldInput } from '@/object-record/record-field/ui/components/FormFieldInput'; +import { FormSingleRecordPicker } from '@/object-record/record-field/ui/form-types/components/FormSingleRecordPicker'; +import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/isFieldRelation'; +import { Select } from '@/ui/input/components/Select'; +import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; +import { WorkflowFieldsMultiSelect } from '@/workflow/components/WorkflowEditUpdateEventFieldsMultiSelect'; import { type WorkflowUpdateRecordAction } from '@/workflow/types/Workflow'; +import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; -import { WorkflowUpdateRecordBody } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowUpdateRecordBody'; - import { UPDATE_RECORD_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/UpdateRecordAction'; import { useWorkflowActionHeader } from '@/workflow/workflow-steps/workflow-actions/hooks/useWorkflowActionHeader'; import { type UpdateRecordFormData } from '@/workflow/workflow-steps/workflow-actions/types/update-record-form-data.type'; -import { useIcons } from 'twenty-ui/display'; +import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField'; +import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; +import { useTheme } from '@emotion/react'; +import { useEffect, useState } from 'react'; +import { isDefined } from 'twenty-shared/utils'; +import { canObjectBeManagedByWorkflow } from 'twenty-shared/workflow'; +import { HorizontalSeparator, useIcons } from 'twenty-ui/display'; +import { type SelectOption } from 'twenty-ui/input'; +import { type JsonValue } from 'type-fest'; +import { useDebouncedCallback } from 'use-debounce'; +import { RelationType } from '~/generated-metadata/graphql'; type WorkflowEditActionUpdateRecordProps = { action: WorkflowUpdateRecordAction; @@ -24,35 +41,119 @@ export const WorkflowEditActionUpdateRecord = ({ action, actionOptions, }: WorkflowEditActionUpdateRecordProps) => { + const theme = useTheme(); + + const { getIcon } = useIcons(); + + const { activeNonSystemObjectMetadataItems } = + useFilteredObjectMetadataItems(); + + const availableMetadata: Array> = + activeNonSystemObjectMetadataItems + .filter((objectMetadataItem) => + canObjectBeManagedByWorkflow({ + nameSingular: objectMetadataItem.nameSingular, + isSystem: objectMetadataItem.isSystem, + }), + ) + .map((item) => ({ + Icon: getIcon(item.icon), + label: item.labelPlural, + value: item.nameSingular, + })); + + const [formData, setFormData] = useState({ + objectNameSingular: action.settings.input.objectName, + objectRecordId: action.settings.input.objectRecordId, + fieldsToUpdate: action.settings.input.fieldsToUpdate ?? [], + ...action.settings.input.objectRecord, + }); + + const isFormDisabled = actionOptions.readonly === true; + const { headerTitle, headerIcon, headerIconColor, headerType } = useWorkflowActionHeader({ action, defaultTitle: UPDATE_RECORD_ACTION.defaultLabel, }); - const { getIcon } = useIcons(); + const handleFieldChange = ( + fieldName: keyof UpdateRecordFormData, + updatedValue: JsonValue, + ) => { + const newFormData: UpdateRecordFormData = { + ...formData, + [fieldName]: updatedValue, + }; - const isFormDisabled = actionOptions.readonly === true; + setFormData(newFormData); - const handleUpdate = (formData: UpdateRecordFormData) => { - if (actionOptions.readonly === true) { - return; - } - - actionOptions.onActionUpdate({ - ...action, - settings: { - ...action.settings, - input: { - objectName: formData.objectNameSingular, - objectRecord: formData, - objectRecordId: formData.objectRecordId ?? '', - fieldsToUpdate: formData.fieldsToUpdate, - }, - }, - }); + saveAction(newFormData); }; + const selectedObjectMetadataItem = activeNonSystemObjectMetadataItems.find( + (item) => item.nameSingular === formData.objectNameSingular, + ); + + const objectNameSingular = selectedObjectMetadataItem?.nameSingular; + + const inlineFieldMetadataItems = selectedObjectMetadataItem?.fields + .filter((fieldMetadataItem) => + shouldDisplayFormField({ + fieldMetadataItem, + actionType: 'UPDATE_RECORD', + }), + ) + .sort((fieldMetadataItemA, fieldMetadataItemB) => + fieldMetadataItemA.name.localeCompare(fieldMetadataItemB.name), + ); + + const inlineFieldDefinitions = isDefined(selectedObjectMetadataItem) + ? inlineFieldMetadataItems?.map((fieldMetadataItem) => + formatFieldMetadataItemAsFieldDefinition({ + field: fieldMetadataItem, + objectMetadataItem: selectedObjectMetadataItem, + showLabel: true, + labelWidth: 90, + }), + ) + : []; + + const saveAction = useDebouncedCallback( + async (formData: UpdateRecordFormData) => { + if (actionOptions.readonly === true) { + return; + } + + const { + objectNameSingular: updatedObjectName, + objectRecordId: updatedObjectRecordId, + fieldsToUpdate: updatedFieldsToUpdate, + ...updatedOtherFields + } = formData; + + actionOptions.onActionUpdate({ + ...action, + settings: { + ...action.settings, + input: { + objectName: updatedObjectName, + objectRecordId: updatedObjectRecordId ?? '', + fieldsToUpdate: updatedFieldsToUpdate ?? [], + objectRecord: updatedOtherFields, + }, + }, + }); + }, + 1_000, + ); + + useEffect(() => { + return () => { + saveAction.flush(); + }; + }, [saveAction]); + return ( <> - + + { - const newFormData: UpdateRecordFormData = { - objectNameSingular: updatedObjectName, - objectRecordId: '', - fieldsToUpdate: [], - }; - - setFormData(newFormData); - - saveAction(newFormData); - }} - withSearchInput - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} - dropdownWidth={GenericDropdownContentWidth.ExtraLarge} - /> - - - - {isDefined(objectNameSingular) && shouldPickRecord && ( - - handleFieldChange('objectRecordId', objectRecordId) - } - objectNameSingulars={[objectNameSingular]} - defaultValue={formData.objectRecordId} - disabled={readonly} - VariablePicker={WorkflowVariablePicker} - /> - )} - - {isDefined(selectedObjectMetadataItem) && ( - - handleFieldChange('fieldsToUpdate', fieldsToUpdate) - } - readonly={readonly ?? false} - defaultFields={formData.fieldsToUpdate} - /> - )} - - - - {formData.fieldsToUpdate.map((fieldName) => { - const fieldDefinition = inlineFieldDefinitions?.find((definition) => { - const isFieldRelationManyToOne = - isFieldRelation(definition) && - definition.metadata.relationType === RelationType.MANY_TO_ONE; - - const value = isFieldRelationManyToOne - ? `${definition.metadata.fieldName}Id` - : definition.metadata.fieldName; - - return value === fieldName; - }); - - if (!isDefined(fieldDefinition)) { - return null; - } - - const currentValue = formData[fieldName] as JsonValue; - - return ( - { - handleFieldChange(fieldName, value); - }} - VariablePicker={WorkflowVariablePicker} - readonly={readonly} - /> - ); - })} - - ); -}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField.ts index c56b03f54c4..97e2ccaa015 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField.ts @@ -3,7 +3,7 @@ import { type WorkflowActionType } from '@/workflow/types/Workflow'; import { CustomError } from 'twenty-shared/utils'; import { FieldMetadataType } from '~/generated-metadata/graphql'; -const COMMON_DISPLAYABLE_FIELD_TYPES = [ +const SUPPORTED_FORM_FIELD_TYPES = [ FieldMetadataType.TEXT, FieldMetadataType.NUMBER, FieldMetadataType.DATE, @@ -19,10 +19,6 @@ const COMMON_DISPLAYABLE_FIELD_TYPES = [ FieldMetadataType.DATE_TIME, FieldMetadataType.RAW_JSON, FieldMetadataType.UUID, -]; - -const FIND_RECORDS_DISPLAYABLE_FIELD_TYPES = [ - ...COMMON_DISPLAYABLE_FIELD_TYPES, FieldMetadataType.ARRAY, FieldMetadataType.RELATION, ]; @@ -34,35 +30,28 @@ export const shouldDisplayFormField = ({ fieldMetadataItem: FieldMetadataItem; actionType: WorkflowActionType; }) => { - let isTypeAllowedForAction = false; + if (!SUPPORTED_FORM_FIELD_TYPES.includes(fieldMetadataItem.type)) { + return false; + } + const isIdField = fieldMetadataItem.name === 'id'; + const isNotSupportedRelation = + fieldMetadataItem.type === FieldMetadataType.RELATION && + fieldMetadataItem.settings?.['relationType'] !== 'MANY_TO_ONE'; switch (actionType) { case 'CREATE_RECORD': - isTypeAllowedForAction = - fieldMetadataItem.type !== FieldMetadataType.RELATION || - fieldMetadataItem.settings?.['relationType'] === 'MANY_TO_ONE'; - return ( - isTypeAllowedForAction && - !fieldMetadataItem.isSystem && - fieldMetadataItem.isActive - ); case 'UPDATE_RECORD': case 'UPSERT_RECORD': - isTypeAllowedForAction = - COMMON_DISPLAYABLE_FIELD_TYPES.includes(fieldMetadataItem.type) || - fieldMetadataItem.settings?.['relationType'] === 'MANY_TO_ONE'; return ( - isTypeAllowedForAction && + !isNotSupportedRelation && + !fieldMetadataItem.isUIReadOnly && !fieldMetadataItem.isSystem && fieldMetadataItem.isActive ); case 'FIND_RECORDS': - isTypeAllowedForAction = FIND_RECORDS_DISPLAYABLE_FIELD_TYPES.includes( - fieldMetadataItem.type, - ); return ( - isTypeAllowedForAction && + !isNotSupportedRelation && (!fieldMetadataItem.isSystem || isIdField) && fieldMetadataItem.isActive ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx index 2f99efd6c49..3c303a78572 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx @@ -95,10 +95,13 @@ export const WorkflowEditTriggerWebhookForm = ({ return; } - triggerOptions.onTriggerUpdate({ - ...trigger, - name: newName, - }); + triggerOptions.onTriggerUpdate( + { + ...trigger, + name: newName, + }, + { computeOutputSchema: false }, + ); }} Icon={getIcon(headerIcon)} iconColor={getTriggerIconColor({ theme, triggerType: trigger.type })} diff --git a/packages/twenty-server/src/engine/core-modules/record-crud/services/upsert-record.service.ts b/packages/twenty-server/src/engine/core-modules/record-crud/services/upsert-record.service.ts index c56d4842b6c..466b58b3d5e 100644 --- a/packages/twenty-server/src/engine/core-modules/record-crud/services/upsert-record.service.ts +++ b/packages/twenty-server/src/engine/core-modules/record-crud/services/upsert-record.service.ts @@ -30,13 +30,8 @@ export class UpsertRecordService { ) {} async execute(params: UpsertRecordParams): Promise { - const { - objectName, - objectRecord, - fieldsToUpdate, - workspaceId, - rolePermissionConfig, - } = params; + const { objectName, objectRecord, workspaceId, rolePermissionConfig } = + params; if (!workspaceId) { return { @@ -54,7 +49,9 @@ export class UpsertRecordService { rolePermissionConfig, ); - const fieldsToUpdateArray = fieldsToUpdate || Object.keys(objectRecord); + const fieldsToUpdateArray = Object.keys(objectRecord).filter((field) => + isDefined(objectRecord[field]), + ); const { objectMetadataItemWithFieldsMaps } = await this.workflowCommonWorkspaceService.getObjectMetadataItemWithFieldsMaps( diff --git a/packages/twenty-server/src/engine/core-modules/record-crud/types/record-crud-input.type.ts b/packages/twenty-server/src/engine/core-modules/record-crud/types/record-crud-input.type.ts index 447921c86d1..2c8c395cf97 100644 --- a/packages/twenty-server/src/engine/core-modules/record-crud/types/record-crud-input.type.ts +++ b/packages/twenty-server/src/engine/core-modules/record-crud/types/record-crud-input.type.ts @@ -43,5 +43,4 @@ export type FindRecordsInput = { export type UpsertRecordInput = { objectName: string; objectRecord: ObjectRecordProperties; - fieldsToUpdate?: string[]; }; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/upsert-record.workflow-action.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/upsert-record.workflow-action.ts index ee0cc63b0c6..7ca7d475684 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/upsert-record.workflow-action.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/upsert-record.workflow-action.ts @@ -74,7 +74,6 @@ export class UpsertRecordWorkflowAction implements WorkflowAction { const toolOutput = await this.upsertRecordService.execute({ objectName: workflowActionInput.objectName, objectRecord: workflowActionInput.objectRecord, - fieldsToUpdate: workflowActionInput.fieldsToUpdate, workspaceId, rolePermissionConfig: executionContext.rolePermissionConfig, }); diff --git a/packages/twenty-shared/src/workflow/schemas/upsert-record-action-settings-schema.ts b/packages/twenty-shared/src/workflow/schemas/upsert-record-action-settings-schema.ts index 814fbb07cc1..5694b9b1677 100644 --- a/packages/twenty-shared/src/workflow/schemas/upsert-record-action-settings-schema.ts +++ b/packages/twenty-shared/src/workflow/schemas/upsert-record-action-settings-schema.ts @@ -7,6 +7,5 @@ export const workflowUpsertRecordActionSettingsSchema = input: z.object({ objectName: z.string(), objectRecord: objectRecordSchema, - fieldsToUpdate: z.array(z.string()), }), });