Skip to content

RunMethod User Guide ​

This guide is for users who configure runMethod actions through JSON configuration files.

Table of Contents ​

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 call
  • request.objects: Array of LinkEndpoint strategies that determine which objects to pass

Optional Properties ​

  • editor: Form configuration for user input before execution
  • response: 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 ​

StrategyWhen to UseExample
objectIdFixed object GUIDConfig object, system settings
getFromItemUser's selected itemsMost common case
getFromCreatedObjectJust-created object⚠️ Not yet supported
getSelectedObjectForEventIdObject from eventNotification clicks
selectPanelUser picks from modalChoose supplier, operator
getSelectedObjectForPanelIdObjects from another panelMulti-panel workflows
getFromActionIdObjects from another actionAction 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:

  1. User selects 1+ items in table/tree
  2. User clicks the action button
  3. 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:

  1. User clicks action
  2. Modal opens with a table/tree
  3. User selects object(s) from modal
  4. 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 selection
  • getSelectedObjectForPanelId: 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.

  • attribute must be the parameter name that the backend method expects.
  • type must be set explicitly to String: the method receives a token, not the file.
  • defaultValue is not allowed: only the user chooses the file.
  • Without a chosen file the request contains no such parameter. required is 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 413 answer 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.

Open the file round trip demo

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/Run response, when the backend returns an actions array
  • 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 string
  • severity: success, info, warn, or error; default is info
  • summary: optional toast header or modal title
  • life: toast lifetime in milliseconds; default is 5000
  • mode: toast or modal; default is a toast
  • closeLabel: modal close button text; default is Close / Закрыть

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.runMethod of a create action does not download returned files.
  • When a run returns several files, the browser may ask the user to allow several downloads from the page.
  • download holds a token, not a URL. The old files/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:

  1. No objects selected in panel
  2. Wrong panel ID in getSelectedObjectForPanelId
  3. Event ID doesn't match
  4. 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 objects array to avoid redundant strategies

Issue: Action Chain Broken ​

Symptom: Warning "failed to resolve from store"

Causes:

  1. First action hasn't run yet
  2. First action already completed and store disposed
  3. Action ID typo

Solution:

  • Ensure correct action execution order
  • Check action IDs match exactly
  • Verify store lifecycle timing