Appearance
Руководство по действию runMethod
Руководство описывает, как настроить действия runMethod в JSON-файлах конфигурации.
Содержание
- Что такое
runMethod - Базовая конфигурация
- Стратегии LinkEndpoint
- Как работает
idSource - Форма перед запуском (
editor) - Действия после ответа
- Файлы, которые возвращает метод
- Примеры
- Рекомендации
- Частые проблемы
Что такое runMethod
Действие runMethod запускает серверный метаметод из интерфейса. Пользователь может:
- выбрать объекты в таблице или дереве;
- при необходимости заполнить форму (
editor); - запустить серверный метод для выбранных объектов;
- увидеть результат: всплывающие уведомления, обновлённые данные объектов и т. д.
Базовая конфигурация
Действие runMethod состоит из трёх основных частей:
json
{
"id": "action-id",
"method": "runMethod",
"label": "Button Label",
"icon": "icon-name",
"request": {
"parent": "MetaTypeName",
"methodName": "backendMethodName",
"objects": [/* стратегии LinkEndpoint */]
},
"editor": {/* необязательная настройка формы */},
"response": {/* необязательные действия после успешного выполнения */}
}Обязательные свойства
request.parent— тип метамодели, например"ProductionOrder".request.methodName— серверный метод, который нужно вызвать.request.objects— массив стратегий LinkEndpoint; они определяют, какие объекты передать в метод.
Необязательные свойства
editor— форма, в которой пользователь вводит данные перед запуском.response— действия на стороне клиента, которые выполняются после успешного вызова.
Стратегии LinkEndpoint
Элементы LinkEndpoint определяют, какие объекты получит серверный метод. Можно использовать семь стратегий.
Обзор стратегий
| Стратегия | Когда использовать | Пример |
|---|---|---|
objectId | Фиксированный GUID объекта | Объект конфигурации, системные настройки |
getFromItem | Элементы, выбранные пользователем | Самый частый случай |
getFromCreatedObject | Только что созданный объект | ⚠️ Пока не поддерживается |
getSelectedObjectForEventId | Объект из события | Нажатие на уведомление |
selectPanel | Пользователь выбирает в модальном окне | Выбор поставщика или оператора |
getSelectedObjectForPanelId | Объекты из другой панели | Сценарии с несколькими панелями |
getFromActionId | Объекты из другого действия | Цепочка действий |
1. objectId
Передаёт GUID объекта, заданный прямо в конфигурации.
json
{
"objects": [
{
"objectId": {
"objectGuid": "123e4567-e89b-12d3-a456-426614174000"
}
}
]
}Когда использовать: для объектов конфигурации, системных настроек и любых других фиксированных ссылок.
2. getFromItem
Передаёт объекты, которые пользователь выбрал в таблице или дереве.
json
{
"objects": [
{
"getFromItem": true
}
]
}Когда использовать: это самая распространённая стратегия. Используйте её, когда действие работает со строками или узлами, выбранными пользователем.
Как это выглядит для пользователя:
- Пользователь выбирает один или несколько элементов в таблице или дереве.
- Нажимает кнопку действия.
- Метод выполняется с ID выбранных объектов.
3. getFromCreatedObject
⚠️ Для runMethod пока не поддерживается
Задумана для цепочки: create → link → runMethod.
4. getSelectedObjectForEventId
Передаёт объект, который вызвал указанное событие.
json
{
"objects": [
{
"getSelectedObjectForEventId": "notification--on-click"
}
]
}Когда использовать: для действий, которые запускает событие, например нажатие на уведомление или автоматический триггер.
5. selectPanel
Открывает модальную панель, в которой пользователь выбирает объект.
json
{
"objects": [
{
"selectPanel": {
"panel": {
"id": "supplier-select",
"type": "table",
"request": {
"metaTypeName": "Supplier"
},
"columns": [
{"attribute": "name", "label": "Supplier Name"}
]
}
}
}
]
}Когда использовать: когда целевой объект заранее неизвестен, например для действий «Assign to Operator» или «Link to Supplier».
Как это выглядит для пользователя:
- Пользователь нажимает кнопку действия.
- Панель открывает модальное окно с таблицей или деревом.
- Пользователь выбирает в нём объект или объекты.
- Метод выполняется с выбранным объектом.
6. getSelectedObjectForPanelId
Передаёт все объекты, которые сейчас выбраны на панели с указанным ID.
json
{
"objects": [
{
"getSelectedObjectForPanelId": "sidebar-panel-id"
}
]
}Когда использовать: в сценариях с несколькими панелями, когда методу нужны объекты из другой панели.
Отличие от selectPanel:
selectPanelоткрывает модальное окно для выбора;getSelectedObjectForPanelIdберёт то, что уже выбрано на существующей панели.
7. getFromActionId
Берёт ID объектов из контекста другого действия (цепочка действий).
json
{
"objects": [
{
"getFromActionId": "create-batch-action"
}
]
}Когда использовать: в цепочках, где первое действие создаёт или изменяет объекты, а второе их обрабатывает.
Пример: создание партии → запуск её производства.
Как работает idSource
Когда речь идёт о связанных объектах, каждый выбранный элемент содержит два GUID:
link.objectGuid— ID сущности связи, то есть самой связи;linkedObject.objectGuid— ID целевого объекта.
Свойство idSource определяет, какой из них передать.
Когда какой вариант выбрать
idSource: 'link', если:
- удаляете сущности связи;
- работаете с самой связью;
- метод ожидает GUID связей.
idSource: 'linkedObject' (значение по умолчанию), если:
- работаете с данными связанного объекта;
- выполняете большинство стандартных CRUD-операций;
- метод ожидает GUID объектов.
Примеры
Удалить связь и сохранить оба объекта:
json
{
"request": {
"parent": "Link",
"methodName": "deleteLink",
"objects": [
{
"getFromItem": true,
"idSource": "link"
}
]
}
}Обновить данные связанного объекта:
json
{
"request": {
"parent": "Product",
"methodName": "updatePrice",
"objects": [
{
"getFromItem": true,
"idSource": "linkedObject"
}
]
}
}Без idSource (по умолчанию используется linkedObject):
json
{
"objects": [
{"getFromItem": true}
]
}Какие стратегии поддерживают idSource
- ✅
getFromItem - ✅
getFromCreatedObject - ✅
getSelectedObjectForEventId - ✅
selectPanel - ✅
getSelectedObjectForPanelId - ❌
getFromActionId(возвращает уже определённые ID) - ❌
objectId(GUID вы задаёте сами)
Практический сценарий
Задача: удалить связь между Product и Supplier, не удаляя ни Product, ни Supplier.
Решение:
json
{
"id": "remove-supplier-link",
"method": "runMethod",
"label": "Remove Supplier",
"request": {
"parent": "Link",
"methodName": "deleteLink",
"objects": [
{
"getFromItem": true,
"idSource": "link"
}
]
}
}Без idSource: 'link' действие попыталось бы удалить объект Supplier, а не связь.
Форма перед запуском (editor)
Свойство editor добавляет форму, которая открывается перед запуском метода.
Без формы: немедленный запуск
json
{
"method": "runMethod",
"request": {
"parent": "ProductionOrder",
"methodName": "startProduction",
"objects": [{"getFromItem": true}]
}
}Как это выглядит для пользователя: нажатие на кнопку → метод сразу выполняется.
Метод запускается сразу, только если свойства editor нет. Редактор с пустым массивом fields всё равно остаётся формой и открывает модальное окно. Поэтому для методов, которым не нужен ввод, не указывайте editor совсем.
С формой перед запуском
json
{
"method": "runMethod",
"editor": {
"mode": "modal",
"header": {
"title": "Assign to Operator"
},
"fields": [
{
"attribute": "operator",
"label": "Operator",
"type": "Object",
"required": true,
"propertyAsId": "itemId",
"selectPanel": {
"panel": {
"id": "operator-select",
"type": "table",
"request": {"metaTypeName": "Operator"}
}
}
},
{
"attribute": "priority",
"label": "Priority",
"type": "String",
"required": true
}
]
},
"request": {
"parent": "ProductionOrder",
"methodName": "assignOperator",
"objects": [{"getFromItem": true}]
}
}Как это выглядит для пользователя: нажатие на кнопку → панель открывает модальное окно → пользователь заполняет форму → нажимает Применить → метод выполняется.
Файл для метода
Если методу нужен файл от пользователя, например таблица для импорта, задайте полю "control": "scratchFile":
json
{
"id": "import-materials",
"method": "runMethod",
"label": {"ru": "Импорт материалов", "en": "Import materials"},
"editor": {
"mode": "modal",
"header": {
"title": "Import materials"
},
"fields": [
{
"attribute": "scratchToken",
"type": "String",
"control": "scratchFile",
"label": {"ru": "Файл импорта", "en": "Import file"}
}
]
},
"request": {
"parent": "MaterialDefinition",
"methodName": "materialImport",
"objects": [{"getFromItem": true}]
}
}MaterialDefinition и materialImport здесь условные: укажите метод своего API, который читает токен из параметра с именем из attribute.
Поле показывает кнопку Выбрать файл. Пользователь выбирает один файл размером до 256 МиБ; файл большего размера форма сразу отклоняет и предлагает выбрать файл поменьше. Сам выбор файла ещё ничего не отправляет.
Когда пользователь нажимает Применить, панель сначала загружает файл в хранилище временных файлов (POST /files/scratch) и получает токен вида sc_…. Затем она вызывает метод и передаёт этот токен строковым параметром, имя которого совпадает с attribute поля, — здесь это params.scratchToken. Серверный метод читает файл по этому токену. Токен действует 24 часа и только для пользователя, который загрузил файл. Набором данных (Dataset) файл не становится.
attribute— имя параметра, которого ожидает серверный метод.typeнужно явно указать какString: метод получает токен, а не файл.defaultValueзадавать нельзя: файл выбирает только пользователь.- Если файл не выбран, этого параметра в запросе нет.
requiredне проверяется — как и у других полей. - Если загрузка не удалась, панель показывает сообщение «Файл не загружен, метод не запущен»; при ответе
413она добавляет, что файл больше 256 МиБ. Метод не запускается, а форма остаётся открытой с выбранными значениями. - Если пользователь закроет форму, пока файл загружается, метод не запустится.
- Кнопка Отменить ничего не загружает.
scratchFile работает только в форме действия runMethod. Все остальные случаи — ошибка конфигурации: поле в другом редакторе — create, update, http, редакторе атрибутов или editor.runMethod действия create; scratchFile без явного "type": "String" или с defaultValue; любое другое значение control, в том числе пустое. Тогда поле показывает ошибку, например «Ошибка настройки: выбор файла (control «scratchFile») работает только в форме запуска метода. Действие не выполняется», и форма не отправляется: иначе действие выполнилось бы без значения, которого ждёт его настройка. Скрытые поля и поля на других вкладках тоже проверяются: их ошибки появляются в уведомлении, когда пользователь отправляет форму. Чтобы действие заработало, исправьте JSON редактора.
Действие runMethod в attributes.panelActions запускается без своего редактора и не может заполнить это поле: если в его редакторе есть поле с control, действие не выполняется, а такое же уведомление называет поле. То же относится к create с editor.mode: "direct-request", к http без модального редактора и к runMethod, который запускается при создании узла BPMN без формы или при его удалении.
На вкладке Action input нажмите Action input: файл → файл, выберите любой файл и нажмите Применить. Метод демонстрационного API получает токен, а браузер сохраняет файл round-trip-report.txt с именем и размером выбранного файла. Если файл не выбран, в отчёте сказано, что файл не получен.
Действия после ответа
После успешного выполнения метода можно запустить дополнительные действия. runMethod берёт действия после ответа из двух источников:
- из ответа
/MetaMethods/Run, если сервер возвращает массивactions; - из JSON-конфигурации действия, через
response.actions.
Действия из обоих источников выполняет один и тот же обработчик. Сначала выполняются действия от сервера, затем — заданные в конфигурации. Если метод запускался для выбранных объектов, каждое действие после ответа выполняется один раз для каждого объекта, который определили стратегии request.objects. Если таких объектов нет, действия после ответа выполняются один раз в контексте текущей панели.
Действия после ответа от сервера
Серверный метод может вернуть один объект ответа или массив таких объектов. Каждый из них может содержать actions:
json
{
"actions": [
{
"method": "reloadEntities",
"panels": [{"panelId": "orders-table"}]
},
{
"method": "showNotification",
"severity": "success",
"message": "Orders were updated"
}
]
}Этот вариант подходит, когда поведение интерфейса после /MetaMethods/Run должно зависеть от результата на сервере: например, нужно обновить изменившуюся панель или показать именно то сообщение, которое сформировал метод.
Действия после ответа из конфигурации
Используйте response.actions, когда дальнейшие действия известны заранее и их можно задать в JSON-конфигурации:
json
{
"request": {...},
"response": {
"actions": [
{
"method": "reloadEntities",
"panels": [{"panelId": "orders-table"}]
},
{
"method": "showNotification",
"severity": "success",
"message": "Method completed"
}
]
}
}Поддерживаемые действия после ответа:
reloadEntities
Обновляет данные панели после того, как метод изменил объекты. Если нужно перезагрузить конкретную панель, укажите её в panels:
json
{
"method": "reloadEntities",
"panels": [{"panelId": "orders-table"}]
}Без panels действие обновляет текущую панель. Панели-деревья могут также перезагрузить выбранный узел дерева через treeNodes:
json
{
"method": "reloadEntities",
"treeNodes": [
{
"getFromItem": true,
"reloadSelf": true,
"reloadChildren": true
}
]
}Когда действия после ответа выполнены, runMethod дополнительно делает свой обычный повторный запрос данных текущей панели. Используйте reloadEntities, когда нужно обновить другую панель или конкретный узел дерева.
showNotification
По умолчанию показывает локализованное всплывающее уведомление:
json
{
"method": "showNotification",
"severity": "success",
"summary": "Method completed",
"message": "Objects were updated",
"life": 5000
}Поддерживаемые поля:
message— обязательный текст сообщения или локализованная строка;severity—success,info,warnилиerror; по умолчаниюinfo;summary— необязательный заголовок всплывающего уведомления или модального окна;life— время показа всплывающего уведомления в миллисекундах; по умолчанию5000;mode—toastилиmodal; по умолчанию всплывающее уведомление;closeLabel— текст кнопки закрытия модального окна; по умолчаниюClose/Закрыть.
Задайте mode: "modal", если сообщение должно оставаться на экране, пока пользователь его не закроет:
json
{
"method": "showNotification",
"mode": "modal",
"severity": "info",
"summary": "Server message",
"message": "Review this result before continuing"
}Если среди действий после ответа — от сервера или из конфигурации — есть showNotification, runMethod не показывает своё стандартное уведомление об успехе, чтобы пользователь не видел повторных сообщений об успехе.
Файлы, которые возвращает метод
Метод может подготовить файл для пользователя, например отчёт с маршрутной картой. Токен этого временного файла метод возвращает в поле download:
json
[{"download": "sc_…"}]Настраивать ничего не нужно. Когда пользователь запускает метод, панель берёт из ответа каждый такой токен, запрашивает по нему файл (GET /files/scratch/{token}), и браузер сохраняет файл в папку загрузок. Имя файла берётся из заголовка Content-Disposition ответа сервера; если заголовка нет, файл сохраняется под именем download. Если панель обращается к API на другом домене, браузер показывает ей этот заголовок, только когда API разрешает это через Access-Control-Expose-Headers.
- Панель, которая читает свои данные через метод (
request.methodName), файлы не скачивает. - Токен действует 24 часа и только для пользователя, который запустил метод.
- Если файл скачать не удалось, результат выполнения метода не отменяется, а панель показывает сообщение «Метод выполнен, но его файл не скачан». Повторный запуск метода создаст новый файл, но выполнит и все действия метода ещё раз, например импорт.
editor.runMethodдействияcreateвозвращаемые файлы не скачивает.- Если запуск возвращает несколько файлов, браузер может попросить пользователя разрешить несколько загрузок со страницы.
downloadсодержит токен, а не URL. Старые ссылки видаfiles/download-tmp/<name>API больше не поддерживает.
Примеры
Пример 1: немедленный запуск
Запуск производства для выбранных заказов без формы.
json
{
"id": "start-production",
"method": "runMethod",
"label": "Start Production",
"icon": "pi pi-play",
"request": {
"parent": "ProductionOrder",
"methodName": "startProduction",
"objects": [
{"getFromItem": true}
]
}
}Пример 2: запуск с формой
Назначение заказов оператору с указанием приоритета.
json
{
"id": "assign-operator",
"method": "runMethod",
"label": "Assign to Operator",
"editor": {
"mode": "modal",
"header": {"title": "Assign Orders"},
"fields": [
{
"attribute": "operator",
"label": "Operator",
"type": "Object",
"propertyAsId": "itemId",
"required": true,
"selectPanel": {
"panel": {
"id": "operators-select",
"type": "table",
"request": {"metaTypeName": "Operator"}
}
}
},
{
"attribute": "priority",
"label": "Priority",
"type": "String",
"required": true
}
]
},
"request": {
"parent": "ProductionOrder",
"methodName": "assignOperator",
"objects": [{"getFromItem": true}]
}
}Пример 3: объекты из нескольких источников
Связывание заказов из двух разных панелей.
json
{
"id": "link-orders",
"method": "runMethod",
"label": "Link Orders",
"request": {
"parent": "OrderRelation",
"methodName": "createRelation",
"objects": [
{"getFromItem": true},
{"getSelectedObjectForPanelId": "related-orders-panel"}
]
}
}Результат: метод получает объекты из текущего выбора вместе с объектами, выбранными на боковой панели.
Пример 4: действие по событию
Запуск метода по нажатию на уведомление.
json
{
"id": "approve-from-notification",
"method": "runMethod",
"label": "Approve",
"request": {
"parent": "Approval",
"methodName": "approve",
"objects": [
{"getSelectedObjectForEventId": "approval-notification--on-click"}
]
}
}Пример 5: цепочка действий
Первое действие создаёт партию, второе запускает её.
Действие 1: создание партии
json
{
"id": "create-batch",
"method": "runMethod",
"label": "Create Batch",
"request": {
"parent": "ProductionBatch",
"methodName": "createBatch",
"objects": []
}
}Действие 2: запуск партии
json
{
"id": "start-batch",
"method": "runMethod",
"label": "Start Batch",
"request": {
"parent": "ProductionBatch",
"methodName": "startBatch",
"objects": [
{"getFromActionId": "create-batch"}
]
}
}Рекомендации
1. Для обычных действий используйте getFromItem
Большинство действий работает с элементами, которые выбрал пользователь:
json
{"objects": [{"getFromItem": true}]}2. При необходимости объединяйте несколько источников
json
{
"objects": [
{"getFromItem": true},
{"objectId": {"objectGuid": "config-object-id"}}
]
}3. Не добавляйте пустые формы
❌ Плохо:
json
{
"editor": {"mode": "modal", "fields": []},
"request": {...}
}✅ Хорошо:
json
{
"request": {...}
}4. Используйте действия после ответа
Объединяйте операции в цепочку, чтобы пользователю было удобнее:
json
{
"request": {...},
"response": {
"actions": [
{"method": "reloadEntities", "panels": [{"panelId": "main-table"}]},
{"method": "showNotification", "severity": "success", "message": "Success!"}
]
}
}Задайте mode: "modal", если пользователь должен закрыть сообщение сам:
json
{
"actions": [
{
"method": "showNotification",
"mode": "modal",
"severity": "info",
"summary": "Server message",
"message": "Read this message before continuing"
}
]
}5. Правильно выбирайте idSource
- Удаляете связи? Используйте
idSource: 'link'. - Обновляете объекты? Используйте
idSource: 'linkedObject'или не указывайте свойство: это значение по умолчанию.
Частые проблемы
Проблема: на сервер не передаются объекты
Признак: метод выполняется с пустым objects: [].
Причины:
- На панели не выбраны объекты.
- В
getSelectedObjectForPanelIdуказан неверный ID панели. - Не совпадает ID события.
- Действия с ID из
getFromActionIdне существует.
Решение:
- Проверьте, что пользователь выбрал элементы.
- Проверьте, что ID панелей совпадают в точности.
- Проверьте, что ID событий совпадают с конфигурацией панели.
Проблема: удалён не тот объект
Признак: удалён объект Supplier, а не связь между Product и Supplier.
Причина: не указан idSource: 'link'.
Решение:
json
{
"objects": [
{
"getFromItem": true,
"idSource": "link"
}
]
}Проблема: повторяющиеся объекты в запросе
Признак: один и тот же ID объекта встречается несколько раз.
Причина: несколько стратегий находят один и тот же объект.
Решение:
- Повторы удаляются автоматически.
- Просмотрите массив
objectsи уберите избыточные стратегии.
Проблема: цепочка действий не работает
Признак: предупреждение «failed to resolve from store».
Причины:
- Первое действие ещё не выполнялось.
- Первое действие уже завершилось, и его хранилище (store) освобождено.
- Опечатка в ID действия.
Решение:
- Проверьте порядок выполнения действий.
- Проверьте, что ID действий совпадают в точности.
- Проверьте, в какой момент хранилище создаётся и освобождается.