> ## Documentation Index
> Fetch the complete documentation index at: https://twenty-claude-cool-pascal-5ay683.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Макеты страниц

> Настраивайте страницы деталей записей — вкладки, виджеты и места, где отображаются фронтенд-компоненты, — с помощью `definePageLayout` и `definePageLayoutTab`.

**Макет страницы** управляет тем, как устроена страница деталей записи: какие вкладки отображаются и какие виджеты они содержат. Используйте `definePageLayout()` для объявления макета для объекта, которым вы владеете, или `definePageLayoutTab()` для добавления одной вкладки к макету, который уже существует (вашему или стандартному Twenty).

| Сценарий использования                                                                        | Сущность              |
| --------------------------------------------------------------------------------------------- | --------------------- |
| Определите весь макет для страницы записи на объекте, которым вы владеете                     | `definePageLayout`    |
| Добавьте одну вкладку в существующий макет (для вашего собственного объекта или стандартного) | `definePageLayoutTab` |

## definePageLayout

Используйте это, когда вы управляете всей страницей деталей — обычно для пользовательского объекта, который вы определили сами.

```ts src/page-layouts/example-record-page-layout.ts theme={null}
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.VERTICAL_LIST,
      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_INDEX'`, `'RECORD_PAGE'`, `'DASHBOARD'` или `'STANDALONE_PAGE'`. Используйте `'RECORD_PAGE'` для настройки детального представления конкретного объекта.
* `objectUniversalIdentifier` указывает, к какому объекту применяется этот макет.
* Каждая `tab` определяет раздел страницы с `title`, `position` и `layoutMode`: `VERTICAL_LIST` для страниц записей и автономных страниц, `GRID` для панелей мониторинга и `CANVAS` для одного виджета, который должен заполнять область просмотра вкладки. Во вкладке `VERTICAL_LIST` виджеты располагаются вертикально. Встроенные виджеты, которые самостоятельно управляют прокруткой, такие как временные шкалы, файлы, заметки, задачи и рабочие процессы, заполняют одну область просмотра; поля, фронтальные компоненты, графики и другие виджеты с подгонкой по содержимому отображаются с высотой по содержимому или заданной высотой. Во вкладке `GRID` виджеты всегда размещаются в виде карточек в 12-колоночной сетке. Виджет `CANVAS` не имеет явно заданного положения; если вкладка холста содержит несколько виджетов, они отображаются на высоте своего содержимого, а не заполняют область просмотра.
* Явно задайте `layoutMode`. Если его не указывать, вы получите `VERTICAL_LIST` на `STANDALONE_PAGE` и `GRID` в остальных случаях, что редко бывает нужно на странице записи.
* Каждый `widget` внутри вкладки может отображать [front component](/l/ru/developers/extend/apps/layout/front-components), список связей или другие встроенные типы виджетов.
* Виджет `FRONT_COMPONENT` может задавать для `headerCommandMenuItemUniversalIdentifiers` упорядоченный массив универсальных идентификаторов элементов меню команд из того же приложения. Эти действия отображаются как кнопки со значками в заголовке карточки виджета и сохраняют доступность и проверки разрешений на уровне команд. Идентификаторы должны быть уникальными и разрешаться при установке приложения.
* `position` у вкладок управляет их порядком. Используйте большие значения (например, 50), чтобы разместить пользовательские вкладки после встроенных.

### Виджеты полей

Виджет `FIELD` отображает одно поле записи. Для полей связи он также может встраивать список связанных записей:

```ts theme={null}
{
  universalIdentifier: 'c1c2c3c4-c5c6-4000-8000-000000000003',
  title: 'People → Opportunities',
  type: 'FIELD',
  configuration: {
    configurationType: 'FIELD',
    fieldMetadataId: PEOPLE_FIELD_UNIVERSAL_IDENTIFIER,
    fieldDisplayMode: 'TABLE',
    nestedRelationFieldMetadataId: OPPORTUNITIES_FIELD_UNIVERSAL_IDENTIFIER,
  },
}
```

* `fieldMetadataId` принимает универсальный идентификатор поля в объекте макета.
* `fieldDisplayMode` может иметь одно из следующих значений: `'FIELD'`, `'CARD'`, `'EDITOR'`, `'VIEW'` или `'TABLE'`. `TABLE` встраивает представление, отображающее записи поля связи «один‑ко‑многим».
* `nestedRelationFieldMetadataId` является необязательным и принимает универсальный идентификатор поля связи «один‑ко‑многим» на целевом объекте связи, чтобы перечислять записи на два перехода связи дальше (например, страница Company, перечисляющая сделки людей этой компании, или страница Person, перечисляющая сделки компании этого человека). Первый переход может быть полем связи «один‑ко‑многим» или «многие‑к‑одному», второй обязан быть «один‑ко‑многим» (соединительные связи не поддерживаются), и это требует `fieldDisplayMode: 'TABLE'` — комбинирование его с любым другим режимом отображения является ошибкой валидации, поскольку вложенный виджет всегда отображается как встраиваемое представление.

## definePageLayoutTab

Используйте это, когда вы хотите только **добавить** вкладку к существующему макету — например, вкладку аналитики на стандартной странице Company или вкладку с AI-сводкой, прикреплённую к макету вашего собственного объекта.

```ts src/page-layouts/example-extra-tab.ts theme={null}
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.VERTICAL_LIST,
  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`:

  ```ts theme={null}
  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`, поэтому вы можете ссылаться на любой уровень:

  ```ts theme={null}
  STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home
    .universalIdentifier;
  STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.taskRecordPage.tabs.home.widgets
    .fields.universalIdentifier;
  ```

  Также доступен короткий псевдоним `STANDARD_PAGE_LAYOUT`:

  ```ts theme={null}
  import { STANDARD_PAGE_LAYOUT } from 'twenty-sdk/define';

  STANDARD_PAGE_LAYOUT.companyRecordPage.universalIdentifier;
  ```

* `widgets` ограничены только этой вкладкой — они ссылаются на [front components](/l/ru/developers/extend/apps/layout/front-components), представления и т. п. точно так же, как виджеты, определённые непосредственно в `definePageLayout`.

* `position` управляет порядком относительно существующих вкладок в целевом макете. Выберите значение, которое поместит вашу вкладку в нужное место относительно встроенных вкладок.

* Используйте это вместо `definePageLayout`, когда вы хотите только добавить к существующему макету. Используйте `definePageLayout`, когда вы управляете всем макетом.
