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 a90ccf902c..648be4912a 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 @@ -12,6 +12,7 @@ import { RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect } from '@ import { RecordIndexEmptyStateNotShared } from '@/object-record/record-index/components/RecordIndexEmptyStateNotShared'; import { RecordIndexLoadBaseOnContextStoreEffect } from '@/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect'; import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader'; +import { RecordIndexViewFieldsSSESyncEffect } from '@/object-record/record-index/components/RecordIndexViewFieldsSSESyncEffect'; 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'; @@ -114,6 +115,7 @@ export const RecordIndexContainerGater = () => { + diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexViewFieldsSSESyncEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexViewFieldsSSESyncEffect.tsx new file mode 100644 index 0000000000..0072d38869 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexViewFieldsSSESyncEffect.tsx @@ -0,0 +1,43 @@ +import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent'; +import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow'; +import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; +import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; +import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; +import { viewFromViewIdFamilySelector } from '@/views/states/selectors/viewFromViewIdFamilySelector'; +import { useStore } from 'jotai'; +import { isDefined } from 'twenty-shared/utils'; +import { AllMetadataName } from '~/generated-metadata/graphql'; + +export const RecordIndexViewFieldsSSESyncEffect = () => { + const store = useStore(); + + const { syncRecordIndexViewFields } = useLoadRecordIndexStates(); + const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); + + const contextStoreCurrentViewId = useAtomComponentStateValue( + contextStoreCurrentViewIdComponentState, + ); + + useListenToMetadataOperationBrowserEvent({ + metadataName: AllMetadataName.viewField, + onMetadataOperationBrowserEvent: () => { + if (!isDefined(contextStoreCurrentViewId)) { + return; + } + + const currentView = store.get( + viewFromViewIdFamilySelector.selectorFamily({ + viewId: contextStoreCurrentViewId, + }), + ); + + if (!isDefined(currentView)) { + return; + } + + syncRecordIndexViewFields(currentView, objectMetadataItem); + }, + }); + + return null; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts index e8f57494b9..67bb1d2081 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts @@ -73,9 +73,9 @@ export const useLoadRecordIndexStates = () => { const { setRecordGroupsFromViewGroups } = useSetRecordGroups(); - const loadRecordIndexStates = useCallback( + const syncRecordIndexViewFields = useCallback( ( - view: View, + view: Pick, objectMetadataItem: EnrichedObjectMetadataItem, options?: { skipGlobalIndexStates?: boolean }, ) => { @@ -134,6 +134,88 @@ export const useLoadRecordIndexStates = () => { .map(mapViewFieldToRecordField) .filter(isDefined); + const recordIndexId = getRecordIndexIdFromObjectNamePluralAndViewId( + objectMetadataItem.namePlural, + view.id, + ); + + const currentRecordFieldsAtom = + currentRecordFieldsComponentState.atomFamily({ + instanceId: recordIndexId, + }); + + const hasInitializedFieldsAtom = + hasInitializedCurrentRecordFieldsComponentFamilyState.atomFamily({ + instanceId: recordIndexId, + familyKey: { viewId: view.id }, + }); + + store.set( + atom(null, (get, batchSet) => { + if (!skipGlobalIndexStates) { + const existingFieldDefs = get( + recordIndexFieldDefinitionsState.atom, + ); + + if (!isDeeplyEqual(existingFieldDefs, newFieldDefinitions)) { + batchSet( + recordIndexFieldDefinitionsState.atom, + newFieldDefinitions, + ); + } + } + + for (const viewField of view.viewFields) { + const viewFieldMetadataType = objectMetadataItem.fields?.find( + (field) => field.id === viewField.fieldMetadataId, + )?.type; + + const existingAggregateOp = get( + viewFieldAggregateOperationState.atomFamily({ + viewFieldId: viewField.id, + }), + ); + + const convertedViewFieldAggregateOp = isDefined( + viewField.aggregateOperation, + ) + ? convertAggregateOperationToExtendedAggregateOperation( + viewField.aggregateOperation, + viewFieldMetadataType, + ) + : viewField.aggregateOperation; + + if (existingAggregateOp !== convertedViewFieldAggregateOp) { + batchSet( + viewFieldAggregateOperationState.atomFamily({ + viewFieldId: viewField.id, + }), + convertedViewFieldAggregateOp, + ); + } + } + + const existingRecordFields = get(currentRecordFieldsAtom); + + if (!isDeeplyEqual(existingRecordFields, recordFields)) { + batchSet(currentRecordFieldsAtom, recordFields); + } + + batchSet(hasInitializedFieldsAtom, true); + }), + ); + }, + [store], + ); + + const loadRecordIndexStates = useCallback( + ( + view: View, + objectMetadataItem: EnrichedObjectMetadataItem, + options?: { skipGlobalIndexStates?: boolean }, + ) => { + const skipGlobalIndexStates = options?.skipGlobalIndexStates ?? false; + const flattenedFieldMetadataItems = store.get( flattenedFieldMetadataItemsSelector.atom, ); @@ -178,10 +260,6 @@ export const useLoadRecordIndexStates = () => { view.id, ); - const currentRecordFieldsAtom = - currentRecordFieldsComponentState.atomFamily({ - instanceId: recordIndexId, - }); const currentRecordFiltersAtom = currentRecordFiltersComponentState.atomFamily({ instanceId: recordIndexId, @@ -195,11 +273,6 @@ export const useLoadRecordIndexStates = () => { instanceId: recordIndexId, }); - const hasInitializedFieldsAtom = - hasInitializedCurrentRecordFieldsComponentFamilyState.atomFamily({ - instanceId: recordIndexId, - familyKey: { viewId: view.id }, - }); const hasInitializedFiltersAtom = hasInitializedCurrentRecordFiltersComponentFamilyState.atomFamily({ instanceId: recordIndexId, @@ -211,53 +284,12 @@ export const useLoadRecordIndexStates = () => { familyKey: { viewId: view.id }, }); + syncRecordIndexViewFields(view, objectMetadataItem, { + skipGlobalIndexStates, + }); + store.set( atom(null, (get, batchSet) => { - if (!skipGlobalIndexStates) { - const existingFieldDefs = get( - recordIndexFieldDefinitionsState.atom, - ); - if (!isDeeplyEqual(existingFieldDefs, newFieldDefinitions)) { - batchSet( - recordIndexFieldDefinitionsState.atom, - newFieldDefinitions, - ); - } - } - - for (const viewField of view.viewFields) { - const viewFieldMetadataType = objectMetadataItem.fields?.find( - (field) => field.id === viewField.fieldMetadataId, - )?.type; - - const existingAggregateOp = get( - viewFieldAggregateOperationState.atomFamily({ - viewFieldId: viewField.id, - }), - ); - - const convertedViewFieldAggregateOp = isDefined( - viewField.aggregateOperation, - ) - ? convertAggregateOperationToExtendedAggregateOperation( - viewField.aggregateOperation, - viewFieldMetadataType, - ) - : viewField.aggregateOperation; - - if (existingAggregateOp !== convertedViewFieldAggregateOp) { - batchSet( - viewFieldAggregateOperationState.atomFamily({ - viewFieldId: viewField.id, - }), - convertedViewFieldAggregateOp, - ); - } - } - - batchSet(currentRecordFieldsAtom, recordFields); - batchSet(hasInitializedFieldsAtom, true); - batchSet(currentRecordFiltersAtom, recordFilters); batchSet(currentRecordFilterGroupsAtom, recordFilterGroups); batchSet(hasInitializedFiltersAtom, true); @@ -325,10 +357,12 @@ export const useLoadRecordIndexStates = () => { recordIndexShouldHideEmptyRecordGroupsAtom, getFieldMetadataItemByIdOrThrow, setRecordGroupsFromViewGroups, + syncRecordIndexViewFields, ], ); return { loadRecordIndexStates, + syncRecordIndexViewFields, }; };