Appearance
RunMethod User Guide
This guide is for users who configure runMethod actions through JSON configuration files.
Table of Contents
- What is RunMethod?
- Basic Configuration
- LinkEndpoint Strategies
- Understanding idSource
- Editor Configuration
- Response Actions
- Files Returned by the Method
- Usage Examples
- Best Practices
- Common Issues
What is RunMethod?
RunMethod allows you to execute backend metamethods from the UI. Users can:
- Select objects in tables/trees
- Optionally fill in a form (editor)
- Execute a backend method with the selected objects
- See the results (toast notifications, entity refreshes, etc.)
Basic Configuration
A runMethod action has three main parts:
json
{
"id": "action-id",
"method": "runMethod",
"label": "Button Label",
"icon": "icon-name",
"request": {
"parent": "MetaTypeName",
"methodName": "backendMethodName",
"objects": [/* LinkEndpoint strategies */]
},
"editor": {/* Optional form configuration */},
"response": {/* Optional actions after success */}
}Required Properties
request.parent: The metamodel type (e.g.,"ProductionOrder")request.methodName: The backend method to callrequest.objects: Array of LinkEndpoint strategies that determine which objects to pass
Optional Properties
editor: Form configuration for user input before executionresponse: Client-side actions to execute after success
LinkEndpoint Strategies
LinkEndpoints determine which objects are passed to the backend method. You can use 7 different strategies:
Strategy Overview
| Strategy | When to Use | Example |
|---|---|---|
objectId | Fixed object GUID | Config object, system settings |
getFromItem | User's selected items | Most common case |
getFromCreatedObject | Just-created object | ⚠️ Not yet supported |
getSelectedObjectForEventId | Object from event | Notification clicks |
selectPanel | User picks from modal | Choose supplier, operator |
getSelectedObjectForPanelId | Objects from another panel | Multi-panel workflows |
getFromActionId | Objects from another action | Action chaining |
1. objectId
Use a hardcoded object GUID.
json
{
"objects": [
{
"objectId": {
"objectGuid": "123e4567-e89b-12d3-a456-426614174000"
}
}
]
}When to use: Configuration objects, system settings, or any fixed reference.
2. getFromItem
Use the objects the user has selected in the table/tree.
json
{
"objects": [
{
"getFromItem": true
}
]
}When to use: This is the most common strategy. Use it when the action operates on user-selected rows/nodes.
User flow:
- User selects 1+ items in table/tree
- User clicks the action button
- Method executes with selected object IDs
3. getFromCreatedObject
⚠️ Not yet supported for runMethod
Intended for chaining: create → link → runMethod.
4. getSelectedObjectForEventId
Get the object that triggered a specific event.
json
{
"objects": [
{
"getSelectedObjectForEventId": "notification--on-click"
}
]
}When to use: Event-triggered actions like notification clicks, auto-triggers.
5. selectPanel
Open a modal panel for the user to select an object.
json
{
"objects": [
{
"selectPanel": {
"panel": {
"id": "supplier-select",
"type": "table",
"request": {
"metaTypeName": "Supplier"
},
"columns": [
{"attribute": "name", "label": "Supplier Name"}
]
}
}
}
]
}When to use: When the target object is not predetermined (e.g., "Assign to Operator", "Link to Supplier").
User flow:
- User clicks action
- Modal opens with a table/tree
- User selects object(s) from modal
- Method executes with selected object
6. getSelectedObjectForPanelId
Get all currently selected objects from a specific panel by its ID.
json
{
"objects": [
{
"getSelectedObjectForPanelId": "sidebar-panel-id"
}
]
}When to use: Multi-panel workflows where you need objects from a different panel.
Difference from selectPanel:
selectPanel: Opens a modal for selectiongetSelectedObjectForPanelId: Uses existing panel's current selection
7. getFromActionId
Get object IDs from another action's context (action chaining).
json
{
"objects": [
{
"getFromActionId": "create-batch-action"
}
]
}When to use: Chaining actions where the first action creates/modifies objects and the second processes them.
Example: Create batch → Start batch production
Understanding idSource
When working with linked objects, each selection contains two GUIDs:
link.objectGuid- The link entity ID (the relationship)linkedObject.objectGuid- The target object ID
The idSource property lets you choose which one to use.
When to Use Each Option
Use idSource: 'link' when:
- Deleting link entities
- Operating on the relationship itself
- Methods that expect link GUIDs
Use idSource: 'linkedObject' (default) when:
- Operating on the linked object's data
- Most standard CRUD operations
- Methods that expect object GUIDs
Examples
Delete a link (keep both objects):
json
{
"request": {
"parent": "Link",
"methodName": "deleteLink",
"objects": [
{
"getFromItem": true,
"idSource": "link"
}
]
}
}Update linked object data:
json
{
"request": {
"parent": "Product",
"methodName": "updatePrice",
"objects": [
{
"getFromItem": true,
"idSource": "linkedObject"
}
]
}
}Omit idSource (defaults to linkedObject):
json
{
"objects": [
{"getFromItem": true}
]
}Which Strategies Support idSource?
- ✅
getFromItem - ✅
getFromCreatedObject - ✅
getSelectedObjectForEventId - ✅
selectPanel - ✅
getSelectedObjectForPanelId - ❌
getFromActionId(returns already-resolved IDs) - ❌
objectId(you control the GUID directly)
Real-World Scenario
Problem: Delete a Product-Supplier link without deleting the Product or Supplier.
Solution:
json
{
"id": "remove-supplier-link",
"method": "runMethod",
"label": "Remove Supplier",
"request": {
"parent": "Link",
"methodName": "deleteLink",
"objects": [
{
"getFromItem": true,
"idSource": "link"
}
]
}
}Without idSource: 'link', it would try to delete the Supplier object instead of the link!
Editor Configuration
The editor property adds a form before executing the method.
Without Editor (Direct Execution)
json
{
"method": "runMethod",
"request": {
"parent": "ProductionOrder",
"methodName": "startProduction",
"objects": [{"getFromItem": true}]
}
}User flow: User clicks → Method executes immediately
Direct execution is selected when the editor property is omitted. An editor with an empty fields array is still an editor and opens the modal, so omit the property entirely for methods that do not require input.
With Editor (Form Before Execution)
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}]
}
}User flow: User clicks → Modal opens → User fills form → Submits → Method executes
File for the Method
Use "control": "scratchFile" when the method needs a file from the user, for example an import spreadsheet:
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 and materialImport are illustrative: use a method of your API that reads the token from the parameter named by attribute.
The field shows a Choose file button. The user chooses one file of up to 256 MiB; the form rejects a larger file at once and asks for a smaller one. Choosing the file sends nothing yet.
When the user submits the form, the panel first uploads the file to the temporary file storage (POST /files/scratch) and receives a token such as sc_…. It then calls the method and passes that token as a string parameter named after the field's attribute, here params.scratchToken. The backend method reads the file by this token. The token is valid for 24 hours and only for the user who uploaded the file. The file never becomes a dataset.
attributemust be the parameter name that the backend method expects.typemust be set explicitly toString: the method receives a token, not the file.defaultValueis not allowed: only the user chooses the file.- Without a chosen file the request contains no such parameter.
requiredis not enforced, as for other fields. - If the upload fails, the panel shows “The file was not uploaded; the method did not run”; for a
413answer it adds that the file is larger than 256 MiB. The method does not run, and the form stays open with the chosen values. - If the user closes the form while the file is uploading, the method does not run.
- Cancel uploads nothing.
scratchFile works only in the editor of a runMethod action. Every other case is a configuration error: the field in another editor — create, update, http, the attributes editor or the editor.runMethod of a create action; scratchFile without an explicit "type": "String" or with a defaultValue; any other control value, an empty one included. The field then shows the error, for example “Configuration error: file selection (control "scratchFile") works only in a method run form. The action does not run”, and the form is not submitted: the action would otherwise run without the value its configuration expects. Hidden fields and fields on other tabs are checked too: their errors appear in a notification when the user submits the form. Fix the editor JSON to make the action usable.
A runMethod action in attributes.panelActions runs without its editor, so it cannot fill the field: when its editor has a field with control, the action does not run and the same notification names the field. The same applies to create with editor.mode: "direct-request", to http without its modal editor, and to a runMethod that runs when a BPMN node is created without its form or deleted.
On the Action input tab, press Action input: file → file, choose any file, and press Submit. The fixture method receives the token, and the browser saves round-trip-report.txt with the name and size of the chosen file. Without a file, the report says that no file was received.
Response Actions
Execute additional actions after the method succeeds. runMethod supports response actions from two places:
- the
/MetaMethods/Runresponse, when the backend returns anactionsarray - the JSON action configuration, through
response.actions
Both sources use the same action processor. Backend actions run first, then client-configured actions run. If the method was executed for selected objects, each response action runs once per resolved object; if there are no resolved objects, response actions run once in the current panel context.
Server Response Actions
A backend method can return one response object or an array of response objects. Each response object may include actions:
json
{
"actions": [
{
"method": "reloadEntities",
"panels": [{"panelId": "orders-table"}]
},
{
"method": "showNotification",
"severity": "success",
"message": "Orders were updated"
}
]
}Use this when the backend result should decide what the UI does after /MetaMethods/Run, for example refreshing a panel that changed or showing the exact message produced by the method.
Client-Side Response Actions
Use response.actions when the follow-up behavior is known from the JSON configuration:
json
{
"request": {...},
"response": {
"actions": [
{
"method": "reloadEntities",
"panels": [{"panelId": "orders-table"}]
},
{
"method": "showNotification",
"severity": "success",
"message": "Method completed"
}
]
}
}Supported response actions:
reloadEntities
Refreshes panel data after a method changes objects. Configure panels when a specific panel must reload:
json
{
"method": "reloadEntities",
"panels": [{"panelId": "orders-table"}]
}If panels is omitted, the current panel is refreshed. Tree panels can also reload a selected tree node through treeNodes:
json
{
"method": "reloadEntities",
"treeNodes": [
{
"getFromItem": true,
"reloadSelf": true,
"reloadChildren": true
}
]
}After response actions finish, runMethod also performs its normal current-panel refetch. Use reloadEntities when another panel or a specific tree node must refresh.
showNotification
Shows a localized toast by default:
json
{
"method": "showNotification",
"severity": "success",
"summary": "Method completed",
"message": "Objects were updated",
"life": 5000
}Supported fields:
message: required message text or localized stringseverity:success,info,warn, orerror; default isinfosummary: optional toast header or modal titlelife: toast lifetime in milliseconds; default is5000mode:toastormodal; default is a toastcloseLabel: modal close button text; default isClose/Закрыть
Use mode: "modal" when the message must stay visible until the user closes it:
json
{
"method": "showNotification",
"mode": "modal",
"severity": "info",
"summary": "Server message",
"message": "Review this result before continuing"
}When either server or client response actions include showNotification, runMethod suppresses its generic success toast so users do not see duplicate success messages.
Files Returned by the Method
A method can prepare a file for the user, for example a route card report. It returns the token of that temporary file in the download field:
json
[{"download": "sc_…"}]No configuration is needed. After a user starts the method, the panel takes every such token from the response, requests its file with GET /files/scratch/{token}, and the browser saves the file to its downloads folder. The file name comes from the server's Content-Disposition header; without it the file is saved as download. When the panel calls the API on another origin, the browser shows this header to the panel only if the API allows it with Access-Control-Expose-Headers.
- A panel that reads its data through a method (
request.methodName) does not download files. - The token is valid for 24 hours and only for the user who ran the method.
- If a file cannot be downloaded, the method result stays as it is and the panel shows “The method ran, but its file was not downloaded”. Running the method again creates a new file, but it also repeats everything the method does, for example an import.
- The
editor.runMethodof acreateaction does not download returned files. - When a run returns several files, the browser may ask the user to allow several downloads from the page.
downloadholds a token, not a URL. The oldfiles/download-tmp/<name>links are no longer supported by the API.
Usage Examples
Example 1: Simple Direct Execution
Start production for selected orders (no form).
json
{
"id": "start-production",
"method": "runMethod",
"label": "Start Production",
"icon": "pi pi-play",
"request": {
"parent": "ProductionOrder",
"methodName": "startProduction",
"objects": [
{"getFromItem": true}
]
}
}Example 2: With Form Editor
Assign orders to an operator with priority.
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}]
}
}Example 3: Multi-Source Objects
Link orders from two different panels.
json
{
"id": "link-orders",
"method": "runMethod",
"label": "Link Orders",
"request": {
"parent": "OrderRelation",
"methodName": "createRelation",
"objects": [
{"getFromItem": true},
{"getSelectedObjectForPanelId": "related-orders-panel"}
]
}
}Result: Combines objects from current selection + sidebar panel selection.
Example 4: Event-Triggered Action
Run method from a notification click.
json
{
"id": "approve-from-notification",
"method": "runMethod",
"label": "Approve",
"request": {
"parent": "Approval",
"methodName": "approve",
"objects": [
{"getSelectedObjectForEventId": "approval-notification--on-click"}
]
}
}Example 5: Action Chaining
First action creates a batch, second action starts it.
Action 1: Create Batch
json
{
"id": "create-batch",
"method": "runMethod",
"label": "Create Batch",
"request": {
"parent": "ProductionBatch",
"methodName": "createBatch",
"objects": []
}
}Action 2: Start Batch
json
{
"id": "start-batch",
"method": "runMethod",
"label": "Start Batch",
"request": {
"parent": "ProductionBatch",
"methodName": "startBatch",
"objects": [
{"getFromActionId": "create-batch"}
]
}
}Best Practices
1. Use getFromItem for Standard Actions
Most actions operate on user-selected items:
json
{"objects": [{"getFromItem": true}]}2. Combine Multiple Sources When Needed
json
{
"objects": [
{"getFromItem": true},
{"objectId": {"objectGuid": "config-object-id"}}
]
}3. Don't Add Empty Editors
❌ Bad:
json
{
"editor": {"mode": "modal", "fields": []},
"request": {...}
}✅ Good:
json
{
"request": {...}
}4. Leverage Response Actions
Chain operations for better UX:
json
{
"request": {...},
"response": {
"actions": [
{"method": "reloadEntities", "panels": [{"panelId": "main-table"}]},
{"method": "showNotification", "severity": "success", "message": "Success!"}
]
}
}Use mode: "modal" when the user must close the message explicitly:
json
{
"actions": [
{
"method": "showNotification",
"mode": "modal",
"severity": "info",
"summary": "Server message",
"message": "Read this message before continuing"
}
]
}5. Use idSource Correctly
- Deleting links? Use
idSource: 'link' - Updating objects? Use
idSource: 'linkedObject'or omit (default)
Common Issues
Issue: No Objects Sent to Backend
Symptom: Method executes with empty objects: []
Causes:
- No objects selected in panel
- Wrong panel ID in
getSelectedObjectForPanelId - Event ID doesn't match
- Action ID doesn't exist in
getFromActionId
Solution:
- Verify user has selected items
- Check panel IDs match exactly
- Verify event IDs match panel configuration
Issue: Wrong Object Deleted
Symptom: Deleted the Supplier instead of the Product-Supplier link
Cause: Missing idSource: 'link'
Solution:
json
{
"objects": [
{
"getFromItem": true,
"idSource": "link"
}
]
}Issue: Duplicate Objects in Request
Symptom: Same object ID appears multiple times
Cause: Multiple strategies resolve to the same object
Solution:
- Deduplication happens automatically
- Review your
objectsarray to avoid redundant strategies
Issue: Action Chain Broken
Symptom: Warning "failed to resolve from store"
Causes:
- First action hasn't run yet
- First action already completed and store disposed
- Action ID typo
Solution:
- Ensure correct action execution order
- Check action IDs match exactly
- Verify store lifecycle timing