diff --git a/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabLayoutMode.test.ts b/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabLayoutMode.test.ts new file mode 100644 index 0000000000..5e1fd165e4 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/utils/__tests__/getTabLayoutMode.test.ts @@ -0,0 +1,46 @@ +import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab'; +import { getTabLayoutMode } from '@/page-layout/utils/getTabLayoutMode'; +import { + PageLayoutTabLayoutMode, + PageLayoutType, +} from '~/generated-metadata/graphql'; + +const buildTab = (layoutMode: PageLayoutTabLayoutMode) => + ({ layoutMode }) as unknown as PageLayoutTab; + +describe('getTabLayoutMode', () => { + describe('page types that respect tab.layoutMode', () => { + it.each([PageLayoutType.RECORD_PAGE, PageLayoutType.STANDALONE_PAGE])( + "returns the tab's layoutMode for %s", + (pageLayoutType) => { + const tab = buildTab(PageLayoutTabLayoutMode.CANVAS); + + expect(getTabLayoutMode({ tab, pageLayoutType })).toBe( + PageLayoutTabLayoutMode.CANVAS, + ); + }, + ); + + it.each([PageLayoutType.RECORD_PAGE, PageLayoutType.STANDALONE_PAGE])( + 'throws when tab is undefined for %s', + (pageLayoutType) => { + expect(() => + getTabLayoutMode({ tab: undefined, pageLayoutType }), + ).toThrow('Tab layout mode is not defined'); + }, + ); + }); + + describe('page types that ignore tab.layoutMode and default to GRID', () => { + it.each([PageLayoutType.DASHBOARD, PageLayoutType.RECORD_INDEX])( + 'returns GRID for %s regardless of tab.layoutMode', + (pageLayoutType) => { + const tab = buildTab(PageLayoutTabLayoutMode.CANVAS); + + expect(getTabLayoutMode({ tab, pageLayoutType })).toBe( + PageLayoutTabLayoutMode.GRID, + ); + }, + ); + }); +}); diff --git a/packages/twenty-front/src/modules/page-layout/utils/getTabLayoutMode.ts b/packages/twenty-front/src/modules/page-layout/utils/getTabLayoutMode.ts index ac2cb38cde..6a7397a18d 100644 --- a/packages/twenty-front/src/modules/page-layout/utils/getTabLayoutMode.ts +++ b/packages/twenty-front/src/modules/page-layout/utils/getTabLayoutMode.ts @@ -14,7 +14,10 @@ export const getTabLayoutMode = ({ tab, pageLayoutType, }: GetTabLayoutModeParams): PageLayoutTabLayoutMode => { - if (pageLayoutType === PageLayoutType.RECORD_PAGE) { + if ( + pageLayoutType === PageLayoutType.RECORD_PAGE || + pageLayoutType === PageLayoutType.STANDALONE_PAGE + ) { assertPageLayoutTabHasDefinedLayoutModeOrThrow(tab); return tab.layoutMode; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx index 5841d8f3a4..664db2ccbb 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/front-component/components/FrontComponentWidgetRenderer.tsx @@ -3,15 +3,20 @@ import { Suspense, lazy } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { usePageLayoutContentContext } from '@/page-layout/contexts/PageLayoutContentContext'; import { useIsPageLayoutInEditMode } from '@/page-layout/hooks/useIsPageLayoutInEditMode'; import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay'; import { isWidgetConfigurationOfType } from '@/side-panel/pages/page-layout/utils/isWidgetConfigurationOfType'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; +import { PageLayoutTabLayoutMode } from '~/generated-metadata/graphql'; -const StyledContainer = styled.div<{ isInEditMode: boolean }>` +const StyledContainer = styled.div<{ + isCanvasLayout: boolean; + isInEditMode: boolean; +}>` height: 100%; - overflow: auto; + overflow: ${({ isCanvasLayout }) => (isCanvasLayout ? 'visible' : 'auto')}; pointer-events: ${({ isInEditMode }) => (isInEditMode ? 'none' : 'auto')}; width: 100%; `; @@ -30,6 +35,7 @@ export const FrontComponentWidgetRenderer = ({ widget, }: FrontComponentWidgetRendererProps) => { const isPageLayoutInEditMode = useIsPageLayoutInEditMode(); + const { layoutMode } = usePageLayoutContentContext(); const { targetRecordIdentifier } = useLayoutRenderingContext(); const configuration = widget.configuration; @@ -47,7 +53,10 @@ export const FrontComponentWidgetRenderer = ({ : undefined; return ( - + { - it('should return dashboard for DASHBOARD page layout type', () => { - expect( - getWidgetCardVariant({ - layoutMode: PageLayoutTabLayoutMode.GRID, - isInPinnedTab: false, - pageLayoutType: PageLayoutType.DASHBOARD, - isMobile: false, - isInSidePanel: false, - }), - ).toBe('dashboard'); + describe('when layoutMode is CANVAS', () => { + it.each([ + PageLayoutType.RECORD_PAGE, + PageLayoutType.STANDALONE_PAGE, + PageLayoutType.DASHBOARD, + PageLayoutType.RECORD_INDEX, + ])( + "returns 'canvas' regardless of pageLayoutType (%s)", + (pageLayoutType) => { + expect( + getWidgetCardVariant({ + ...baseParams, + layoutMode: PageLayoutTabLayoutMode.CANVAS, + pageLayoutType, + }), + ).toBe('canvas'); + }, + ); }); - it('should return standalone for STANDALONE_PAGE page layout type', () => { - expect( - getWidgetCardVariant({ - layoutMode: PageLayoutTabLayoutMode.GRID, - isInPinnedTab: false, - pageLayoutType: PageLayoutType.STANDALONE_PAGE, - isMobile: false, - isInSidePanel: false, - }), - ).toBe('standalone'); + describe('when layoutMode is GRID', () => { + it("returns 'dashboard' for DASHBOARD page", () => { + expect( + getWidgetCardVariant({ + ...baseParams, + layoutMode: PageLayoutTabLayoutMode.GRID, + pageLayoutType: PageLayoutType.DASHBOARD, + }), + ).toBe('dashboard'); + }); + + it("returns 'standalone' for STANDALONE_PAGE", () => { + expect( + getWidgetCardVariant({ + ...baseParams, + layoutMode: PageLayoutTabLayoutMode.GRID, + pageLayoutType: PageLayoutType.STANDALONE_PAGE, + }), + ).toBe('standalone'); + }); + + it("returns 'record-page' for RECORD_PAGE by default", () => { + expect( + getWidgetCardVariant({ + ...baseParams, + layoutMode: PageLayoutTabLayoutMode.GRID, + pageLayoutType: PageLayoutType.RECORD_PAGE, + }), + ).toBe('record-page'); + }); }); - it('should prioritize standalone over canvas', () => { - expect( - getWidgetCardVariant({ - layoutMode: PageLayoutTabLayoutMode.CANVAS, - isInPinnedTab: false, - pageLayoutType: PageLayoutType.STANDALONE_PAGE, - isMobile: false, - isInSidePanel: false, - }), - ).toBe('standalone'); - }); - - it('should return canvas for CANVAS layout mode', () => { - expect( - getWidgetCardVariant({ - layoutMode: PageLayoutTabLayoutMode.CANVAS, - isInPinnedTab: false, - pageLayoutType: PageLayoutType.RECORD_PAGE, - isMobile: false, - isInSidePanel: false, - }), - ).toBe('canvas'); - }); - - it('should return side-column when isInPinnedTab is true', () => { - expect( - getWidgetCardVariant({ - layoutMode: PageLayoutTabLayoutMode.GRID, - isInPinnedTab: true, - pageLayoutType: PageLayoutType.RECORD_PAGE, - isMobile: false, - isInSidePanel: false, - }), - ).toBe('side-column'); - }); - - it('should return side-column when isMobile is true', () => { - expect( - getWidgetCardVariant({ - layoutMode: PageLayoutTabLayoutMode.GRID, - isInPinnedTab: false, - pageLayoutType: PageLayoutType.RECORD_PAGE, - isMobile: true, - isInSidePanel: false, - }), - ).toBe('side-column'); - }); - - it('should return side-column when isInSidePanel is true', () => { - expect( - getWidgetCardVariant({ - layoutMode: PageLayoutTabLayoutMode.GRID, - isInPinnedTab: false, - pageLayoutType: PageLayoutType.RECORD_PAGE, - isMobile: false, - isInSidePanel: true, - }), - ).toBe('side-column'); - }); - - it('should return record-page as default', () => { - expect( - getWidgetCardVariant({ - layoutMode: PageLayoutTabLayoutMode.GRID, - isInPinnedTab: false, - pageLayoutType: PageLayoutType.RECORD_PAGE, - isMobile: false, - isInSidePanel: false, - }), - ).toBe('record-page'); - }); - - it('should prioritize dashboard over canvas', () => { - expect( - getWidgetCardVariant({ - layoutMode: PageLayoutTabLayoutMode.CANVAS, - isInPinnedTab: false, - pageLayoutType: PageLayoutType.DASHBOARD, - isMobile: false, - isInSidePanel: false, - }), - ).toBe('dashboard'); + describe('side-column context for record pages', () => { + it.each([ + ['isInPinnedTab', { isInPinnedTab: true }], + ['isMobile', { isMobile: true }], + ['isInSidePanel', { isInSidePanel: true }], + ])("returns 'side-column' when %s is true", (_label, override) => { + expect( + getWidgetCardVariant({ + ...baseParams, + ...override, + layoutMode: PageLayoutTabLayoutMode.GRID, + pageLayoutType: PageLayoutType.RECORD_PAGE, + }), + ).toBe('side-column'); + }); }); }); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/utils/getWidgetCardVariant.ts b/packages/twenty-front/src/modules/page-layout/widgets/utils/getWidgetCardVariant.ts index 7d909bcc94..a91dc591ab 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/utils/getWidgetCardVariant.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/utils/getWidgetCardVariant.ts @@ -19,21 +19,20 @@ export const getWidgetCardVariant = ({ isMobile, isInSidePanel, }: GetWidgetCardVariantParams): WidgetCardVariant => { - if (pageLayoutType === PageLayoutType.DASHBOARD) { - return 'dashboard'; - } - - if (pageLayoutType === PageLayoutType.STANDALONE_PAGE) { - return 'standalone'; - } - if (layoutMode === PageLayoutTabLayoutMode.CANVAS) { return 'canvas'; } - if (isInPinnedTab || isMobile || isInSidePanel) { - return 'side-column'; - } + const isSideColumnContext = isInPinnedTab || isMobile || isInSidePanel; - return 'record-page'; + switch (pageLayoutType) { + case PageLayoutType.DASHBOARD: + return 'dashboard'; + case PageLayoutType.STANDALONE_PAGE: + return 'standalone'; + case PageLayoutType.RECORD_PAGE: + case PageLayoutType.RECORD_INDEX: + case null: + return isSideColumnContext ? 'side-column' : 'record-page'; + } };