From 28763428f6708347bc280a0cb7775433f9d816b8 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:28:51 +0000 Subject: [PATCH] Differentiate edit mode behavior for record pages vs dashboards (#17550) Temporary disable tabs edition for record page layouts https://github.com/user-attachments/assets/c1f5d7fd-f125-4fb0-bf9c-96fadec14cd2 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Devessier <29370468+Devessier@users.noreply.github.com> Co-authored-by: Baptiste Devessier --- .../components/PageLayoutRendererContent.tsx | 34 ++++++++++------- .../components/PageLayoutTabList.tsx | 27 +++++++++++-- ...youtTabListReorderableOverflowDropdown.tsx | 9 ++++- .../__stories__/PageLayoutTabList.stories.tsx | 2 + .../shouldEnableTabEditingFeatures.test.ts | 38 +++++++++++++++++++ .../utils/shouldEnableTabEditingFeatures.ts | 7 ++++ 6 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 packages/twenty-front/src/modules/page-layout/utils/__tests__/shouldEnableTabEditingFeatures.test.ts create mode 100644 packages/twenty-front/src/modules/page-layout/utils/shouldEnableTabEditingFeatures.ts diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx index 16894efd4c..0b8023595f 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx @@ -14,6 +14,7 @@ import { getScrollWrapperInstanceIdFromPageLayoutId } from '@/page-layout/utils/ import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId'; import { getTabsByDisplayMode } from '@/page-layout/utils/getTabsByDisplayMode'; import { getTabsWithVisibleWidgets } from '@/page-layout/utils/getTabsWithVisibleWidgets'; +import { shouldEnableTabEditingFeatures } from '@/page-layout/utils/shouldEnableTabEditingFeatures'; import { sortTabsByPosition } from '@/page-layout/utils/sortTabsByPosition'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; @@ -66,23 +67,29 @@ export const PageLayoutRendererContent = () => { ); const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu(); - const handleAddTab = isPageLayoutInEditMode - ? () => { - const newTabId = createPageLayoutTab(t`Untitled`); - setTabSettingsOpenTabId(newTabId); - navigatePageLayoutCommandMenu({ - commandMenuPage: CommandMenuPages.PageLayoutTabSettings, - focusTitleInput: true, - }); - } - : undefined; - const isMobile = useIsMobile(); if (!isDefined(currentPageLayout)) { return null; } + const handleAddTab = + isPageLayoutInEditMode && + shouldEnableTabEditingFeatures(currentPageLayout.type) + ? () => { + const newTabId = createPageLayoutTab(t`Untitled`); + setTabSettingsOpenTabId(newTabId); + navigatePageLayoutCommandMenu({ + commandMenuPage: CommandMenuPages.PageLayoutTabSettings, + focusTitleInput: true, + }); + } + : undefined; + + const canEnableTabEditing = + isPageLayoutInEditMode && + shouldEnableTabEditingFeatures(currentPageLayout.type); + const tabsWithVisibleWidgets = getTabsWithVisibleWidgets({ tabs: currentPageLayout.tabs, isMobile, @@ -123,8 +130,9 @@ export const PageLayoutRendererContent = () => { behaveAsLinks={!isInRightDrawer && !isPageLayoutInEditMode} componentInstanceId={tabListInstanceId} onAddTab={handleAddTab} - isReorderEnabled={isPageLayoutInEditMode} - onReorder={isPageLayoutInEditMode ? reorderTabs : undefined} + isReorderEnabled={canEnableTabEditing} + onReorder={canEnableTabEditing ? reorderTabs : undefined} + pageLayoutType={currentPageLayout.type} /> )} diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx index 9891927696..4c7b80092e 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx @@ -37,11 +37,13 @@ import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPag import { pageLayoutTabListCurrentDragDroppableIdComponentState } from '@/page-layout/states/pageLayoutTabListCurrentDragDroppableIdComponentState'; import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState'; import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab'; +import { shouldEnableTabEditingFeatures } from '@/page-layout/utils/shouldEnableTabEditingFeatures'; import { TabListFromUrlOptionalEffect } from '@/ui/layout/tab-list/components/TabListFromUrlOptionalEffect'; import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { isDefined } from 'twenty-shared/utils'; +import { type PageLayoutType } from '~/generated/graphql'; const StyledContainer = styled.div` box-sizing: border-box; @@ -75,6 +77,7 @@ type PageLayoutTabListProps = Omit & { onAddTab?: () => void; onReorder?: (result: DropResult, provided: ResponderProvided) => boolean; behaveAsLinks: boolean; + pageLayoutType: PageLayoutType; }; export const PageLayoutTabList = ({ @@ -88,6 +91,7 @@ export const PageLayoutTabList = ({ onAddTab, isReorderEnabled, onReorder, + pageLayoutType, }: PageLayoutTabListProps) => { const { getIcon } = useIcons(); @@ -229,17 +233,24 @@ export const PageLayoutTabList = ({ const handleSelectTab = useCallback( (tabId: string) => { - if (isPageLayoutInEditMode && activeTabId === tabId) { + const shouldOpenSettings = + isPageLayoutInEditMode && + shouldEnableTabEditingFeatures(pageLayoutType); + + if (shouldOpenSettings && activeTabId === tabId) { openTabSettings(tabId); return; } - if (isPageLayoutInEditMode && isTabSettingsOpen) { + + if (shouldOpenSettings && isTabSettingsOpen) { openTabSettings(tabId); } + selectTab(tabId); }, [ isPageLayoutInEditMode, + pageLayoutType, activeTabId, isTabSettingsOpen, openTabSettings, @@ -249,18 +260,25 @@ export const PageLayoutTabList = ({ const handleSelectTabFromDropdown = useCallback( (tabId: string) => { - if (isPageLayoutInEditMode && activeTabId === tabId) { + const shouldOpenSettings = + isPageLayoutInEditMode && + shouldEnableTabEditingFeatures(pageLayoutType); + + if (shouldOpenSettings && activeTabId === tabId) { openTabSettings(tabId); closeOverflowDropdown(); return; } - if (isPageLayoutInEditMode && isTabSettingsOpen) { + + if (shouldOpenSettings && isTabSettingsOpen) { openTabSettings(tabId); } + selectTabFromDropdown(tabId); }, [ isPageLayoutInEditMode, + pageLayoutType, activeTabId, isTabSettingsOpen, openTabSettings, @@ -336,6 +354,7 @@ export const PageLayoutTabList = ({ onSelect={handleSelectTabFromDropdown} visibleTabCount={visibleTabCount} onClose={closeOverflowDropdown} + pageLayoutType={pageLayoutType} /> )} diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx index f68ef93a5f..8a0a7f5580 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx @@ -18,6 +18,7 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/context import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { isPageLayoutTabDraggingComponentState } from '@/page-layout/states/isPageLayoutTabDraggingComponentState'; import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState'; +import { shouldEnableTabEditingFeatures } from '@/page-layout/utils/shouldEnableTabEditingFeatures'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -28,6 +29,7 @@ import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/com import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { useContext } from 'react'; +import { type PageLayoutType } from '~/generated/graphql'; const StyledOverflowDropdownListDraggableWrapper = styled.div` display: flex; @@ -48,6 +50,7 @@ type PageLayoutTabListReorderableOverflowDropdownProps = { onSelect: (tabId: string) => void; visibleTabCount: number; onClose: () => void; + pageLayoutType: PageLayoutType; }; export const PageLayoutTabListReorderableOverflowDropdown = ({ @@ -60,6 +63,7 @@ export const PageLayoutTabListReorderableOverflowDropdown = ({ onSelect, visibleTabCount, onClose, + pageLayoutType, }: PageLayoutTabListReorderableOverflowDropdownProps) => { const theme = useTheme(); const context = useContext(TabListComponentInstanceContext); @@ -74,6 +78,9 @@ export const PageLayoutTabListReorderableOverflowDropdown = ({ pageLayoutId, ); + const shouldShowEditButton = + isPageLayoutInEditMode && shouldEnableTabEditingFeatures(pageLayoutType); + const isTabDragging = useRecoilComponentValue( isPageLayoutTabDraggingComponentState, instanceId, @@ -201,7 +208,7 @@ export const PageLayoutTabListReorderableOverflowDropdown = ({ : () => handleTabSelect(tab.id) } disabled={disabled} - showEditButton={isPageLayoutInEditMode} + showEditButton={shouldShowEditButton} onEditClick={handleEditClick} /> diff --git a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx index 519ed4dd7e..47d7a057fd 100644 --- a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx @@ -11,6 +11,7 @@ import { PageLayoutTabListEffect } from '@/page-layout/components/PageLayoutTabL import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab'; import { calculateNewPosition } from '@/ui/layout/draggable-list/utils/calculateNewPosition'; +import { PageLayoutType } from '~/generated/graphql'; const StyledContainer = styled.div` border: 1px solid ${({ theme }) => theme.border.color.strong}; @@ -163,6 +164,7 @@ const PageLayoutTabListPlayground = ({ onAddTab={isReorderEnabled ? handleAddTab : undefined} isReorderEnabled={isReorderEnabled} onReorder={isReorderEnabled ? handleReorder : undefined} + pageLayoutType={PageLayoutType.DASHBOARD} /> ); diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/shouldEnableTabEditingFeatures.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/shouldEnableTabEditingFeatures.test.ts new file mode 100644 index 0000000000..f384fe256f --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/shouldEnableTabEditingFeatures.test.ts @@ -0,0 +1,38 @@ +import { shouldEnableTabEditingFeatures } from '@/page-layout/utils/shouldEnableTabEditingFeatures'; +import { PageLayoutType } from '~/generated/graphql'; + +describe('shouldEnableTabEditingFeatures', () => { + it('should return true for DASHBOARD layout type', () => { + const result = shouldEnableTabEditingFeatures(PageLayoutType.DASHBOARD); + expect(result).toBe(true); + }); + + it('should return false for RECORD_PAGE layout type', () => { + const result = shouldEnableTabEditingFeatures(PageLayoutType.RECORD_PAGE); + expect(result).toBe(false); + }); + + it('should return false for RECORD_INDEX layout type', () => { + const result = shouldEnableTabEditingFeatures(PageLayoutType.RECORD_INDEX); + expect(result).toBe(false); + }); + + describe('behavior validation', () => { + it('should enable tab editing features only for dashboards', () => { + // Dashboards should allow adding tabs and opening settings on click + expect(shouldEnableTabEditingFeatures(PageLayoutType.DASHBOARD)).toBe( + true, + ); + + // Record pages should NOT allow adding tabs or opening settings on click + expect(shouldEnableTabEditingFeatures(PageLayoutType.RECORD_PAGE)).toBe( + false, + ); + + // Record index pages should NOT allow adding tabs or opening settings on click + expect(shouldEnableTabEditingFeatures(PageLayoutType.RECORD_INDEX)).toBe( + false, + ); + }); + }); +}); diff --git a/packages/twenty-front/src/modules/page-layout/utils/shouldEnableTabEditingFeatures.ts b/packages/twenty-front/src/modules/page-layout/utils/shouldEnableTabEditingFeatures.ts new file mode 100644 index 0000000000..54c74723c6 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/utils/shouldEnableTabEditingFeatures.ts @@ -0,0 +1,7 @@ +import { PageLayoutType } from '~/generated/graphql'; + +export const shouldEnableTabEditingFeatures = ( + pageLayoutType: PageLayoutType, +): boolean => { + return pageLayoutType === PageLayoutType.DASHBOARD; +};