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,
};
};