From a82b74c1ff2666ae5970817f27676d97ed2772fb Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Thu, 30 Oct 2025 13:36:16 +0100 Subject: [PATCH] Make upsert action body common with create record instead of update record (#15442) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do not want the fields to update multiselect for upsert record action. We want all available fields displayed by default. This makes upsert record action closer to create record than update record. This PR: - deletes WorkflowUpdateRecordBody that was common between update and upsert and put back content into update - creates WorkflowCreateRecordBody that is now common between create and upsert - simplifies shouldDisplayFormField Before - using fields to update as update record action Capture d’écran 2025-10-30 à 10 00
24 After - displaying all fields as create record action Capture d’écran 2025-10-30 à 10 00
04 --- .../components/WorkflowCreateRecordBody.tsx | 239 ++++++++++++++++ .../WorkflowEditActionCreateRecord.tsx | 255 +++--------------- .../WorkflowEditActionSendEmail.tsx | 20 +- .../WorkflowEditActionUpdateRecord.tsx | 244 ++++++++++++++--- .../WorkflowEditActionUpsertRecord.tsx | 21 +- .../components/WorkflowUpdateRecordBody.tsx | 232 ---------------- .../utils/shouldDisplayFormField.ts | 33 +-- .../WorkflowEditTriggerWebhookForm.tsx | 11 +- .../services/upsert-record.service.ts | 13 +- .../types/record-crud-input.type.ts | 1 - .../upsert-record.workflow-action.ts | 1 - .../upsert-record-action-settings-schema.ts | 1 - 12 files changed, 526 insertions(+), 545 deletions(-) create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowCreateRecordBody.tsx delete mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowUpdateRecordBody.tsx 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()), }), });