diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx index 48ac76efb..5fc4227e5 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectMenu.tsx @@ -173,7 +173,9 @@ export const AdvancedFilterFieldSelectMenu = ({ {shouldShowSeparator && } {shouldShowHiddenFields && ( <> - + {visibleColumnsFieldMetadataItems.length > 0 && ( + + )} {hiddenColumnsFieldMetadataItems.map( (hiddenFieldMetadataItem, index) => ( diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueFormInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueFormInput.tsx index 69cbdb3ce..bdcbaa102 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueFormInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueFormInput.tsx @@ -9,6 +9,7 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata' import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { isObject } from '@sniptt/guards'; import { FieldMetadataType } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { JsonValue } from 'type-fest'; @@ -40,7 +41,13 @@ export const AdvancedFilterValueFormInput = ({ useApplyObjectFilterDropdownFilterValue(); const handleChange = (newValue: JsonValue) => { - applyObjectFilterDropdownFilterValue(String(newValue)); + if (typeof newValue === 'string') { + applyObjectFilterDropdownFilterValue(newValue); + } else if (Array.isArray(newValue) || isObject(newValue)) { + applyObjectFilterDropdownFilterValue(JSON.stringify(newValue)); + } else { + applyObjectFilterDropdownFilterValue(String(newValue)); + } }; const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( @@ -68,13 +75,15 @@ export const AdvancedFilterValueFormInput = ({ ); } + const field = { + type: recordFilter.type as FieldMetadataType, + label: '', + metadata: fieldDefinition?.metadata as FieldMetadata, + }; + return ( ) : isFieldFullName(field) ? ( @@ -170,7 +170,7 @@ export const FormFieldInput = ({ defaultValue={defaultValue as FieldMultiSelectValue | string | undefined} onChange={onChange} VariablePicker={VariablePicker} - options={field.metadata.options} + options={field.metadata?.options} readonly={readonly} placeholder={placeholder} /> @@ -213,7 +213,9 @@ export const FormFieldInput = ({ } + defaultValue={ + defaultValue as FieldRelationValue | string + } onChange={onChange} VariablePicker={VariablePicker} readonly={readonly} diff --git a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormAddressFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormAddressFieldInput.tsx index 6cc90d4b2..cd9908114 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormAddressFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormAddressFieldInput.tsx @@ -83,6 +83,7 @@ export const FormAddressFieldInput = ({ placeholder="Post Code" /> void; + label?: string; readonly?: boolean; VariablePicker?: VariablePickerComponent; }) => { @@ -52,7 +54,7 @@ export const FormCountrySelectInput = ({ return ( { + try { + return JSON.parse(value); + } catch (error) { + return value; + } +}; + export const FormMultiSelectFieldInput = ({ label, defaultValue, @@ -87,7 +96,7 @@ export const FormMultiSelectFieldInput = ({ const [draftValue, setDraftValue] = useState< | { type: 'static'; - value: FieldMultiSelectValue; + value: FieldMultiSelectValue | string; editingMode: 'view' | 'edit'; } | { @@ -171,10 +180,14 @@ export const FormMultiSelectFieldInput = ({ }; const selectedNames = - draftValue.type === 'static' ? draftValue.value : undefined; + draftValue.type === 'static' && isDefined(draftValue.value) + ? isArray(draftValue.value) + ? draftValue.value + : safeParsedValue(draftValue.value) + : undefined; const selectedOptions = - isDefined(selectedNames) && isDefined(options) + isDefined(selectedNames) && isDefined(options) && isArray(selectedNames) ? options.filter((option) => selectedNames.some((name) => option.value === name), ) @@ -246,7 +259,7 @@ export const FormMultiSelectFieldInput = ({ options={options} onCancel={onCancel} onOptionSelected={onOptionSelected} - values={draftValue.value} + values={selectedNames} /> )} diff --git a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormRelationToOneFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormRelationToOneFieldInput.tsx index b9a0690c1..48dd9a842 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormRelationToOneFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormRelationToOneFieldInput.tsx @@ -1,21 +1,28 @@ -import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent'; import { FormSingleRecordPicker } from '@/object-record/record-field/form-types/components/FormSingleRecordPicker'; -import { isDefined } from 'twenty-shared/utils'; -import { JsonValue } from 'type-fest'; +import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent'; import { FieldRelationToOneValue, FieldRelationValue, } from '@/object-record/record-field/types/FieldMetadata'; +import { isObject } from '@sniptt/guards'; +import { isDefined } from 'twenty-shared/utils'; +import { JsonValue } from 'type-fest'; export type FormRelationToOneFieldInputProps = { label?: string; objectNameSingular?: string; - defaultValue?: FieldRelationValue; + defaultValue?: FieldRelationValue | string; onChange: (value: JsonValue) => void; readonly?: boolean; VariablePicker?: VariablePickerComponent; }; +const isFieldRelationToOneValue = ( + value: FormRelationToOneFieldInputProps['defaultValue'], +): value is FieldRelationValue => { + return isObject(value) && isDefined(value?.id); +}; + export const FormRelationToOneFieldInput = ({ label, objectNameSingular, @@ -28,12 +35,12 @@ export const FormRelationToOneFieldInput = ({ isDefined(objectNameSingular) && ( { - onChange({ - id: recordId, - }); - }} + defaultValue={ + isFieldRelationToOneValue(defaultValue) + ? defaultValue?.id + : defaultValue + } + onChange={onChange} objectNameSingular={objectNameSingular} disabled={readonly} VariablePicker={VariablePicker} diff --git a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/__stories__/FormCountrySelectInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/__stories__/FormCountrySelectInput.stories.tsx index 8896df725..3eca18d21 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/__stories__/FormCountrySelectInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/__stories__/FormCountrySelectInput.stories.tsx @@ -15,6 +15,7 @@ type Story = StoryObj; export const Default: Story = { args: { + label: 'Country', selectedCountryName: 'Canada', }, play: async ({ canvasElement }) => { diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneObject.ts b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneObject.ts index c95991dd0..ae508e9da 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneObject.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldRelationToOneObject.ts @@ -8,4 +8,4 @@ export const isFieldRelationToOneObject = ( field: Pick, 'type' | 'metadata'>, ): field is FieldDefinition => isFieldRelation(field) && - field.metadata.relationType === RelationType.MANY_TO_ONE; + field.metadata?.relationType === RelationType.MANY_TO_ONE; 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 685a07d35..65eac4693 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 @@ -6,19 +6,21 @@ import { useEffect, useState } from 'react'; import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition'; import { FormFieldInput } from '@/object-record/record-field/components/FormFieldInput'; import { FormSingleRecordPicker } from '@/object-record/record-field/form-types/components/FormSingleRecordPicker'; +import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; import { WorkflowFieldsMultiSelect } from '@/workflow/components/WorkflowEditUpdateEventFieldsMultiSelect'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader'; import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow'; import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow'; import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; +import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; import { isDefined } from 'twenty-shared/utils'; import { HorizontalSeparator, useIcons } from 'twenty-ui/display'; import { SelectOption } from 'twenty-ui/input'; import { JsonValue } from 'type-fest'; import { useDebouncedCallback } from 'use-debounce'; -import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField'; +import { RelationType } from '~/generated-metadata/graphql'; type WorkflowEditActionUpdateRecordProps = { action: WorkflowUpdateRecordAction; @@ -217,25 +219,31 @@ export const WorkflowEditActionUpdateRecord = ({ {formData.fieldsToUpdate.map((fieldName) => { - const fieldDefinition = inlineFieldDefinitions?.find( - (definition) => definition.metadata.fieldName === 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[ - fieldDefinition.metadata.fieldName - ] as JsonValue; + const currentValue = formData[fieldName] as JsonValue; return ( { - handleFieldChange(fieldDefinition.metadata.fieldName, value); + handleFieldChange(fieldName, value); }} VariablePicker={WorkflowVariablePicker} readonly={isFormDisabled} diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFiltersEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFiltersEffect.tsx index a65857c0c..23232a8cf 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFiltersEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFiltersEffect.tsx @@ -68,7 +68,7 @@ export const WorkflowFindRecordsFiltersEffect = ({ isDefined(defaultValue?.recordFilterGroups) && defaultValue.recordFilterGroups.length > 0 ) { - setCurrentRecordFilterGroups(defaultValue.recordFilterGroups); + setCurrentRecordFilterGroups(defaultValue.recordFilterGroups ?? []); setHasInitializedCurrentRecordFilterGroups(true); } }, [