User: {userId}
Record: {recordId ?? 'No record context'}
Component: {componentId}
);
};
export default defineFrontComponent({
universalIdentifier: 'b2c3d4e5-f6a7-8901-bcde-f23456789012',
name: 'record-info',
component: RecordInfo,
});
```
Доступные хуки:
| Хук | Возвращает | Описание |
| --------------------------------------------- | ------------------- | ----------------------------------------------------------------- |
| `useUserId()` | `string` или `null` | ID текущего пользователя |
| `useRecordId()` | `string` или `null` | ID текущей записи (при размещении на странице записи) |
| `useFrontComponentId()` | `строка` | ID этого экземпляра компонента |
| `useFrontComponentExecutionContext(selector)` | различается | Доступ к полному контексту выполнения с помощью функции-селектора |
#### API взаимодействия с хостом
Компоненты фронтенда могут вызывать навигацию, модальные окна и уведомления с помощью функций из `twenty-sdk`:
| Функция | Описание |
| ----------------------------------------------- | -------------------------------- |
| `navigate(to, params?, queryParams?, options?)` | Перейти на страницу в приложении |
| `openSidePanelPage(params)` | Открыть боковую панель |
| `closeSidePanel()` | Закрыть боковую панель |
| `openCommandConfirmationModal(params)` | Показать диалог подтверждения |
| `enqueueSnackbar(params)` | Показать всплывающее уведомление |
| `unmountFrontComponent()` | Размонтировать компонент |
| `updateProgress(progress)` | Обновить индикатор прогресса |
#### Параметры команды
Добавление поля `command` в `defineFrontComponent` регистрирует компонент в меню команд (Cmd+K). Если `isPinned` имеет значение `true`, команда также отображается как кнопка быстрого действия в правом верхнем углу страницы.
| Поле | Обязательно | Описание |
| --------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `universalIdentifier` | Да | Стабильный уникальный идентификатор для команды |
| `label` | Да | Полная метка, отображаемая в меню команд (Cmd+K) |
| `shortLabel` | Нет | Короткая метка, отображаемая на закреплённой кнопке быстрого действия |
| `icon` | Нет | Имя значка, отображаемое рядом с меткой (например, `'IconBolt'`, `'IconSend'`) |
| `isPinned` | Нет | При значении `true` показывает команду как кнопку быстрого действия в правом верхнем углу страницы |
| `availabilityType` | Нет | Определяет, где отображается команда: `'GLOBAL'` (доступна всегда), `'RECORD_SELECTION'` (только при выборе записей) или `'FALLBACK'` (показывается, когда другие команды не подходят) |
| `availabilityObjectUniversalIdentifier` | Нет | Ограничивает команду страницами определённого типа объектов (например, только для записей Company) |
| `conditionalAvailabilityExpression` | Нет | Логическое выражение для динамического управления видимостью команды (см. ниже) |
#### Выражения условной доступности
Поле `conditionalAvailabilityExpression` позволяет управлять видимостью команды в зависимости от текущего контекста страницы. Импортируйте типизированные переменные и операторы из `twenty-sdk`, чтобы составлять выражения:
```tsx
import {
defineFrontComponent,
pageType,
numberOfSelectedRecords,
objectPermissions,
everyEquals,
isDefined,
} from 'twenty-sdk';
export default defineFrontComponent({
universalIdentifier: '...',
name: 'bulk-action',
component: BulkAction,
command: {
universalIdentifier: '...',
label: 'Bulk Update',
availabilityType: 'RECORD_SELECTION',
conditionalAvailabilityExpression: everyEquals(
objectPermissions,
'canUpdateObjectRecords',
true,
),
},
});
```
**Переменные контекста** — представляют текущее состояние страницы:
| Переменная | Тип | Описание |
| ------------------------------ | --------- | ------------------------------------------------------------------------ |
| `pageType` | `строка` | Текущий тип страницы (например, `'RecordIndexPage'`, `'RecordShowPage'`) |
| `isInSidePanel` | `boolean` | Указывает, рендерится ли компонент в боковой панели |
| `numberOfSelectedRecords` | `number` | Количество выбранных в данный момент записей |
| `isSelectAll` | `boolean` | Активен ли режим "выбрать все" |
| `selectedRecords` | `массив` | Объекты выбранных записей |
| `favoriteRecordIds` | `массив` | ID избранных записей |
| `objectPermissions` | `object` | Разрешения для текущего типа объекта |
| `targetObjectReadPermissions` | `object` | Права на чтение для целевого объекта |
| `targetObjectWritePermissions` | `object` | Права на запись для целевого объекта |
| `featureFlags` | `object` | Активные флаги функций |
| `objectMetadataItem` | `object` | Метаданные текущего типа объекта |
| `hasAnySoftDeleteFilterOnView` | `boolean` | Есть ли у текущего представления фильтр мягкого удаления |
**Операторы** — комбинируют переменные в логические выражения:
| Оператор | Описание |
| ----------------------------------- | ------------------------------------------------------------------------- |
| `isDefined(value)` | `true`, если значение не null/undefined |
| `isNonEmptyString(value)` | `true`, если значение — непустая строка |
| `includes(array, value)` | `true`, если массив содержит значение |
| `includesEvery(array, prop, value)` | `true`, если свойство каждого элемента включает значение |
| `every(array, prop)` | `true`, если свойство истинно для каждого элемента |
| `everyDefined(array, prop)` | `true`, если свойство определено у каждого элемента |
| `everyEquals(array, prop, value)` | `true`, если свойство равно значению у каждого элемента |
| `some(array, prop)` | `true`, если свойство истинно хотя бы у одного элемента |
| `someDefined(array, prop)` | `true`, если свойство определено хотя бы у одного элемента |
| `someEquals(array, prop, value)` | `true`, если свойство равно значению хотя бы у одного элемента |
| `someNonEmptyString(array, prop)` | `true`, если свойство является непустой строкой хотя бы у одного элемента |
| `none(array, prop)` | `true`, если свойство ложно для каждого элемента |
| `noneDefined(array, prop)` | `true`, если свойство не определено ни у одного элемента |
| `noneEquals(array, prop, value)` | `true`, если свойство не равно значению ни у одного элемента |
#### Публичные ресурсы
Компоненты фронтенда могут получать доступ к файлам из каталога приложения `public/` с помощью `getPublicAssetUrl`:
```tsx
import { defineFrontComponent, getPublicAssetUrl } from 'twenty-sdk';
const Logo = () =>