diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/MorphRelationManyToOneFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/MorphRelationManyToOneFieldDisplay.tsx index b37a602ac6..726c11eda3 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/MorphRelationManyToOneFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/MorphRelationManyToOneFieldDisplay.tsx @@ -1,17 +1,22 @@ -import { CoreObjectNameSingular } from 'twenty-shared/types'; import { RecordChip } from '@/object-record/components/RecordChip'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; +import { ForbiddenFieldDisplay } from '@/object-record/record-field/ui/meta-types/display/components/ForbiddenFieldDisplay'; import { useMorphRelationToOneFieldDisplay } from '@/object-record/record-field/ui/meta-types/hooks/useMorphRelationToOneFieldDisplay'; import { useContext } from 'react'; +import { CoreObjectNameSingular } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; export const MorphRelationManyToOneFieldDisplay = () => { - const { morphFieldValuesWithObjectName } = + const { morphFieldValuesWithObjectName, foreignKeyFieldValue } = useMorphRelationToOneFieldDisplay(); const { disableChipClick, triggerEvent } = useContext(FieldContext); if (!isDefined(morphFieldValuesWithObjectName?.value)) { + if (isDefined(foreignKeyFieldValue)) { + return ; + } + return null; } diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMorphRelationToOneFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMorphRelationToOneFieldDisplay.ts index 99134159eb..27f6eab7f5 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMorphRelationToOneFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/hooks/useMorphRelationToOneFieldDisplay.ts @@ -13,7 +13,7 @@ import { isFieldMorphRelation } from '@/object-record/record-field/ui/types/guar import { useRecordFieldValue } from '@/object-record/record-store/hooks/useRecordFieldValue'; -import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { type FieldMorphRelationManyToOneValue } from '@/object-record/record-field/ui/types/FieldMetadata'; import { isDefined } from 'twenty-shared/utils'; export const useMorphRelationToOneFieldDisplay = () => { @@ -34,10 +34,12 @@ export const useMorphRelationToOneFieldDisplay = () => { const button = fieldDefinition.editButtonIcon; - const morphFieldValueWithObjectName = useRecordFieldValue<{ - objectNameSingular: string; - value: ObjectRecord; - }>(recordId, fieldDefinition.metadata.fieldName, fieldDefinition); + const morphFieldValueWithObjectName = + useRecordFieldValue( + recordId, + fieldDefinition.metadata.fieldName, + fieldDefinition, + ); if (!isDefined(morphFieldValueWithObjectName)) { return { @@ -66,6 +68,7 @@ export const useMorphRelationToOneFieldDisplay = () => { return { fieldDefinition, + foreignKeyFieldValue: morphFieldValueWithObjectName.foreignKeyFieldValue, morphFieldValuesWithObjectName: morphFieldValueWithObjectName, maxWidth: maxWidthForField, recordId, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldMetadata.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldMetadata.ts index bacd2a2b78..2971d49228 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldMetadata.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/types/FieldMetadata.ts @@ -276,6 +276,19 @@ export type FieldRelationValue< T extends FieldRelationToOneValue | FieldRelationFromManyValue, > = T; +export type FieldMorphRelationManyToOneValue = { + objectNameSingular: string; + objectNamePlural: string; + value?: ObjectRecord; + foreignKeyFieldValue: string; +} | null; + +export type FieldMorphRelationOneToManyValue = { + objectNameSingular: string; + objectNamePlural: string; + value: ObjectRecord[]; +}[]; + export type Json = ZodHelperLiteral | { [key: string]: Json } | Json[]; export type FieldJsonValue = Record | Json[] | null; diff --git a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts index daf9912699..b97f4e20eb 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts +++ b/packages/twenty-front/src/modules/object-record/record-store/states/selectors/recordStoreFieldValueSelector.ts @@ -1,11 +1,17 @@ import { atom, type Atom } from 'jotai'; +import { type FieldMetadataItemRelation } from '@/object-metadata/types/FieldMetadataItemRelation'; import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; -import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; +import { + type FieldMetadata, + type FieldMorphRelationManyToOneValue, + type FieldMorphRelationMetadata, + type FieldMorphRelationOneToManyValue, +} from '@/object-record/record-field/ui/types/FieldMetadata'; import { isFieldMorphRelation } from '@/object-record/record-field/ui/types/guards/isFieldMorphRelation'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { createAtomFamilySelector } from '@/ui/utilities/state/jotai/utils/createAtomFamilySelector'; -import { RelationType, type ObjectRecord } from 'twenty-shared/types'; +import { RelationType } from 'twenty-shared/types'; import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils'; const simpleFieldValueSelector = createAtomFamilySelector< @@ -34,61 +40,53 @@ const getMorphRelationFieldValueAtom = ( } const morphRelations = - ( - fieldDefinition.metadata as { - morphRelations?: Array<{ - type: string; - sourceFieldMetadata: { name: string }; - targetObjectMetadata: { - nameSingular: string; - namePlural: string; - }; - }>; - } - ).morphRelations ?? []; + (fieldDefinition.metadata as FieldMorphRelationMetadata).morphRelations ?? + []; + + const relationType = morphRelations[0]?.type; const derivedAtom = atom((get) => { - const record = get(recordStoreFamilyState.atomFamily(recordId)); + const recordStore = get(recordStoreFamilyState.atomFamily(recordId)); - const morphValuesWithObjectName = morphRelations.map((morphRelation) => { - const computedFieldName = computeMorphRelationFieldName({ + const computeMorphFieldName = (morphRelation: FieldMetadataItemRelation) => + computeMorphRelationFieldName({ fieldName: morphRelation.sourceFieldMetadata.name, - relationType: morphRelation.type as RelationType, + relationType: morphRelation.type, targetObjectMetadataNameSingular: morphRelation.targetObjectMetadata.nameSingular, targetObjectMetadataNamePlural: morphRelation.targetObjectMetadata.namePlural, }); - return { - objectNameSingular: morphRelation.targetObjectMetadata.nameSingular, - value: record?.[computedFieldName], - }; - }); - - const relationType = morphRelations[0]?.type; - if (relationType === RelationType.ONE_TO_MANY) { - return morphValuesWithObjectName.map((morphValue) => ({ - ...morphValue, - value: morphValue.value ? morphValue.value : [], - })) as { - objectNameSingular: string; - value: ObjectRecord[]; - }[]; + return morphRelations.map((morphRelation) => ({ + objectNameSingular: morphRelation.targetObjectMetadata.nameSingular, + objectNamePlural: morphRelation.targetObjectMetadata.namePlural, + value: recordStore?.[computeMorphFieldName(morphRelation)] ?? [], + })) as FieldMorphRelationOneToManyValue; } if (relationType === RelationType.MANY_TO_ONE) { - const morphValueFiltered = morphValuesWithObjectName.filter( - (morphValue) => isDefined(morphValue.value), + const morphValuesWithObjectName = morphRelations.map((morphRelation) => { + const computedFieldName = computeMorphFieldName(morphRelation); + + return { + objectNameSingular: morphRelation.targetObjectMetadata.nameSingular, + objectNamePlural: morphRelation.targetObjectMetadata.namePlural, + value: recordStore?.[computedFieldName], + foreignKeyFieldValue: recordStore?.[`${computedFieldName}Id`], + }; + }); + + const morphValueWithRelationOrForeignKey = morphValuesWithObjectName.find( + (morphValue) => isDefined(morphValue.foreignKeyFieldValue), ); - return morphValueFiltered.length > 0 - ? (morphValueFiltered[0] as { - objectNameSingular: string; - value: ObjectRecord; - }) - : null; + if (isDefined(morphValueWithRelationOrForeignKey)) { + return morphValueWithRelationOrForeignKey as FieldMorphRelationManyToOneValue; + } + + return null; } return null;