Skip to content

Руководство по действию runMethod ​

Руководство описывает, как настроить действия runMethod в JSON-файлах конфигурации.

Содержание ​

Что такое 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
    }
  ]
}

Когда использовать: это самая распространённая стратегия. Используйте её, когда действие работает со строками или узлами, выбранными пользователем.

Как это выглядит для пользователя:

  1. Пользователь выбирает один или несколько элементов в таблице или дереве.
  2. Нажимает кнопку действия.
  3. Метод выполняется с 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».

Как это выглядит для пользователя:

  1. Пользователь нажимает кнопку действия.
  2. Панель открывает модальное окно с таблицей или деревом.
  3. Пользователь выбирает в нём объект или объекты.
  4. Метод выполняется с выбранным объектом.

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: [].

Причины:

  1. На панели не выбраны объекты.
  2. В getSelectedObjectForPanelId указан неверный ID панели.
  3. Не совпадает ID события.
  4. Действия с ID из getFromActionId не существует.

Решение:

  • Проверьте, что пользователь выбрал элементы.
  • Проверьте, что ID панелей совпадают в точности.
  • Проверьте, что ID событий совпадают с конфигурацией панели.

Проблема: удалён не тот объект ​

Признак: удалён объект Supplier, а не связь между Product и Supplier.

Причина: не указан idSource: 'link'.

Решение:

json
{
  "objects": [
    {
      "getFromItem": true,
      "idSource": "link"
    }
  ]
}

Проблема: повторяющиеся объекты в запросе ​

Признак: один и тот же ID объекта встречается несколько раз.

Причина: несколько стратегий находят один и тот же объект.

Решение:

  • Повторы удаляются автоматически.
  • Просмотрите массив objects и уберите избыточные стратегии.

Проблема: цепочка действий не работает ​

Признак: предупреждение «failed to resolve from store».

Причины:

  1. Первое действие ещё не выполнялось.
  2. Первое действие уже завершилось, и его хранилище (store) освобождено.
  3. Опечатка в ID действия.

Решение:

  • Проверьте порядок выполнения действий.
  • Проверьте, что ID действий совпадают в точности.
  • Проверьте, в какой момент хранилище создаётся и освобождается.