[Breaking change] fix: make pageLayout type field required (#22450)
fixes https://github.com/twentyhq/twenty/issues/22251 **Summary** - Fixes #22251 — NavigationMenuItem with type PAGE_LAYOUT returns 404 "Off track" for custom standalone pages - Makes type a required field in PageLayoutManifest instead of relying on a fallback default to RECORD_PAGE - Adds PageLayoutType enum to twenty-shared and exports it from the SDK for app developers - Adds build-time validation in definePageLayout to reject manifests missing type - Updates the CLI add command to prompt users to select a page layout type interactively **Root cause** When definePageLayout was called without type, the manifest converter defaulted to RECORD_PAGE. The frontend route guard at /page/:id then rejected it (only STANDALONE_PAGE is allowed), producing a 404. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22450?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
+21
-3
@@ -5,11 +5,12 @@ describe('fromPageLayoutManifestToUniversalFlatPageLayout', () => {
|
||||
const now = '2026-01-01T00:00:00.000Z';
|
||||
const applicationUniversalIdentifier = 'app-uuid-1';
|
||||
|
||||
it('should convert a minimal page layout manifest', () => {
|
||||
it('should convert a standalone page layout manifest', () => {
|
||||
const result = fromPageLayoutManifestToUniversalFlatPageLayout({
|
||||
pageLayoutManifest: {
|
||||
universalIdentifier: 'pl-uuid-1',
|
||||
name: 'My Page Layout',
|
||||
type: PageLayoutType.STANDALONE_PAGE,
|
||||
},
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
@@ -20,7 +21,7 @@ describe('fromPageLayoutManifestToUniversalFlatPageLayout', () => {
|
||||
applicationUniversalIdentifier,
|
||||
);
|
||||
expect(result.name).toBe('My Page Layout');
|
||||
expect(result.type).toBe(PageLayoutType.RECORD_PAGE);
|
||||
expect(result.type).toBe(PageLayoutType.STANDALONE_PAGE);
|
||||
expect(result.objectMetadataUniversalIdentifier).toBeNull();
|
||||
expect(
|
||||
result.defaultTabToFocusOnMobileAndSidePanelUniversalIdentifier,
|
||||
@@ -28,10 +29,27 @@ describe('fromPageLayoutManifestToUniversalFlatPageLayout', () => {
|
||||
expect(result.tabUniversalIdentifiers).toEqual([]);
|
||||
});
|
||||
|
||||
it('should convert a fully specified page layout manifest', () => {
|
||||
it('should convert a record page layout manifest', () => {
|
||||
const result = fromPageLayoutManifestToUniversalFlatPageLayout({
|
||||
pageLayoutManifest: {
|
||||
universalIdentifier: 'pl-uuid-2',
|
||||
name: 'Record Layout',
|
||||
type: PageLayoutType.RECORD_PAGE,
|
||||
objectUniversalIdentifier: 'obj-uuid-1',
|
||||
},
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
});
|
||||
|
||||
expect(result.name).toBe('Record Layout');
|
||||
expect(result.type).toBe(PageLayoutType.RECORD_PAGE);
|
||||
expect(result.objectMetadataUniversalIdentifier).toBe('obj-uuid-1');
|
||||
});
|
||||
|
||||
it('should convert a fully specified page layout manifest', () => {
|
||||
const result = fromPageLayoutManifestToUniversalFlatPageLayout({
|
||||
pageLayoutManifest: {
|
||||
universalIdentifier: 'pl-uuid-3',
|
||||
name: 'Dashboard Layout',
|
||||
type: PageLayoutType.DASHBOARD,
|
||||
objectUniversalIdentifier: 'obj-uuid-1',
|
||||
|
||||
+2
-3
@@ -1,6 +1,6 @@
|
||||
import { type PageLayoutManifest } from 'twenty-shared/application';
|
||||
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { type PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { type UniversalFlatPageLayout } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-page-layout.type';
|
||||
|
||||
export const fromPageLayoutManifestToUniversalFlatPageLayout = ({
|
||||
@@ -16,8 +16,7 @@ export const fromPageLayoutManifestToUniversalFlatPageLayout = ({
|
||||
universalIdentifier: pageLayoutManifest.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
name: pageLayoutManifest.name,
|
||||
type:
|
||||
(pageLayoutManifest.type as PageLayoutType) ?? PageLayoutType.RECORD_PAGE,
|
||||
type: pageLayoutManifest.type as PageLayoutType,
|
||||
objectMetadataUniversalIdentifier:
|
||||
pageLayoutManifest.objectUniversalIdentifier ?? null,
|
||||
defaultTabToFocusOnMobileAndSidePanelUniversalIdentifier:
|
||||
|
||||
Reference in New Issue
Block a user