From 97339f673346b0febdedc90b67595f36b09d2136 Mon Sep 17 00:00:00 2001 From: Sonarly Claude Code Date: Mon, 6 Apr 2026 14:08:51 +0000 Subject: [PATCH] fix: merge page layout tabs from multiple SDK apps on the same object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://sonarly.com/issue/22151?type=bug When multiple SDK apps define page layouts for the same system object, only the first layout's tabs are displayed because the frontend selector uses `.find()` instead of collecting and merging all matching layouts. Fix: Changed `recordPageLayoutByObjectMetadataIdFamilySelector` from using `.find()` (which returns only the first matching layout) to using `.filter()` to collect all page layouts matching the given `objectMetadataId` with type `RECORD_PAGE`. When multiple layouts exist (from different SDK apps), the selector now merges their tabs into a single `PageLayout` object using the first layout as the base. This preserves the return type `PageLayout | undefined` so no consumer changes are needed. The merging strategy: - 0 matches → returns `undefined` (same as before) - 1 match → returns it directly (same as before, no overhead) - 2+ matches → uses first layout as base, concatenates all tabs from all layouts The downstream `PageLayoutTabsRenderer` already sorts tabs by position (`sortTabsByPosition`), so tabs from different apps will be correctly ordered as long as their positions don't conflict. Tab position conflicts would be a separate concern handled at the SDK sync level. --- ...eLayoutByObjectMetadataIdFamilySelector.ts | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector.ts b/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector.ts index 77d414b5f5b..bf1f9bd3057 100644 --- a/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector.ts +++ b/packages/twenty-front/src/modules/page-layout/states/selectors/recordPageLayoutByObjectMetadataIdFamilySelector.ts @@ -14,10 +14,32 @@ export const recordPageLayoutByObjectMetadataIdFamilySelector = ({ get }) => { const pageLayouts = get(pageLayoutsWithRelationsSelector); - return pageLayouts.find( + const matchingLayouts = pageLayouts.filter( (pageLayout) => pageLayout.type === PageLayoutType.RECORD_PAGE && pageLayout.objectMetadataId === objectMetadataId, ); + + if (matchingLayouts.length === 0) { + return undefined; + } + + if (matchingLayouts.length === 1) { + return matchingLayouts[0]; + } + + // Merge tabs from all matching layouts (e.g. multiple SDK apps + // defining page layouts for the same object) into the first layout. + const [baseLayout, ...otherLayouts] = matchingLayouts; + + const mergedTabs = [ + ...baseLayout.tabs, + ...otherLayouts.flatMap((layout) => layout.tabs), + ]; + + return { + ...baseLayout, + tabs: mergedTabs, + }; }, });