From 6d576ebbcd9c0acf7330ccd9308af3f0158204fc Mon Sep 17 00:00:00 2001 From: ehconitin Date: Sun, 17 May 2026 17:12:32 +0530 Subject: [PATCH] fix(twenty-front): preserve kanban scroll on data-driven board re-init --- .../components/RecordBoardDataChangedEffect.tsx | 10 +++++----- .../hooks/useTriggerRecordBoardInitialQuery.ts | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx index fa13327fe26..cafabc12863 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx @@ -57,13 +57,13 @@ export const RecordBoardDataChangedEffect = () => { getShouldInitializeRecordBoardForUpdateInputs(updateInputs); if (shouldInitializeForUpdateOperation) { - triggerRecordBoardInitialQuery(); + triggerRecordBoardInitialQuery({ preserveScroll: true }); } } break; case 'create-one': { if (objectRecordOperation.createdRecord.position === 'first') { - triggerRecordBoardInitialQuery(); + triggerRecordBoardInitialQuery({ preserveScroll: true }); } else { const createdRecordPosition = objectRecordOperation.createdRecord.position; @@ -106,7 +106,7 @@ export const RecordBoardDataChangedEffect = () => { const groupIsEmpty = recordIdsWithoutCreatedRecord.length === 0; if (groupIsEmpty) { - triggerRecordBoardInitialQuery(); + triggerRecordBoardInitialQuery({ preserveScroll: true }); return; } @@ -122,7 +122,7 @@ export const RecordBoardDataChangedEffect = () => { if ( createdRecordPosition < (firstExistingRecordInGroup.position ?? 0) ) { - triggerRecordBoardInitialQuery(); + triggerRecordBoardInitialQuery({ preserveScroll: true }); } } break; @@ -148,7 +148,7 @@ export const RecordBoardDataChangedEffect = () => { return; } default: { - triggerRecordBoardInitialQuery(); + triggerRecordBoardInitialQuery({ preserveScroll: true }); } } }, diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery.ts index 3400c7a04d0..f164c0a9746 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery.ts @@ -75,7 +75,11 @@ export const useTriggerRecordBoardInitialQuery = () => { objectMetadataItem, }); - const triggerRecordBoardInitialQuery = useCallback(async () => { + const triggerRecordBoardInitialQuery = useCallback(async (options?: { + preserveScroll?: boolean; + }) => { + const preserveScroll = options?.preserveScroll === true; + store.set(recordIndexRecordGroupsAreInInitialLoading, true); const cleanStateBeforeExit = () => { @@ -85,7 +89,13 @@ export const useTriggerRecordBoardInitialQuery = () => { setRecordBoardCurrentGroupByQueryOffset(0); - scrollWrapperHTMLElement?.scrollTo({ top: 0, left: 0 }); + // Scroll reset only makes sense when the dataset itself changed + // (filters/sort/group). For data-driven re-init (a single record + // changed via SSE or an own mutation), preserveScroll keeps the user + // where they were. + if (!preserveScroll) { + scrollWrapperHTMLElement?.scrollTo({ top: 0, left: 0 }); + } }; const recordIndexGroupsRecordsGroupByLazyQueryResult =