How to configure a «List by API» (ActionJail) field?
The List by API type loads dropdown options from an ActionJail action while the operator edits a record. Use it when values are dynamic (operators, stores, an external catalog) and do not fit a static List.
When you need this
- You need a dropdown backed by changing data (users, external statuses, API catalog).
- A static List is not enough — too many values or they update automatically.
- System types (User, Subject, …) do not fit — you need a custom jail action.
What to know
| Editor setting | Purpose |
|---|---|
| ActionJail action | Technical action name (action_…) that returns the list |
List label field (label_key) |
Property on each item: both the dropdown label and the value saved in the field after selection |
Where the dropdown works today
- client fields in the operator dialog;
- dynamic fields in operator forms (Table view, OperatorLine);
- not in the record table or record side card yet — value is shown as plain text until list selection is wired there (planned).
When to pick another type
- fixed enum → List;
- link to another Custom Data table → Table link;
- platform user / subject / tag → System types.
Before you start
Step 1. Create an ActionJail action
- Open ActionJail → Create action (or edit an existing one).
- Set the technical name — the same name you will pick in the field config (e.g.
action_list_storesoraj_list_operators). - In the action body:
- read request params from constants:
query(search),limit,offset— passed by the platform when the list opens; - build an array of items;
- store the result as
{ rows, count }inresult; - return
'success'.
- read request params from constants:
Response contract
this.setCurrentStateConstant('result', {
rows: [
{ id: 1, label: 'Kyiv — Center' },
{ id: 2, label: 'Lviv — Main' },
],
count: 2,
});
Each rows item is an object. It must include a property whose name matches List label field (commonly label, name, or title). To store an ID, set label_key to id — the cell will receive the selected row's id.
Minimal action example
const appPath = process.cwd();
const OpModels = require(appPath + '/modules/extra/operator_panel/db/models');
async function action_list_active_operators() {
const state = await this.getCurrentStateJSON();
const query = String(state?.const?.query || '').trim();
const limit = Number(state?.const?.limit) || 20;
const offset = Number(state?.const?.offset) || 0;
const where = { active: true };
const rows = await OpModels.OpUsers.findAll({
where,
attributes: [ 'id', 'first_name', 'last_name' ],
limit,
offset,
raw: true,
});
const formatted = rows.map((row) => ({
id: row.id,
label: [ row.first_name, row.last_name ].filter(Boolean).join(' '),
}));
this.setCurrentStateConstant('result', {
rows: formatted,
count: formatted.length,
});
return 'success';
}
module.exports = action_list_active_operators;
The platform calls the action via GET /kw/tickets/custom_list/<action_name> with query, limit, offset.
Step 2. Configure the field in Custom Data
- In the model editor Fields tab, choose List by API.
- In List source:
- ActionJail action — your action from step 1;
- List label field — key for label and stored value (
label,id,name, …).
- Save the model.
In columns_json:
"store_ref": {
"type": "STRING",
"label": "Store",
"select_api_action": {
"name": "action_list_stores",
"label_key": "label"
}
}
Step 3. Verify
- Open an operator form where the field is shown (not the data table if the dropdown is not wired there yet).
- Open the list — rows from the action should appear.
- Select a value and save — the database should contain the property named in
label_key. - If the list is empty — check action name, ActionJail logs, and that
result.rowsis non-empty.
Common issues
| Symptom | What to check |
|---|---|
| Empty list | Field action name matches ActionJail; action returns success and result.rows |
Labels show undefined |
Each row includes the label_key property |
| Wrong stored value | label_key controls both label and stored value — use id for IDs |
| Plain text in data table | Expected; dropdown is in operator forms |