From db5897d4d02a9e50e7a39828da7f9917ad2ffb8e Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Sat, 30 Aug 2025 13:36:28 +0200 Subject: [PATCH] Refactor board field definitions to use record fields (#14165) This PR removes board field definitions usage in favor of record fields, like we've already done on table with table columns. This PR also introduces a first step in the refactoring of the RecordIndexContext as a new way to store in-memory a normalized cache for some states used pretty much everywhere like field metadata items or field definition (for now but it will soon be removed). Since most of those states do not change if we don't modify the metadata, then we can safely store them in a context, which has the fastest access time in React. Co-authored-by: Charles Bochet --- .../useRecordIndexTableQuery.test.tsx | 51 ++++---- .../ObjectOptionsDropdownContent.stories.tsx | 15 +++ .../components/RecordBoardCard.tsx | 15 +-- .../components/RecordBoardCardBody.tsx | 118 +++++++++--------- .../useRecordBoardCardMetadataFromPosition.ts | 30 +++-- .../RecordBoardColumnCardsContainer.tsx | 8 +- ...cordBoardFieldDefinitionsComponentState.ts | 12 -- ...isibleFieldDefinitionsComponentSelector.ts | 17 --- .../perf/ChipFieldDisplay.perf.stories.tsx | 15 +++ .../RecordIndexBoardDataLoaderEffect.tsx | 15 --- .../components/RecordIndexContainerGater.tsx | 15 +++ .../contexts/RecordIndexContext.ts | 11 ++ .../hooks/useRecordBoardRecordGqlFields.ts | 23 +++- ...seRecordIndexFieldMetadataDerivedStates.ts | 63 ++++++++++ .../hooks/useRecordTableRecordGqlFields.ts | 4 +- .../components/RecordTableContextProvider.tsx | 49 -------- .../perf/RecordTableCell.perf.stories.tsx | 8 +- .../contexts/RecordTableContext.ts | 10 -- .../RecordTableCellFieldContextGeneric.tsx | 11 +- ...rdTableCellFieldContextLabelIdentifier.tsx | 2 +- .../RecordTableCellFieldContextWrapper.tsx | 19 ++- .../components/RecordTableHeaderCell.tsx | 3 +- .../SignInBackgroundMockContainer.tsx | 15 +++ .../ViewBarFilterDropdown.stories.tsx | 15 +++ .../WorkflowEditActionFindRecords.tsx | 17 ++- .../decorators/RecordTableDecorator.tsx | 8 +- .../JestRecordIndexContextProviderWrapper.tsx | 40 ++++++ ...dataAndApolloMocksAndActionMenuWrapper.tsx | 65 ++++------ 28 files changed, 386 insertions(+), 288 deletions(-) delete mode 100644 packages/twenty-front/src/modules/object-record/record-board/states/recordBoardFieldDefinitionsComponentState.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates.ts create mode 100644 packages/twenty-front/src/testing/jest/JestRecordIndexContextProviderWrapper.tsx diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useRecordIndexTableQuery.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useRecordIndexTableQuery.test.tsx index d735bd5255..58bae629ff 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useRecordIndexTableQuery.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useRecordIndexTableQuery.test.tsx @@ -11,10 +11,15 @@ import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewCompon import { type MockedResponse } from '@apollo/client/testing'; import gql from 'graphql-tag'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; -import { peopleQueryResult } from '~/testing/mock-data/people'; +import { JestRecordIndexContextProviderWrapper } from '~/testing/jest/JestRecordIndexContextProviderWrapper'; +import { + getMockPersonObjectMetadataItem, + peopleQueryResult, +} from '~/testing/mock-data/people'; const recordTableId = 'people'; const objectNameSingular = 'person'; +const mockPersonObjectMetadataItem = getMockPersonObjectMetadataItem(); const ObjectNamePluralSetter = ({ children }: { children: ReactNode }) => { return <>{children}; @@ -660,29 +665,33 @@ jest.mock('react-router-dom', () => ({ const Wrapper = ({ children }: { children: ReactNode }) => { return ( - - - + - - - - {children} - - - - - - + + + + {children} + + + + + + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx index 7e8a013c54..3ae9fe7602 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/__stories__/ObjectOptionsDropdownContent.stories.tsx @@ -7,6 +7,7 @@ import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropd import { ObjectOptionsDropdownContext } from '@/object-record/object-options-dropdown/states/contexts/ObjectOptionsDropdownContext'; import { type ObjectOptionsContentId } from '@/object-record/object-options-dropdown/types/ObjectOptionsContentId'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; @@ -77,6 +78,16 @@ const createStory = (contentId: ObjectOptionsContentId | null): Story => ({ (item) => item.nameSingular === 'company', )!; + const { + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + } = useRecordIndexFieldMetadataDerivedStates( + companyObjectMetadataItem, + instanceId, + ); + return ( ({ objectNameSingular: 'company', objectMetadataItem: companyObjectMetadataItem, recordIndexId: instanceId, + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, }} > { multiDragState.originalSelection.includes(recordId) && recordId !== multiDragState.primaryDraggedRecordId; - const visibleFieldDefinitions = useRecoilComponentValue( - recordBoardVisibleFieldDefinitionsComponentSelector, - ); - const isCompactModeActive = useRecoilComponentValue( isRecordBoardCompactModeActiveComponentState, ); @@ -223,10 +218,6 @@ export const RecordBoardCard = () => { rootMargin: '1000px', }); - const visibleFieldDefinitionsFiltered = visibleFieldDefinitions.filter( - (boardField) => !boardField.isLabelIdentifier, - ); - return ( { isOpen={isCardExpanded || !isCompactModeActive} initial={false} > - + diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardBody.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardBody.tsx index d146d57eac..d19e02afca 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardBody.tsx @@ -5,29 +5,30 @@ import { StopPropagationContainer } from '@/object-record/record-board/record-bo import { RECORD_BOARD_CARD_INPUT_ID_PREFIX } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardInputIdPrefix'; import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext'; import { recordBoardCardHoverPositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState'; -import { type RecordBoardFieldDefinition } from '@/object-record/record-board/types/RecordBoardFieldDefinition'; +import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; import { FieldContext, type RecordUpdateHook, type RecordUpdateHookParams, } from '@/object-record/record-field/ui/contexts/FieldContext'; import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; -import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { getFieldButtonIcon } from '@/object-record/record-field/ui/utils/getFieldButtonIcon'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { useContext } from 'react'; -export const RecordBoardCardBody = ({ - fieldDefinitions, -}: { - fieldDefinitions: RecordBoardFieldDefinition[]; -}) => { +export const RecordBoardCardBody = () => { const { recordId, isRecordReadOnly } = useContext(RecordBoardCardContext); const { updateOneRecord, objectPermissions } = useContext(RecordBoardContext); + const { + labelIdentifierFieldMetadataItem, + fieldDefinitionByFieldMetadataItemId, + } = useRecordIndexContextOrThrow(); + const useUpdateOneRecordHook: RecordUpdateHook = () => { const updateEntity = ({ variables }: RecordUpdateHookParams) => { updateOneRecord?.({ @@ -39,18 +40,13 @@ export const RecordBoardCardBody = ({ return [updateEntity, { loading: false }]; }; - const fieldDefinitionsWithReadOnly = fieldDefinitions.map( - (fieldDefinition) => ({ - ...fieldDefinition, - isRecordFieldReadOnly: isRecordFieldReadOnly({ - isRecordReadOnly, - objectPermissions, - fieldMetadataItem: { - id: fieldDefinition.fieldMetadataId, - isUIReadOnly: fieldDefinition.metadata.isUIReadOnly ?? false, - }, - }), - }), + const visibleRecordFields = useRecoilComponentValue( + visibleRecordFieldsComponentSelector, + ); + + const visibleRecordFieldsExceptLabelIdentifier = visibleRecordFields.filter( + (recordField) => + recordField.fieldMetadataItemId !== labelIdentifierFieldMetadataItem?.id, ); const setRecordBoardCardHoverPosition = useSetRecoilComponentState( @@ -63,50 +59,52 @@ export const RecordBoardCardBody = ({ return ( - {fieldDefinitionsWithReadOnly.map((fieldDefinition, index) => ( - - handleMouseEnter(index), - }} - > - { + const correspondingFieldDefinition = + fieldDefinitionByFieldMetadataItemId[recordField.fieldMetadataItemId]; + + return ( + + handleMouseEnter(index), }} > - - - - - ))} + + + + + + ); + })} ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition.ts index 40c0c70769..92934003ea 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/hooks/useRecordBoardCardMetadataFromPosition.ts @@ -1,7 +1,8 @@ import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; import { recordBoardCardEditModePositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardEditModePositionComponentState'; import { recordBoardCardHoverPositionComponentState } from '@/object-record/record-board/record-board-card/states/recordBoardCardHoverPositionComponentState'; -import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector'; +import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -17,33 +18,36 @@ export const useRecordBoardCardMetadataFromPosition = () => { recordBoardCardEditModePositionComponentState, ); - const visibleFieldDefinitions = useRecoilComponentValue( - recordBoardVisibleFieldDefinitionsComponentSelector, + const visibleRecordFields = useRecoilComponentValue( + visibleRecordFieldsComponentSelector, ); - const visibleFieldDefinitionsFiltered = visibleFieldDefinitions.filter( - (boardField) => !boardField.isLabelIdentifier, + const { labelIdentifierFieldMetadataItem } = useRecordIndexContextOrThrow(); + + const visibleRecordFieldsFiltered = visibleRecordFields.filter( + (recordField) => + labelIdentifierFieldMetadataItem?.id !== recordField.fieldMetadataItemId, ); - const hoveredFieldDefinition = isDefined(hoverPosition) - ? visibleFieldDefinitionsFiltered.at(hoverPosition) + const hoveredRecordField = isDefined(hoverPosition) + ? visibleRecordFieldsFiltered.at(hoverPosition) : undefined; - const editedFieldDefinition = isDefined(editModePosition) - ? visibleFieldDefinitionsFiltered.at(editModePosition) + const editedRecordField = isDefined(editModePosition) + ? visibleRecordFieldsFiltered.at(editModePosition) : undefined; - const hoveredFieldMetadataItem = isDefined(hoveredFieldDefinition) + const hoveredFieldMetadataItem = isDefined(hoveredRecordField) ? objectMetadataItem.fields.find( (fieldMetadataItem) => - fieldMetadataItem.id === hoveredFieldDefinition.fieldMetadataId, + fieldMetadataItem.id === hoveredRecordField.fieldMetadataItemId, ) : undefined; - const editedFieldMetadataItem = isDefined(editedFieldDefinition) + const editedFieldMetadataItem = isDefined(editedRecordField) ? objectMetadataItem.fields.find( (fieldMetadataItem) => - fieldMetadataItem.id === editedFieldDefinition.fieldMetadataId, + fieldMetadataItem.id === editedRecordField.fieldMetadataItemId, ) : undefined; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx index 0201aa0fc4..6d4e13b5b7 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx @@ -10,7 +10,7 @@ import { RecordBoardColumnNewRecordButton } from '@/object-record/record-board/r import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; import { getNumberOfCardsPerColumnForSkeletonLoading } from '@/object-record/record-board/record-board-column/utils/getNumberOfCardsPerColumnForSkeletonLoading'; import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState'; -import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector'; +import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; import { isRecordIndexBoardColumnLoadingFamilyState } from '@/object-record/states/isRecordBoardColumnLoadingFamilyState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; @@ -52,11 +52,11 @@ export const RecordBoardColumnCardsContainer = ({ isRecordIndexBoardColumnLoadingFamilyState(columnId), ); - const visibleFieldDefinitions = useRecoilComponentValue( - recordBoardVisibleFieldDefinitionsComponentSelector, + const visibleRecordFields = useRecoilComponentValue( + visibleRecordFieldsComponentSelector, ); - const numberOfFields = visibleFieldDefinitions.length; + const numberOfFields = visibleRecordFields.length; const isCompactModeActive = useRecoilComponentValue( isRecordBoardCompactModeActiveComponentState, diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardFieldDefinitionsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardFieldDefinitionsComponentState.ts deleted file mode 100644 index 5c8995e7d4..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardFieldDefinitionsComponentState.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { type RecordBoardFieldDefinition } from '@/object-record/record-board/types/RecordBoardFieldDefinition'; -import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; - -export const recordBoardFieldDefinitionsComponentState = createComponentState< - RecordBoardFieldDefinition[] ->({ - key: 'recordBoardFieldDefinitionsComponentState', - defaultValue: [], - componentInstanceContext: RecordBoardComponentInstanceContext, -}); diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector.ts b/packages/twenty-front/src/modules/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector.ts deleted file mode 100644 index f4a4af4336..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; -import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState'; -import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; - -export const recordBoardVisibleFieldDefinitionsComponentSelector = - createComponentSelector({ - key: 'recordBoardVisibleFieldDefinitionsComponentSelector', - get: - ({ instanceId }) => - ({ get }) => - get( - recordBoardFieldDefinitionsComponentState.atomFamily({ instanceId }), - ) - .filter((field) => field.isVisible) - .sort((a, b) => a.position - b.position), - componentInstanceContext: RecordBoardComponentInstanceContext, - }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx index 5a4dc5be19..842e5fa37e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx @@ -4,6 +4,7 @@ import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlur import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ChipFieldDisplay } from '@/object-record/record-field/ui/meta-types/display/components/ChipFieldDisplay'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { ComponentDecorator } from 'twenty-ui/testing'; import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; @@ -22,6 +23,16 @@ const meta: Meta = { (item) => item.nameSingular === CoreObjectNameSingular.Company, )!; + const { + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + } = useRecordIndexFieldMetadataDerivedStates( + companyObjectMetadataItem, + instanceId, + ); + return ( diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx index 5645c761a1..5ae0781cdb 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx @@ -3,9 +3,7 @@ import { useRecoilValue } from 'recoil'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState'; -import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState'; import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector'; -import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState'; import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; @@ -17,19 +15,10 @@ type RecordIndexBoardDataLoaderEffectProps = { export const RecordIndexBoardDataLoaderEffect = ({ recordBoardId, }: RecordIndexBoardDataLoaderEffectProps) => { - const recordIndexFieldDefinitions = useRecoilValue( - recordIndexFieldDefinitionsState, - ); - const recordIndexIsCompactModeActive = useRecoilValue( recordIndexIsCompactModeActiveState, ); - const setRecordBoardFieldDefinitions = useSetRecoilComponentState( - recordBoardFieldDefinitionsComponentState, - recordBoardId, - ); - const selectedRecordIds = useRecoilComponentValue( recordBoardSelectedRecordIdsComponentSelector, recordBoardId, @@ -44,10 +33,6 @@ export const RecordIndexBoardDataLoaderEffect = ({ setIsCompactModeActive(recordIndexIsCompactModeActive); }, [recordIndexIsCompactModeActive, setIsCompactModeActive]); - useEffect(() => { - setRecordBoardFieldDefinitions(recordIndexFieldDefinitions); - }, [recordIndexFieldDefinitions, setRecordBoardFieldDefinitions]); - const setContextStoreTargetedRecords = useSetRecoilComponentState( contextStoreTargetedRecordsRuleComponentState, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx index daf0a761b0..0754007daa 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx @@ -11,6 +11,7 @@ import { RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect } from '@ import { RecordIndexLoadBaseOnContextStoreEffect } from '@/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect'; import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader'; import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick'; +import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates'; import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore'; import { PageBody } from '@/ui/layout/page/components/PageBody'; import { RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS } from '@/ui/utilities/drag-select/constants/RecordIndecDragSelectBoundaryClass'; @@ -52,6 +53,16 @@ export const RecordIndexContainerGater = () => { const hasObjectReadPermissions = objectPermissions.canReadObjectRecords; + const { + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + } = useRecordIndexFieldMetadataDerivedStates( + objectMetadataItem, + recordIndexId, + ); + if (!hasObjectReadPermissions) { return ; } @@ -67,6 +78,10 @@ export const RecordIndexContainerGater = () => { objectMetadataItem, onIndexRecordsLoaded: handleIndexRecordsLoaded, indexIdentifierUrl, + recordFieldByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + fieldMetadataItemByFieldMetadataItemId, + fieldDefinitionByFieldMetadataItemId, }} > ; recordIndexId: string; + recordFieldByFieldMetadataItemId: Record; + labelIdentifierFieldMetadataItem: FieldMetadataItem | undefined; + fieldMetadataItemByFieldMetadataItemId: Record; + fieldDefinitionByFieldMetadataItemId: Record< + string, + ColumnDefinition + >; }; export const [RecordIndexContextProvider, useRecordIndexContextOrThrow] = diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts index 3940fd7d1e..54fd0cffa7 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts @@ -3,8 +3,9 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { generateDepthOneWithoutRelationsRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneWithoutRelationsRecordGqlFields'; -import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector'; +import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { isDefined } from 'twenty-shared/utils'; @@ -15,11 +16,14 @@ export const useRecordBoardRecordGqlFields = ({ recordBoardId: string; objectMetadataItem: ObjectMetadataItem; }) => { - const visibleFieldDefinitions = useRecoilComponentValue( - recordBoardVisibleFieldDefinitionsComponentSelector, + const visibleRecordFields = useRecoilComponentValue( + visibleRecordFieldsComponentSelector, recordBoardId, ); + const { fieldMetadataItemByFieldMetadataItemId } = + useRecordIndexContextOrThrow(); + const recordGroupFieldMetadata = useRecoilComponentValue( recordGroupFieldMetadataComponentState, recordBoardId, @@ -40,11 +44,20 @@ export const useRecordBoardRecordGqlFields = ({ objectMetadataItem, }); + const visibleFieldMetadataItems = visibleRecordFields + .map( + (recordField) => + fieldMetadataItemByFieldMetadataItemId[ + recordField.fieldMetadataItemId + ] ?? null, + ) + .filter(isDefined); + const recordGqlFields: Record = { ...allDepthOneWithoutRelationsRecordGqlFields, ...Object.fromEntries( - visibleFieldDefinitions.map((visibleFieldDefinition) => [ - visibleFieldDefinition.metadata.fieldName, + visibleFieldMetadataItems.map((visibleFieldMetadataItem) => [ + visibleFieldMetadataItem.name, true, ]), ), diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates.ts new file mode 100644 index 0000000000..1c2bf74f20 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates.ts @@ -0,0 +1,63 @@ +import { labelIdentifierFieldMetadataItemSelector } from '@/object-metadata/states/labelIdentifierFieldMetadataItemSelector'; +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; +import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilValue } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; + +export const useRecordIndexFieldMetadataDerivedStates = ( + objectMetadataItem: ObjectMetadataItem | undefined, + recordIndexId?: string | undefined, +) => { + const fieldMetadataItems = objectMetadataItem?.fields ?? []; + + const fieldMetadataItemByFieldMetadataItemId = Object.fromEntries( + fieldMetadataItems.map((fieldMetadataItem) => [ + fieldMetadataItem.id, + fieldMetadataItem, + ]), + ); + + const currentRecordFields = useRecoilComponentValue( + currentRecordFieldsComponentState, + recordIndexId, + ); + + const recordFieldByFieldMetadataItemId = Object.fromEntries( + currentRecordFields.map((recordField) => [ + recordField.fieldMetadataItemId, + recordField, + ]), + ); + + const fieldDefinitionByFieldMetadataItemId = isDefined(objectMetadataItem) + ? Object.fromEntries( + fieldMetadataItems.map((fieldMetadataItem) => [ + fieldMetadataItem.id, + formatFieldMetadataItemAsColumnDefinition({ + field: fieldMetadataItem, + objectMetadataItem, + position: + recordFieldByFieldMetadataItemId[fieldMetadataItem.id] + ?.position ?? 0, + labelWidth: + recordFieldByFieldMetadataItemId[fieldMetadataItem.id]?.size ?? 0, + }), + ]), + ) + : {}; + + const labelIdentifierFieldMetadataItem = useRecoilValue( + labelIdentifierFieldMetadataItemSelector({ + objectMetadataItemId: objectMetadataItem?.id ?? '', + }), + ); + + return { + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + fieldDefinitionByFieldMetadataItemId, + recordFieldByFieldMetadataItemId, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts index 02ab21e1df..fcc85e3b8e 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts @@ -4,7 +4,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { generateDepthOneWithoutRelationsRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneWithoutRelationsRecordGqlFields'; import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; -import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { FieldMetadataType } from 'twenty-shared/types'; import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils'; @@ -19,7 +19,7 @@ export const useRecordTableRecordGqlFields = ({ ); const { fieldMetadataItemByFieldMetadataItemId } = - useRecordTableContextOrThrow(); + useRecordIndexContextOrThrow(); const { objectMetadataItem: noteTargetObjectMetadataItem } = useObjectMetadataItem({ diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx index cfa33ea4cd..d3a8633347 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx @@ -3,13 +3,9 @@ import { type ReactNode } from 'react'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { RecordTableContextProvider as RecordTableContextInternalProvider } from '@/object-record/record-table/contexts/RecordTableContext'; -import { labelIdentifierFieldMetadataItemSelector } from '@/object-metadata/states/labelIdentifierFieldMetadataItemSelector'; -import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; -import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState'; import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useRecoilValue } from 'recoil'; type RecordTableContextProviderProps = { viewBarId: string; @@ -37,47 +33,6 @@ export const RecordTableContextProvider = ({ recordTableId, ); - const currentRecordFields = useRecoilComponentValue( - currentRecordFieldsComponentState, - recordTableId, - ); - - const fieldMetadataItems = objectMetadataItem.fields; - - const fieldMetadataItemByFieldMetadataItemId = Object.fromEntries( - fieldMetadataItems.map((fieldMetadataItem) => [ - fieldMetadataItem.id, - fieldMetadataItem, - ]), - ); - - const recordFieldByFieldMetadataItemId = Object.fromEntries( - currentRecordFields.map((recordField) => [ - recordField.fieldMetadataItemId, - recordField, - ]), - ); - - const fieldDefinitionByFieldMetadataItemId = Object.fromEntries( - fieldMetadataItems.map((fieldMetadataItem) => [ - fieldMetadataItem.id, - formatFieldMetadataItemAsColumnDefinition({ - field: fieldMetadataItem, - objectMetadataItem, - position: - recordFieldByFieldMetadataItemId[fieldMetadataItem.id]?.position ?? 0, - labelWidth: - recordFieldByFieldMetadataItemId[fieldMetadataItem.id]?.size ?? 0, - }), - ]), - ); - - const labelIdentifierFieldMetadataItem = useRecoilValue( - labelIdentifierFieldMetadataItemSelector({ - objectMetadataItemId: objectMetadataItem.id, - }), - ); - return ( {children} diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx index 985a249271..d7f3c037f3 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx @@ -142,6 +142,10 @@ const meta: Meta = { // TODO: update performance mocks with new data, and merge with common mocks if possible objectMetadataItem: mockPerformance.objectMetadataItem as any, recordIndexId: 'recordIndexId', + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, }} > @@ -156,10 +160,6 @@ const meta: Meta = { objectPermissions: { objectMetadataId: mockPerformance.objectMetadataItem.id, }, - fieldDefinitionByFieldMetadataItemId, - fieldMetadataItemByFieldMetadataItemId, - labelIdentifierFieldMetadataItem, - recordFieldByFieldMetadataItemId, visibleRecordFields, }} > diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts index d5b45b2a4e..80fd218572 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts @@ -1,8 +1,5 @@ -import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; -import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; -import { type ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { type ObjectPermission } from '~/generated/graphql'; import { createRequiredContext } from '~/utils/createRequiredContext'; @@ -13,13 +10,6 @@ type RecordTableContextValue = { objectMetadataItem: ObjectMetadataItem; objectPermissions: ObjectPermission; visibleRecordFields: RecordField[]; - recordFieldByFieldMetadataItemId: Record; - labelIdentifierFieldMetadataItem: FieldMetadataItem | undefined; - fieldMetadataItemByFieldMetadataItemId: Record; - fieldDefinitionByFieldMetadataItemId: Record< - string, - ColumnDefinition - >; }; export const [RecordTableContextProvider, useRecordTableContextOrThrow] = diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextGeneric.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextGeneric.tsx index a66d086441..6ce6b5e39d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextGeneric.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextGeneric.tsx @@ -22,13 +22,14 @@ export const RecordTableCellFieldContextGeneric = ({ }: RecordTableCellFieldContextGenericProps) => { const { recordId, isRecordReadOnly } = useRecordTableRowContextOrThrow(); + const { objectMetadataItem, objectPermissions } = + useRecordTableContextOrThrow(); + const { - objectMetadataItem, - objectPermissions, + indexIdentifierUrl, + objectPermissionsByObjectMetadataId, fieldDefinitionByFieldMetadataItemId, - } = useRecordTableContextOrThrow(); - const { indexIdentifierUrl, objectPermissionsByObjectMetadataId } = - useRecordIndexContextOrThrow(); + } = useRecordIndexContextOrThrow(); const fieldDefinition = fieldDefinitionByFieldMetadataItemId[recordField.fieldMetadataItemId]; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx index 0fda493f41..0c59cdbade 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx @@ -28,7 +28,7 @@ export const RecordTableCellFieldContextLabelIdentifier = ({ useRecordIndexContextOrThrow(); const { recordId, isRecordReadOnly } = useRecordTableRowContextOrThrow(); const { fieldDefinitionByFieldMetadataItemId } = - useRecordTableContextOrThrow(); + useRecordIndexContextOrThrow(); const { recordField } = useContext(RecordTableCellContext); const { objectMetadataItem, recordTableId } = useRecordTableContextOrThrow(); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx index e9c2cc5324..e05682d6da 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx @@ -1,8 +1,7 @@ -import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { RECORD_TABLE_CELL_INPUT_ID_PREFIX } from '@/object-record/record-table/constants/RecordTableCellInputIdPrefix'; -import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableCellFieldContextGeneric } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextGeneric'; import { RecordTableCellFieldContextLabelIdentifier } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier'; @@ -19,8 +18,11 @@ export const RecordTableCellFieldContextWrapper = ({ children, }: RecordTableCellFieldContextWrapperProps) => { const { recordId } = useRecordTableRowContextOrThrow(); - const { objectMetadataItem, fieldMetadataItemByFieldMetadataItemId } = - useRecordTableContextOrThrow(); + + const { + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + } = useRecordIndexContextOrThrow(); const fieldMetadataItem = fieldMetadataItemByFieldMetadataItemId[recordField.fieldMetadataItemId]; @@ -31,13 +33,8 @@ export const RecordTableCellFieldContextWrapper = ({ prefix: RECORD_TABLE_CELL_INPUT_ID_PREFIX, }); - const isLabelIdentifier = isLabelIdentifierField({ - fieldMetadataItem: { - id: recordField.fieldMetadataItemId, - name: fieldMetadataItem.name, - }, - objectMetadataItem, - }); + const isLabelIdentifier = + labelIdentifierFieldMetadataItem?.id === recordField.fieldMetadataItemId; return ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx index f86f09109d..c7e2af5511 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx @@ -6,6 +6,7 @@ import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObje import { useUpdateRecordField } from '@/object-record/record-field/hooks/useUpdateRecordField'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; import { RecordTableColumnHeadWithDropdown } from '@/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown'; @@ -207,7 +208,7 @@ export const RecordTableHeaderCell = ({ const isMobile = useIsMobile(); - const { labelIdentifierFieldMetadataItem } = useRecordTableContextOrThrow(); + const { labelIdentifierFieldMetadataItem } = useRecordIndexContextOrThrow(); const isLabelIdentifier = recordField.fieldMetadataItemId === labelIdentifierFieldMetadataItem?.id; diff --git a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx index 3114e5dd07..fae745ec5d 100644 --- a/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx +++ b/packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx @@ -7,6 +7,7 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/con import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates'; import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers'; import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; @@ -39,6 +40,16 @@ export const SignInBackgroundMockContainer = () => { (objectMetadataItem) => objectMetadataItem.id === objectMetadataItemId, ); + const { + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + } = useRecordIndexFieldMetadataDerivedStates( + objectMetadataItem, + recordIndexId, + ); + return ( { objectMetadataItem: objectMetadataItem ?? objectMetadataItems[0], onIndexRecordsLoaded: () => {}, indexIdentifierUrl: () => '', + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, }} > = { setCurrentRecordFields(columns); + const { + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + } = useRecordIndexFieldMetadataDerivedStates( + companyObjectMetadataItem, + instanceId, + ); + return ( = { objectNameSingular: CoreObjectNameSingular.Company, objectMetadataItem: companyObjectMetadataItem, recordIndexId: instanceId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, }} > item.nameSingular === formData.objectNameSingular, @@ -80,6 +82,16 @@ export const WorkflowEditActionFindRecords = ({ const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); + const { + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + } = useRecordIndexFieldMetadataDerivedStates( + selectedObjectMetadataItem, + instanceId, + ); + const saveAction = useDebouncedCallback( async (formData: FindRecordsFormData) => { if (actionOptions.readonly === true) { @@ -118,7 +130,6 @@ export const WorkflowEditActionFindRecords = ({ action, defaultTitle: 'Search Records', }); - const instanceId = `workflow-edit-action-record-find-records-${action.id}-${formData.objectNameSingular}`; return ( <> @@ -174,6 +185,10 @@ export const WorkflowEditActionFindRecords = ({ objectMetadataItem: selectedObjectMetadataItem, recordIndexId: instanceId, objectPermissionsByObjectMetadataId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, }} > { + const { + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + } = useRecordIndexFieldMetadataDerivedStates(objectMetadataItem); + + return ( + 'indexIdentifierUrl', + onIndexRecordsLoaded: () => {}, + objectNamePlural: objectMetadataItem.namePlural, + objectNameSingular: objectMetadataItem.nameSingular, + objectMetadataItem: objectMetadataItem, + recordIndexId: 'recordIndexId', + labelIdentifierFieldMetadataItem, + recordFieldByFieldMetadataItemId, + fieldDefinitionByFieldMetadataItemId, + fieldMetadataItemByFieldMetadataItemId, + }} + > + {children} + + ); +}; diff --git a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx index 5b68c52cca..4fbe6625d5 100644 --- a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx +++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper.tsx @@ -1,7 +1,5 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; -import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; import { type MockedResponse } from '@apollo/client/testing'; import { type ReactNode } from 'react'; import { type MutableSnapshot } from 'recoil'; @@ -10,6 +8,7 @@ import { JestContextStoreSetter, type JestContextStoreSetterMocks, } from '~/testing/jest/JestContextStoreSetter'; +import { JestRecordIndexContextProviderWrapper } from '~/testing/jest/JestRecordIndexContextProviderWrapper'; import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; import { getMockObjectMetadataItemOrThrow } from '~/testing/utils/getMockObjectMetadataItemOrThrow'; @@ -49,48 +48,34 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({ return ({ children }: { children: ReactNode }) => ( - - - - 'indexIdentifierUrl', - onIndexRecordsLoaded: () => {}, - objectNamePlural: mockObjectMetadataItem.namePlural, - objectNameSingular: mockObjectMetadataItem.nameSingular, - objectMetadataItem: mockObjectMetadataItem, - recordIndexId: 'recordIndexId', - }} + - - {children} - - - - - + {children} + + + + ); };