From c48d14715c77241826a4b4eaa15c0e1e8631c9bd Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Wed, 6 Aug 2025 16:41:06 +0200 Subject: [PATCH] Fixed show page crash with object metadata item not found (#13694) This PR fixes a bug that appeared because of a race condition with context store when navigating between settings page and show page. The bug was caused because record title cell used on record show page was trying to retrieve the object metadata item before the context store was initialized. I created a new hook that supports an undefined state for one render loop, since in that case components can be rendered before the context store is initialized. Fixes https://github.com/twentyhq/twenty/issues/13649 --- .../useContextStoreObjectMetadataItem.ts | 22 +++++++++++++++++++ .../hooks/useRecordTitleCell.tsx | 11 ++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItem.ts diff --git a/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItem.ts b/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItem.ts new file mode 100644 index 0000000000..c02ee5cee5 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/hooks/useContextStoreObjectMetadataItem.ts @@ -0,0 +1,22 @@ +import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilValue } from 'recoil'; + +export const useContextStoreObjectMetadataItem = ( + contextStoreInstanceId?: string, +) => { + const objectMetadataItemId = useRecoilComponentValue( + contextStoreCurrentObjectMetadataItemIdComponentState, + contextStoreInstanceId, + ); + + const objectMetadataItems = useRecoilValue(objectMetadataItemsState); + + const objectMetadataItem = objectMetadataItems.find( + (objectMetadataItemToFind) => + objectMetadataItemToFind.id === objectMetadataItemId, + ); + + return { objectMetadataItem }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useRecordTitleCell.tsx b/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useRecordTitleCell.tsx index b62f31c1a9..7440f3c77c 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useRecordTitleCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/hooks/useRecordTitleCell.tsx @@ -1,4 +1,4 @@ -import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; +import { useContextStoreObjectMetadataItem } from '@/context-store/hooks/useContextStoreObjectMetadataItem'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { useInitDraftValue } from '@/object-record/record-field/hooks/useInitDraftValue'; import { isInlineCellInEditModeFamilyState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeFamilyState'; @@ -9,6 +9,7 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { useRecoilCallback } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; export const useRecordTitleCell = () => { const { goBackToPreviousDropdownFocusId } = @@ -18,7 +19,7 @@ export const useRecordTitleCell = () => { const { removeFocusItemFromFocusStackById } = useRemoveFocusItemFromFocusStackById(); - const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); + const { objectMetadataItem } = useContextStoreObjectMetadataItem(); const closeRecordTitleCell = useRecoilCallback( ({ set }) => @@ -68,6 +69,12 @@ export const useRecordTitleCell = () => { fieldName: string; containerType: RecordTitleCellContainerType; }) => { + if (!isDefined(objectMetadataItem)) { + throw new Error( + 'Cannot find object metadata item in openRecordTitleCell this should not happen.', + ); + } + pushFocusItemToFocusStack({ focusId: getRecordFieldInputInstanceId({ recordId,