Fix From Many relation for deleted notes crashing (#11117)

In this PR, I'm: 
- fixing the root cause (we should not try to render a RecordChip if the
record is not defined in RelationFromMany Display)
- fixing related typing issues
- we won't be able to catch the issue from TS perspective as
ObjectRecord is a Record of string, any
This commit is contained in:
Charles Bochet
2025-03-24 13:29:44 +01:00
committed by GitHub
parent 3ec72a2bca
commit 6e7d2db58f
5 changed files with 30 additions and 18 deletions

View File

@ -1,5 +1,4 @@
import { useRecoilValue } from 'recoil';
import { Nullable } from 'twenty-ui';
import { ActivityTargetWithTargetRecord } from '@/activities/types/ActivityTargetObject';
import { Note } from '@/activities/types/Note';
@ -9,6 +8,7 @@ import { TaskTarget } from '@/activities/types/TaskTarget';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isDefined } from 'twenty-shared/utils';
export const useActivityTargetObjectRecords = (
@ -34,7 +34,7 @@ export const useActivityTargetObjectRecords = (
: [];
const activityTargetObjectRecords = targets
.map<Nullable<ActivityTargetWithTargetRecord>>((activityTarget) => {
.map<ActivityTargetWithTargetRecord | undefined>((activityTarget) => {
if (!isDefined(activityTarget)) {
throw new Error(`Cannot find activity target`);
}
@ -51,10 +51,11 @@ export const useActivityTargetObjectRecords = (
return undefined;
}
const targetObjectRecord =
activityTarget[correspondingObjectMetadataItem.nameSingular];
const targetObjectRecord = activityTarget[
correspondingObjectMetadataItem.nameSingular
] as ObjectRecord | undefined;
if (!targetObjectRecord) {
if (!isDefined(targetObjectRecord)) {
throw new Error(
`Cannot find target object record of type ${correspondingObjectMetadataItem.nameSingular}, make sure the request for activities eagerly loads for the target objects on activity target relation.`,
);
@ -62,7 +63,7 @@ export const useActivityTargetObjectRecords = (
return {
activityTarget,
targetObject: targetObjectRecord ?? undefined,
targetObject: targetObjectRecord,
targetObjectMetadataItem: correspondingObjectMetadataItem,
};
})

View File

@ -1,8 +1,8 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataType } from '~/generated-metadata/graphql';
export const getLabelIdentifierFieldValue = (
record: ObjectRecord,

View File

@ -22,6 +22,7 @@ export const useRecordChipData = ({
const identifierChipGenerator =
identifierChipGeneratorPerObject[objectNameSingular];
if (isDefined(identifierChipGenerator)) {
return {
recordChipData: identifierChipGenerator(record),

View File

@ -48,13 +48,17 @@ export const RelationFromManyFieldDisplay = () => {
return (
<ExpandableList isChipCountDisplayed={isFocused}>
{fieldValue.filter(isDefined).map((record) => (
<RecordChip
key={record.id}
objectNameSingular={objectNameSingular}
record={record[relationFieldName]}
/>
))}
{fieldValue
.map((record) =>
isDefined(record) && isDefined(record[relationFieldName]) ? (
<RecordChip
key={record.id}
objectNameSingular={objectNameSingular}
record={record[relationFieldName]}
/>
) : undefined,
)
.filter(isDefined)}
</ExpandableList>
);
} else if (isRelationFromActivityTargets) {

View File

@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
@ -10,14 +10,20 @@ export const DropdownOnToggleEffect = ({
onDropdownOpen?: () => void;
}) => {
const { isDropdownOpen } = useDropdown();
const [currentIsDropdownOpen, setCurrentIsDropdownOpen] =
useState(isDropdownOpen);
useEffect(() => {
if (isDropdownOpen) {
if (isDropdownOpen && !currentIsDropdownOpen) {
setCurrentIsDropdownOpen(isDropdownOpen);
onDropdownOpen?.();
} else {
}
if (!isDropdownOpen && currentIsDropdownOpen) {
setCurrentIsDropdownOpen(isDropdownOpen);
onDropdownClose?.();
}
}, [isDropdownOpen, onDropdownClose, onDropdownOpen]);
}, [currentIsDropdownOpen, isDropdownOpen, onDropdownClose, onDropdownOpen]);
return null;
};