diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm.tsx index d4771446e5d3..c3b82ccddd8c 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm.tsx @@ -3,10 +3,14 @@ import { Controller, useFormContext } from 'react-hook-form'; import { z } from 'zod'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { fieldMetadataItemSchema } from '@/object-metadata/validation-schemas/fieldMetadataItemSchema'; import { getErrorMessageFromError } from '@/settings/data-model/fields/forms/utils/errorMessages'; +import { RelationType } from '@/settings/data-model/types/RelationType'; import { IconPicker } from '@/ui/input/components/IconPicker'; import { TextInput } from '@/ui/input/components/TextInput'; +import { useEffect, useState } from 'react'; +import { RelationDefinitionType } from '~/generated-metadata/graphql'; export const settingsDataModelFieldIconLabelFormSchema = ( existingOtherLabels: string[] = [], @@ -32,19 +36,47 @@ type SettingsDataModelFieldIconLabelFormProps = { disabled?: boolean; fieldMetadataItem?: FieldMetadataItem; maxLength?: number; + relationObjectMetadataItem?: ObjectMetadataItem; + relationType?: RelationType; }; export const SettingsDataModelFieldIconLabelForm = ({ disabled, fieldMetadataItem, maxLength, + relationObjectMetadataItem, + relationType, }: SettingsDataModelFieldIconLabelFormProps) => { const { control, trigger, formState: { errors }, + setValue, } = useFormContext(); + const [labelEditedManually, setLabelEditedManually] = useState(false); + const [iconEditedManually, setIconEditedManually] = useState(false); + + useEffect(() => { + if (labelEditedManually) return; + const label = [ + RelationDefinitionType.ManyToOne, + RelationDefinitionType.ManyToMany, + ].includes(relationType ?? RelationDefinitionType.OneToMany) + ? relationObjectMetadataItem?.labelPlural + : relationObjectMetadataItem?.labelSingular; + setValue('label', label ?? ''); + + if (iconEditedManually) return; + setValue('icon', relationObjectMetadataItem?.icon ?? 'IconUsers'); + }, [ + labelEditedManually, + iconEditedManually, + relationObjectMetadataItem, + setValue, + relationType, + ]); + return ( onChange(iconKey)} + onChange={({ iconKey }) => { + setIconEditedManually(true); + onChange(iconKey); + }} variant="primary" /> )} @@ -69,6 +104,7 @@ export const SettingsDataModelFieldIconLabelForm = ({ placeholder="Employees" value={value} onChange={(e) => { + setLabelEditedManually(true); onChange(e); trigger('label'); }} diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm.tsx index d6f3fe48be10..9b0968c4f180 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationForm.tsx @@ -10,11 +10,13 @@ import { fieldMetadataItemSchema } from '@/object-metadata/validation-schemas/fi import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength'; import { RELATION_TYPES } from '@/settings/data-model/constants/RelationTypes'; import { useRelationSettingsFormInitialValues } from '@/settings/data-model/fields/forms/relation/hooks/useRelationSettingsFormInitialValues'; +import { SettingsDataModelFieldPreviewCardProps } from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard'; import { RelationType } from '@/settings/data-model/types/RelationType'; import { IconPicker } from '@/ui/input/components/IconPicker'; import { Select } from '@/ui/input/components/Select'; import { TextInput } from '@/ui/input/components/TextInput'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; +import { useEffect, useState } from 'react'; import { RelationDefinitionType } from '~/generated-metadata/graphql'; export const settingsDataModelFieldRelationFormSchema = z.object({ @@ -39,6 +41,7 @@ export type SettingsDataModelFieldRelationFormValues = z.infer< type SettingsDataModelFieldRelationFormProps = { fieldMetadataItem: Pick; + objectMetadataItem: SettingsDataModelFieldPreviewCardProps['objectMetadataItem']; }; const StyledContainer = styled.div` @@ -79,26 +82,49 @@ const RELATION_TYPE_OPTIONS = Object.entries(RELATION_TYPES) export const SettingsDataModelFieldRelationForm = ({ fieldMetadataItem, + objectMetadataItem, }: SettingsDataModelFieldRelationFormProps) => { - const { control, watch: watchFormValue } = - useFormContext(); + const { + control, + watch: watchFormValue, + setValue, + } = useFormContext(); const { getIcon } = useIcons(); const { objectMetadataItems, findObjectMetadataItemById } = useFilteredObjectMetadataItems(); + const [labelEditedManually, setLabelEditedManually] = useState(false); + const { disableFieldEdition, disableRelationEdition, initialRelationFieldMetadataItem, initialRelationObjectMetadataItem, initialRelationType, - } = useRelationSettingsFormInitialValues({ fieldMetadataItem }); + } = useRelationSettingsFormInitialValues({ + fieldMetadataItem, + objectMetadataItem, + }); const selectedObjectMetadataItem = findObjectMetadataItemById( watchFormValue('relation.objectMetadataId'), ); const isMobile = useIsMobile(); + const relationType = watchFormValue('relation.type'); + + useEffect(() => { + if (labelEditedManually) return; + setValue( + 'relation.field.label', + [ + RelationDefinitionType.ManyToMany, + RelationDefinitionType.ManyToOne, + ].includes(relationType) + ? objectMetadataItem.labelPlural + : objectMetadataItem.labelSingular, + ); + }, [labelEditedManually, objectMetadataItem, relationType, setValue]); return ( @@ -169,7 +195,10 @@ export const SettingsDataModelFieldRelationForm = ({ disabled={disableFieldEdition} placeholder="Field name" value={value} - onChange={onChange} + onChange={(newValue) => { + setLabelEditedManually(true); + onChange(newValue); + }} fullWidth maxLength={FIELD_NAME_MAXIMUM_LENGTH} /> diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationSettingsFormCard.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationSettingsFormCard.tsx index db8f46e97216..33509e08e632 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationSettingsFormCard.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/components/SettingsDataModelFieldRelationSettingsFormCard.tsx @@ -114,6 +114,7 @@ export const SettingsDataModelFieldRelationSettingsFormCard = ({ form={ } /> diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/hooks/useRelationSettingsFormInitialValues.ts b/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/hooks/useRelationSettingsFormInitialValues.ts index bd4b2badd0e2..298c3ad6dc24 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/hooks/useRelationSettingsFormInitialValues.ts +++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/relation/hooks/useRelationSettingsFormInitialValues.ts @@ -2,15 +2,17 @@ import { useMemo } from 'react'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation'; +import { SettingsDataModelFieldPreviewCardProps } from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard'; import { RelationDefinitionType } from '~/generated-metadata/graphql'; export const useRelationSettingsFormInitialValues = ({ fieldMetadataItem, + objectMetadataItem, }: { fieldMetadataItem?: Pick; + objectMetadataItem?: SettingsDataModelFieldPreviewCardProps['objectMetadataItem']; }) => { const { objectMetadataItems } = useFilteredObjectMetadataItems(); @@ -28,11 +30,13 @@ export const useRelationSettingsFormInitialValues = ({ const initialRelationObjectMetadataItem = useMemo( () => relationObjectMetadataItemFromFieldMetadata ?? - objectMetadataItems.find( - ({ nameSingular }) => nameSingular === CoreObjectNameSingular.Person, - ) ?? + objectMetadataItem ?? objectMetadataItems.filter(isObjectMetadataAvailableForRelation)[0], - [objectMetadataItems, relationObjectMetadataItemFromFieldMetadata], + [ + objectMetadataItem, + objectMetadataItems, + relationObjectMetadataItemFromFieldMetadata, + ], ); const initialRelationType = @@ -44,7 +48,12 @@ export const useRelationSettingsFormInitialValues = ({ disableRelationEdition: !!relationFieldMetadataItem, initialRelationFieldMetadataItem: relationFieldMetadataItem ?? { icon: initialRelationObjectMetadataItem.icon ?? 'IconUsers', - label: '', + label: [ + RelationDefinitionType.ManyToMany, + RelationDefinitionType.ManyToOne, + ].includes(initialRelationType) + ? initialRelationObjectMetadataItem.labelPlural + : initialRelationObjectMetadataItem.labelSingular, }, initialRelationObjectMetadataItem, initialRelationType, diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx index 4d00210c8782..0b27c458859b 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx @@ -2,6 +2,7 @@ import { useCreateOneRelationMetadataItem } from '@/object-metadata/hooks/useCre import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; @@ -47,6 +48,7 @@ export const SettingsObjectNewFieldConfigure = () => { const { findActiveObjectMetadataItemBySlug } = useFilteredObjectMetadataItems(); + const activeObjectMetadataItem = findActiveObjectMetadataItemBySlug(objectSlug); const { createMetadataField } = useFieldMetadataItem(); @@ -67,6 +69,13 @@ export const SettingsObjectNewFieldConfigure = () => { }, }); + const fieldMetadataItem: Pick = + { + icon: formConfig.watch('icon'), + label: formConfig.watch('label') || 'Employees', + type: formConfig.watch('type'), + }; + const [, setObjectViews] = useState([]); const [, setRelationObjectViews] = useState([]); @@ -200,11 +209,7 @@ export const SettingsObjectNewFieldConfigure = () => {