Type PageLayout manifest type prop with PageLayoutType (#23375)

Closes #23373

`PageLayoutManifest.type` was typed as `string`, so `definePageLayout({
type: 'NOT_A_VALID_PAGE_LAYOUT_TYPE' })` compiled fine.

It is now typed as `` `${PageLayoutType}` ``, which rejects arbitrary
strings while keeping both forms assignable:

```ts
type: PageLayoutType.STANDALONE_PAGE
type: 'STANDALONE_PAGE'
```

A string enum member is assignable to its own literal type, so ``
PageLayoutType | `${PageLayoutType}` `` would have been the same type as
`` `${PageLayoutType}` `` alone. Going the other way (`type:
PageLayoutType` on its own) is strictly narrower and would break every
app manifest in `packages/twenty-apps` plus the `create-twenty-app`
template, which all pass raw strings.
This commit is contained in:
Paul Rastoin
2026-07-27 18:45:10 +02:00
committed by GitHub
parent 24ccdb9b5d
commit 68b26f00ba
2 changed files with 3 additions and 2 deletions
@@ -51,7 +51,7 @@ export default definePageLayout({
### Key points
- `type` is typically `'RECORD_PAGE'` to customize the detail view of a specific object.
- `type` is one of `'RECORD_INDEX'`, `'RECORD_PAGE'`, `'DASHBOARD'` or `'STANDALONE_PAGE'`. Use `'RECORD_PAGE'` to customize the detail view of a specific object.
- `objectUniversalIdentifier` specifies which object this layout applies to.
- Each `tab` defines a section of the page with a `title`, `position`, and `layoutMode` (`VERTICAL_LIST` for record pages, `GRID` for dashboards). A tab holding a single widget renders it full-bleed automatically; with several widgets they stack as cards.
- Each `widget` inside a tab can render a [front component](/developers/extend/apps/layout/front-components), a relation list, or other built-in widget types.
@@ -2,6 +2,7 @@ import { type SyncableEntityOptions } from '@/application/syncableEntityOptionsT
import {
type GridPosition,
type PageLayoutTabLayoutMode,
type PageLayoutType,
type PageLayoutWidgetConditionalDisplay,
type PageLayoutWidgetUniversalConfiguration,
} from '@/types';
@@ -26,7 +27,7 @@ export type PageLayoutTabManifest = SyncableEntityOptions & {
export type PageLayoutManifest = SyncableEntityOptions & {
name: string;
type: string;
type: `${PageLayoutType}`;
objectUniversalIdentifier?: string;
defaultTabToFocusOnMobileAndSidePanelUniversalIdentifier?: string;
tabs?: PageLayoutTabManifest[];