Перейти к основному содержанию
Элемент командного меню — это мост между пользователем и фронтенд-компонентом. Он регистрирует компонент в командном меню Twenty (Cmd+K) и, при необходимости, как закреплённую кнопку быстрого действия в правом верхнем углу страницы.
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НетЛогическое выражение, которое динамически управляет видимостью (см. ниже)

Команды без интерфейса

Элемент командного меню в паре с фронтенд-компонентом без интерфейса — идиоматичный способ предоставить действие в один клик: выполнить код, перейти или подтвердить и выполнить. Страница Front Components описывает SDK Command components (Command, CommandLink, CommandModal, CommandOpenSidePanelPage), которые реализуют шаблон «действие и размонтирование». Типичный сценарий:
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,
});
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, чтобы составлять выражения:
src/command-menu-items/bulk-update.command-menu-item.ts
import {
  defineCommandMenuItem,
  objectPermissions,
  everyEquals,
} from 'twenty-sdk/define';

export default defineCommandMenuItem({
  universalIdentifier: '...',
  label: 'Bulk Update',
  availabilityType: 'RECORD_SELECTION',
  frontComponentUniversalIdentifier: '...',
  conditionalAvailabilityExpression: everyEquals(
    objectPermissions,
    'canUpdateObjectRecords',
    true,
  ),
});
RECORD_SELECTION уже подразумевает, что есть выбранные записи — используйте numberOfSelectedRecords только для конкретных количеств (например, >= 2).

Переменные контекста

Они представляют текущее состояние страницы:
ПеременнаяТипОписание
pageTypestringТекущий тип страницы (например, 'RecordIndexPage', 'RecordShowPage')
isInSidePanelbooleanУказывает, рендерится ли компонент в боковой панели
numberOfSelectedRecordsnumberКоличество выбранных в данный момент записей
isSelectAllbooleanАктивен ли режим “выбрать все”
selectedRecordsarrayОбъекты выбранных записей
favoriteRecordIdsarrayID избранных записей
objectPermissionsobjectРазрешения для текущего типа объекта
targetObjectReadPermissionsobjectПрава на чтение для целевого объекта
targetObjectWritePermissionsobjectПрава на запись для целевого объекта
featureFlagsobjectАктивные флаги функций
objectMetadataItemobjectМетаданные текущего типа объекта
hasAnySoftDeleteFilterOnViewbooleanЕсть ли у текущего представления фильтр мягкого удаления

Операторы

Комбинируйте переменные в логические выражения:
ОператорОписание
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, если свойство не равно значению ни у одного элемента