From e45e45d8b2f0080a17c25b89dc4a97ea95e3fc78 Mon Sep 17 00:00:00 2001 From: sid0-0 <43578323+sid0-0@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:59:37 +0530 Subject: [PATCH] Prefill Relation Fields with Initiating Object Icon and Name (#7363) feat: #7355 Behaviour implemented: 1. Relation field name field is updated when relation type is updated 2. Icon is only prefilled in the beginning 3. If user manually edits the field name, then no subsequent updates are made to that field upon relation type change. https://github.com/user-attachments/assets/d372b106-8dcb-458d-8374-a76cd130f091 --------- Co-authored-by: sid0-0 Co-authored-by: Lucas Bordeau --- .../SettingsDataModelFieldIconLabelForm.tsx | 38 ++++++++++++++++++- .../SettingsDataModelFieldRelationForm.tsx | 37 ++++++++++++++++-- ...DataModelFieldRelationSettingsFormCard.tsx | 1 + .../useRelationSettingsFormInitialValues.ts | 21 +++++++--- .../SettingsObjectNewFieldConfigure.tsx | 15 +++++--- 5 files changed, 96 insertions(+), 16 deletions(-) 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 d4771446e..c3b82ccdd 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 d6f3fe48b..9b0968c4f 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 db8f46e97..33509e08e 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 bd4b2badd..298c3ad6d 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 4d00210c8..0b27c4588 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 = () => {