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 0000000000..4065d11a73 --- /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 71ab500d75..785cf85015 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 b194863278..1b8fdc07e4 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 c56b03f54c..97e2ccaa01 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 2f99efd6c4..3c303a7857 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 c56d4842b6..466b58b3d5 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 447921c86d..2c8c395cf9 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 ee0cc63b0c..7ca7d47568 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 814fbb07cc..5694b9b167 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()), }), });