From 3ef789dab4abe0cebc2bf419e9fec34d572bc7ca Mon Sep 17 00:00:00 2001 From: Baptiste Devessier Date: Thu, 22 Jan 2026 17:52:56 +0100 Subject: [PATCH] Fix blank page layout after navigation (#17340) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now, it wasn’t possible to navigate between page layouts. Dashboards don’t contain links to other dashboards. With record page layouts, however, a page layout can now contain a link to another page layout. If the user opens a record in the side panel and then clicks a link to another record, the current page layout is replaced with the page layout for the clicked record. In this scenario, the `PageLayoutRenderer` component is not remounted. As a result, the `isInitialized` state was not reset to `false`, and the corresponding initialization `useEffect` was not triggered again. All page layout states are component states bound to `PageLayoutComponentInstanceContext`. For example, after navigating to another record, `pageLayoutPersistedComponentState` was actually `undefined` because the context's `instanceId` had changed. Replacing the `isInitialized` state with a component state fixes the bug and is consistent with the existing pattern of using component states to store everything related to page layouts. ## Before https://github.com/user-attachments/assets/24217145-51e5-49ef-8180-de62a6acfe10 ## After https://github.com/user-attachments/assets/e0ffe107-8fae-4f3a-9016-72c85bc735f4 --- .../PageLayoutInitializationQueryEffect.tsx | 16 +++++++++++++--- .../pageLayoutIsInitializedComponentState.ts | 10 ++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 packages/twenty-front/src/modules/page-layout/states/pageLayoutIsInitializedComponentState.ts diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx index 7fcabedac1..7c07f2302c 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx @@ -20,14 +20,16 @@ import { DEFAULT_WORKFLOW_VERSION_PAGE_LAYOUT_ID } from '@/page-layout/constants import { usePageLayoutWithRelationWidgets } from '@/page-layout/hooks/usePageLayoutWithRelationWidgets'; import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; +import { pageLayoutIsInitializedComponentState } from '@/page-layout/states/pageLayoutIsInitializedComponentState'; import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState'; import { type PageLayout } from '@/page-layout/types/PageLayout'; import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts'; import { transformPageLayout } from '@/page-layout/utils/transformPageLayout'; import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { useQuery } from '@apollo/client'; -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -65,7 +67,9 @@ export const PageLayoutInitializationQueryEffect = ({ pageLayoutId, onInitialized, }: PageLayoutInitializationQueryEffectProps) => { - const [isInitialized, setIsInitialized] = useState(false); + const [isInitialized, setIsInitialized] = useRecoilComponentState( + pageLayoutIsInitializedComponentState, + ); const isDefaultLayout = pageLayoutId === DEFAULT_RECORD_PAGE_LAYOUT_ID || @@ -138,7 +142,13 @@ export const PageLayoutInitializationQueryEffect = ({ onInitialized?.(pageLayout); setIsInitialized(true); } - }, [initializePageLayout, isInitialized, pageLayout, onInitialized]); + }, [ + initializePageLayout, + isInitialized, + pageLayout, + onInitialized, + setIsInitialized, + ]); return null; }; diff --git a/packages/twenty-front/src/modules/page-layout/states/pageLayoutIsInitializedComponentState.ts b/packages/twenty-front/src/modules/page-layout/states/pageLayoutIsInitializedComponentState.ts new file mode 100644 index 0000000000..61db2da1fd --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/states/pageLayoutIsInitializedComponentState.ts @@ -0,0 +1,10 @@ +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext'; + +export const pageLayoutIsInitializedComponentState = + createComponentState({ + key: 'pageLayoutIsInitializedComponentState', + defaultValue: false, + componentInstanceContext: PageLayoutComponentInstanceContext, + });