fix: prevent tab synchronization between different records (#17559)

Fixes issue where tabs were synchronized when opening two records of the
same type in show page and side panel.

The root cause was that tab instance IDs were only based on
`pageLayoutId`, causing all records using the same page layout to share
the same tab state.

This change includes the record ID in the tab instance ID, making tabs
unique per record while maintaining backward compatibility for cases
where no record ID is available.

Fixes #17522

---------

Co-authored-by: Eruis <github@eruis.example>
This commit is contained in:
PandaMan
2026-02-13 08:04:07 -05:00
committed by GitHub
parent 83b800a077
commit befbcef824
3 changed files with 40 additions and 7 deletions
@@ -4,8 +4,9 @@ import { PageLayoutRendererContent } from '@/page-layout/components/PageLayoutRe
import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode';
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
import { type PageLayout } from '@/page-layout/types/PageLayout';
import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId';
import { getTabListInstanceIdFromPageLayoutAndRecord } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutAndRecord';
import { isPageLayoutEmpty } from '@/page-layout/utils/isPageLayoutEmpty';
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/contexts/TabListComponentInstanceContext';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
@@ -20,6 +21,8 @@ export const PageLayoutRenderer = ({
const { setIsPageLayoutInEditMode } =
useSetIsPageLayoutInEditMode(pageLayoutId);
const { targetRecordIdentifier, layoutType } = useLayoutRenderingContext();
const onInitialized = (pageLayout: PageLayout) => {
if (isPageLayoutEmpty(pageLayout)) {
setIsPageLayoutInEditMode(true);
@@ -28,6 +31,12 @@ export const PageLayoutRenderer = ({
}
};
const tabListInstanceId = getTabListInstanceIdFromPageLayoutAndRecord({
pageLayoutId,
layoutType,
targetRecordIdentifier,
});
return (
<PageLayoutComponentInstanceContext.Provider
value={{
@@ -36,7 +45,7 @@ export const PageLayoutRenderer = ({
>
<TabListComponentInstanceContext.Provider
value={{
instanceId: getTabListInstanceIdFromPageLayoutId(pageLayoutId),
instanceId: tabListInstanceId,
}}
>
<PageLayoutInitializationQueryEffect
@@ -11,7 +11,7 @@ import { PageLayoutMainContent } from '@/page-layout/PageLayoutMainContent';
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState';
import { getScrollWrapperInstanceIdFromPageLayoutId } from '@/page-layout/utils/getScrollWrapperInstanceIdFromPageLayoutId';
import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId';
import { getTabListInstanceIdFromPageLayoutAndRecord } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutAndRecord';
import { getTabsByDisplayMode } from '@/page-layout/utils/getTabsByDisplayMode';
import { getTabsWithVisibleWidgets } from '@/page-layout/utils/getTabsWithVisibleWidgets';
import { shouldEnableTabEditingFeatures } from '@/page-layout/utils/shouldEnableTabEditingFeatures';
@@ -52,7 +52,8 @@ const StyledScrollWrapper = styled(ScrollWrapper)`
export const PageLayoutRendererContent = () => {
const { currentPageLayout } = useCurrentPageLayout();
const { isInRightDrawer } = useLayoutRenderingContext();
const { isInRightDrawer, layoutType, targetRecordIdentifier } =
useLayoutRenderingContext();
const isPageLayoutInEditMode = useRecoilComponentValue(
isPageLayoutInEditModeComponentState,
@@ -104,9 +105,11 @@ export const PageLayoutRendererContent = () => {
isInRightDrawer,
});
const tabListInstanceId = getTabListInstanceIdFromPageLayoutId(
currentPageLayout.id,
);
const tabListInstanceId = getTabListInstanceIdFromPageLayoutAndRecord({
pageLayoutId: currentPageLayout.id,
layoutType,
targetRecordIdentifier,
});
const sortedTabs = sortTabsByPosition(tabsToRenderInTabList);
@@ -0,0 +1,21 @@
import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier';
import { type LayoutRenderingContextType } from '@/ui/layout/contexts/LayoutRenderingContext';
import { getTabListInstanceIdFromPageLayoutId } from './getTabListInstanceIdFromPageLayoutId';
import { isDefined } from 'twenty-shared/utils';
export const getTabListInstanceIdFromPageLayoutAndRecord = ({
pageLayoutId,
layoutType,
targetRecordIdentifier,
}: {
pageLayoutId: string;
layoutType: LayoutRenderingContextType['layoutType'];
targetRecordIdentifier?: TargetRecordIdentifier;
}) => {
// Include record ID in tab instance ID to prevent tab synchronization between different records
// Only for RECORD_PAGE layouts, as DASHBOARD layouts are standalone
const recordId =
layoutType === 'RECORD_PAGE' ? targetRecordIdentifier?.id : undefined;
const baseInstanceId = getTabListInstanceIdFromPageLayoutId(pageLayoutId);
return isDefined(recordId) ? `${baseInstanceId}-${recordId}` : baseInstanceId;
};