跳转到主要内容
页面布局(page layout) 控制记录详情页的排布方式:显示哪些选项卡,以及这些选项卡中包含哪些小部件。 使用 definePageLayout() 为你拥有的对象声明一个布局,或者使用 definePageLayoutTab() 为已存在的布局(你的自定义布局或标准的 Twenty 布局)添加单个选项卡。
用例实体
为你拥有的对象上的记录页面定义完整布局definePageLayout
向现有布局中添加一个选项卡(你自己的对象或一个标准对象)definePageLayoutTab

definePageLayout

当你拥有整个详情页时使用此方式——通常适用于你自己定义的自定义对象。
src/page-layouts/example-record-page-layout.ts
import { definePageLayout, PageLayoutTabLayoutMode } from 'twenty-sdk/define';
import { EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER } from '../objects/example-object';
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from '../front-components/hello-world';

export default definePageLayout({
  universalIdentifier: '203aeb94-6701-46d6-9af1-be2bbcc9e134',
  name: 'Example Record Page',
  type: 'RECORD_PAGE',
  objectUniversalIdentifier: EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER,
  tabs: [
    {
      universalIdentifier: '6ed26b60-a51d-4ad7-86dd-1c04c7f3cac5',
      title: 'Hello World',
      position: 50,
      icon: 'IconWorld',
      layoutMode: PageLayoutTabLayoutMode.CANVAS,
      widgets: [
        {
          universalIdentifier: 'aa4234e0-2e5f-4c02-a96a-573449e2351d',
          title: 'Hello World',
          type: 'FRONT_COMPONENT',
          configuration: {
            configurationType: 'FRONT_COMPONENT',
            frontComponentUniversalIdentifier:
              HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER,
          },
        },
      ],
    },
  ],
});

关键点

  • type 通常为 ‘RECORD_PAGE’,用于自定义特定对象的详情视图。
  • objectUniversalIdentifier 指定此布局适用于哪个对象。
  • 每个 tab 使用 titlepositionlayoutMode 定义页面的一个部分(CANVAS 表示自由布局)。
  • 选项卡内的每个 widget 可以渲染一个前端组件、关系列表或其他内置小部件类型。
  • 选项卡上的 position 控制其顺序。 使用更高的值(例如 50)可将自定义选项卡放在内置选项卡之后。

definePageLayoutTab

当你只想在现有布局中添加一个选项卡时使用此方式——例如,在标准 Company 页面上添加一个分析选项卡,或者在你自己的对象布局上附加一个 AI 摘要选项卡。
src/page-layouts/example-extra-tab.ts
import {
  definePageLayoutTab,
  PageLayoutTabLayoutMode,
  STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from '../front-components/hello-world';

export default definePageLayoutTab({
  universalIdentifier: 'b1b2b3b4-b5b6-4000-8000-000000000001',
  pageLayoutUniversalIdentifier:
    STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage
      .universalIdentifier,
  title: 'Hello World',
  position: 1000,
  icon: 'IconWorld',
  layoutMode: PageLayoutTabLayoutMode.CANVAS,
  widgets: [
    {
      universalIdentifier: 'b1b2b3b4-b5b6-4000-8000-000000000002',
      title: 'Hello World',
      type: 'FRONT_COMPONENT',
      configuration: {
        configurationType: 'FRONT_COMPONENT',
        frontComponentUniversalIdentifier:
          HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER,
      },
    },
  ],
});

关键点

  • pageLayoutUniversalIdentifier必需的,并且必须在安装时指向一个已存在的页面布局——可以是标准的 Twenty 布局,也可以是由你自己的应用定义的布局。 当前不支持跨应用引用由其他已安装应用拥有的布局。 当父布局缺失时,安装会失败,并给出清晰的验证错误。
  • 对于标准 Twenty 布局,从 twenty-sdk/define 导入标识符:
    import { STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
    
    // STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.companyRecordPage.universalIdentifier
    // STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.personRecordPage.universalIdentifier
    // STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.universalIdentifier
    // STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.opportunityRecordPage.universalIdentifier
    // STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.noteRecordPage.universalIdentifier
    // …
    
    每个布局条目还会公开其 tabs 及其 widgets,因此你可以引用任意层级:
    STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.universalIdentifier
    STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.widgets.fields.universalIdentifier
    
    还提供了一个简短别名 STANDARD_PAGE_LAYOUT
    import { STANDARD_PAGE_LAYOUT } from 'twenty-sdk/define';
    
    STANDARD_PAGE_LAYOUT.companyRecordPage.universalIdentifier;
    
  • widgets 仅作用于此选项卡——它们引用前端组件、视图等,其方式与在 definePageLayout 中内联定义的小部件完全相同。
  • position 控制目标布局中相对于现有选项卡的排序。 选择一个取值,使你的选项卡相对于内置选项卡位于你想要的位置。
  • 当你只想向现有布局进行添加时,请使用此功能,而不是 definePageLayout。 当你拥有整个布局时,请使用 definePageLayout