From 706d72e53e2ab196a57ab9d25b8cca03fc637d3d Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Fri, 31 Jul 2026 15:32:13 +0200 Subject: [PATCH] fix(front): reload record board groups when view groups change (#23637) ## Problem Fixes #23462 On a Kanban (record board) view grouped by a SELECT field, adding a new option to that field creates the column, but dragging a record into the new column silently fails (no move, no error) until a hard page reload. ## Root cause `RecordIndexLoadBaseOnContextStoreEffect` builds its load key from the view id and the calendar-week flag only: ``` `${contextStoreCurrentViewId}-${isCalendarWeekViewEnabled}` ``` The effect early-returns when `loadedViewKey === currentViewLoadKey`. When a new `ViewGroup` is created from the added SELECT option, the view id does not change, so the key is unchanged and `loadRecordIndexStates` never re-runs. The record group state (`recordGroupIdsComponentState` / `recordGroupDefinitionFamilyState`) stays stale, so the drop handler cannot resolve the new group's field value and the move no-ops. A hard reload fixes it because the view then loads with the new group present from the start. ## Fix Include a signature of `view.viewGroups` (ordered `id:position:isVisible`) in the load key so the effect re-runs `loadRecordIndexStates` whenever the view's groups change, not only when the view id changes. The calendar-week flag is kept in the key. ## Testing Verified end to end on a local instance against an Opportunities "By Stage" Kanban, with the record's stage change confirmed in the database: - **Before the fix:** add a new Stage option in-session, then drag a record into the new column. Dragging into an existing column persists the move; dragging into the newly created column does nothing (record's stage unchanged in DB). - **After the fix:** same flow, dragging a record into the newly created column moves it and persists the new stage in DB, with no reload. `nx typecheck twenty-front` and `oxlint` pass. Review in cubic --- ...ecordIndexLoadBaseOnContextStoreEffect.tsx | 13 ++++-- ...IndexLoadBaseOnContextStoreEffect.test.tsx | 43 +++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect.tsx index e00623fba2..10370b59e1 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect.tsx @@ -18,16 +18,21 @@ export const RecordIndexLoadBaseOnContextStoreEffect = () => { FeatureFlagKey.IS_CALENDAR_WEEK_VIEW_ENABLED, ); - const currentViewLoadKey = isDefined(contextStoreCurrentViewId) - ? `${contextStoreCurrentViewId}-${isCalendarWeekViewEnabled}` - : undefined; - const [loadedViewKey, setLoadedViewKey] = useState(); const view = useAtomFamilySelectorValue(viewFromViewIdFamilySelector, { viewId: contextStoreCurrentViewId ?? '', }); + const viewGroupsSignature = (view?.viewGroups ?? []) + .map((viewGroup) => viewGroup.id) + .sort() + .join(','); + + const currentViewLoadKey = isDefined(contextStoreCurrentViewId) + ? `${contextStoreCurrentViewId}-${isCalendarWeekViewEnabled}-${viewGroupsSignature}` + : undefined; + const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); useEffect(() => { diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/__tests__/RecordIndexLoadBaseOnContextStoreEffect.test.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/__tests__/RecordIndexLoadBaseOnContextStoreEffect.test.tsx index a9f23e882d..05126a1b58 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/__tests__/RecordIndexLoadBaseOnContextStoreEffect.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/__tests__/RecordIndexLoadBaseOnContextStoreEffect.test.tsx @@ -84,4 +84,47 @@ describe('RecordIndexLoadBaseOnContextStoreEffect', () => { FeatureFlagKey.IS_CALENDAR_WEEK_VIEW_ENABLED, ); }); + + it('reloads the persisted view state when the view groups change', () => { + const viewWithGroups = { + id: 'view-id', + viewGroups: [{ id: 'group-1' }], + }; + useAtomFamilySelectorValueMock.mockReturnValue(viewWithGroups); + + const { rerender } = render(); + + expect(loadRecordIndexStates).toHaveBeenCalledTimes(1); + + rerender(); + + expect(loadRecordIndexStates).toHaveBeenCalledTimes(1); + + useAtomFamilySelectorValueMock.mockReturnValue({ + ...viewWithGroups, + viewGroups: [...viewWithGroups.viewGroups, { id: 'group-2' }], + }); + rerender(); + + expect(loadRecordIndexStates).toHaveBeenCalledTimes(2); + }); + + it('does not reload when the view groups are only reordered', () => { + useAtomFamilySelectorValueMock.mockReturnValue({ + id: 'view-id', + viewGroups: [{ id: 'group-1' }, { id: 'group-2' }], + }); + + const { rerender } = render(); + + expect(loadRecordIndexStates).toHaveBeenCalledTimes(1); + + useAtomFamilySelectorValueMock.mockReturnValue({ + id: 'view-id', + viewGroups: [{ id: 'group-2' }, { id: 'group-1' }], + }); + rerender(); + + expect(loadRecordIndexStates).toHaveBeenCalledTimes(1); + }); });