145 lines
12 KiB
Plaintext
145 lines
12 KiB
Plaintext
---
|
|
title: Элементы меню команд
|
|
description: Отображайте фронтенд-компоненты как быстрые действия и элементы командного меню (Cmd+K) с помощью `defineCommandMenuItem`.
|
|
icon: terminal
|
|
---
|
|
|
|
**Элемент командного меню** — это мост между пользователем и [фронтенд-компонентом](/l/ru/developers/extend/apps/layout/front-components). Он регистрирует компонент в командном меню Twenty (Cmd+K) и, при необходимости, как закреплённую кнопку быстрого действия в правом верхнем углу страницы.
|
|
|
|
```ts src/command-menu-items/open-dashboard.command-menu-item.ts
|
|
import { defineCommandMenuItem } from 'twenty-sdk/define';
|
|
|
|
export default defineCommandMenuItem({
|
|
universalIdentifier: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
|
label: 'Open Dashboard',
|
|
shortLabel: 'Dashboard',
|
|
icon: 'IconLayoutDashboard',
|
|
isPinned: true,
|
|
availabilityType: 'GLOBAL',
|
|
frontComponentUniversalIdentifier: '74c526eb-cb68-4cf7-b05c-0dd8c288d948',
|
|
});
|
|
```
|
|
|
|
## Поля конфигурации
|
|
|
|
| Поле | Обязательно | Описание |
|
|
| --------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `universalIdentifier` | Да | Стабильный уникальный идентификатор для команды |
|
|
| `label` | Да | Полная метка, отображаемая в меню команд (Cmd+K) |
|
|
| `frontComponentUniversalIdentifier` | Да | `universalIdentifier` фронтенд-компонента, который открывается этой командой |
|
|
| `shortLabel` | Нет | Короткая метка, отображаемая на закреплённой кнопке быстрого действия |
|
|
| `icon` | Нет | Имя значка, отображаемое рядом с меткой (например, `'IconBolt'`, `'IconSend'`) |
|
|
| `isPinned` | Нет | При значении `true` показывает команду как кнопку быстрого действия в правом верхнем углу страницы |
|
|
| `availabilityType` | Нет | Определяет, где отображается команда: `'GLOBAL'` (доступна всегда), `'RECORD_SELECTION'` (только при выборе записей) или `'FALLBACK'` (показывается, когда другие команды не подходят) |
|
|
| `availabilityObjectUniversalIdentifier` | Нет | Ограничивает команду страницами определённого типа объектов (например, только для записей Company) |
|
|
| `conditionalAvailabilityExpression` | Нет | Логическое выражение, которое динамически управляет видимостью (см. ниже) |
|
|
|
|
## Команды без интерфейса
|
|
|
|
Элемент командного меню в паре с [фронтенд-компонентом без интерфейса](/l/ru/developers/extend/apps/layout/front-components#headless-vs-non-headless) — идиоматичный способ предоставить действие в один клик: выполнить код, перейти или подтвердить и выполнить. Страница Front Components описывает [SDK Command components](/l/ru/developers/extend/apps/layout/front-components#sdk-command-components) (`Command`, `CommandLink`, `CommandModal`, `CommandOpenSidePanelPage`), которые реализуют шаблон «действие и размонтирование».
|
|
|
|
Типичный сценарий:
|
|
|
|
```tsx src/front-components/run-action.tsx
|
|
import { defineFrontComponent } from 'twenty-sdk/define';
|
|
import { Command } from 'twenty-sdk/command';
|
|
import { CoreApiClient } from 'twenty-sdk/clients';
|
|
|
|
const RunAction = () => {
|
|
const execute = async () => {
|
|
const client = new CoreApiClient();
|
|
await client.mutation({
|
|
createTask: {
|
|
__args: { data: { title: 'Created by my app' } },
|
|
id: true,
|
|
},
|
|
});
|
|
};
|
|
|
|
return <Command execute={execute} />;
|
|
};
|
|
|
|
export default defineFrontComponent({
|
|
universalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
|
name: 'run-action',
|
|
description: 'Creates a task from the command menu',
|
|
component: RunAction,
|
|
isHeadless: true,
|
|
});
|
|
```
|
|
|
|
```ts src/command-menu-items/run-action.command-menu-item.ts
|
|
import { defineCommandMenuItem } from 'twenty-sdk/define';
|
|
|
|
export default defineCommandMenuItem({
|
|
universalIdentifier: 'f6a7b8c9-d0e1-2345-fabc-456789012345',
|
|
label: 'Run my action',
|
|
icon: 'IconPlayerPlay',
|
|
frontComponentUniversalIdentifier: 'e5f6a7b8-c9d0-1234-efab-345678901234',
|
|
});
|
|
```
|
|
|
|
## Выражения условной доступности
|
|
|
|
Поле `conditionalAvailabilityExpression` позволяет управлять видимостью команды в зависимости от текущего контекста страницы. Импортируйте типизированные переменные и операторы из `twenty-sdk`, чтобы составлять выражения:
|
|
|
|
```ts src/command-menu-items/bulk-update.command-menu-item.ts
|
|
import { defineCommandMenuItem } from 'twenty-sdk/define';
|
|
import {
|
|
objectPermissions,
|
|
everyEquals,
|
|
} from 'twenty-sdk/front-component';
|
|
|
|
export default defineCommandMenuItem({
|
|
universalIdentifier: '...',
|
|
label: 'Bulk Update',
|
|
availabilityType: 'RECORD_SELECTION',
|
|
frontComponentUniversalIdentifier: '...',
|
|
conditionalAvailabilityExpression: everyEquals(
|
|
objectPermissions,
|
|
'canUpdateObjectRecords',
|
|
true,
|
|
),
|
|
});
|
|
```
|
|
|
|
### Переменные контекста
|
|
|
|
Они представляют текущее состояние страницы:
|
|
|
|
| Переменная | Тип | Описание |
|
|
| ------------------------------ | --------- | ------------------------------------------------------------------------ |
|
|
| `pageType` | `string` | Текущий тип страницы (например, `'RecordIndexPage'`, `'RecordShowPage'`) |
|
|
| `isInSidePanel` | `boolean` | Указывает, рендерится ли компонент в боковой панели |
|
|
| `numberOfSelectedRecords` | `number` | Количество выбранных в данный момент записей |
|
|
| `isSelectAll` | `boolean` | Активен ли режим "выбрать все" |
|
|
| `selectedRecords` | `array` | Объекты выбранных записей |
|
|
| `favoriteRecordIds` | `array` | 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`, если свойство не равно значению ни у одного элемента |
|