Actions and lifecycle
A screen with a grid and a dialog covers the standard read and write flow. Actions and lifecycle hooks add everything else: run a query from a button, open another view from a row, call an API or a plugin after a save, refresh the grid after a delete.
They are set in the Actions and Row menu tabs of the screen editor, with the same action shapes everywhere.
Where actions fire
| Group | Lists | When they fire | source reads from |
|---|---|---|---|
| Dialog hooks | on_load | Once the dialog has loaded the row (edit) or seeded the defaults (add). | The form. |
on_save | After the dialog's main insert or update succeeds. | The form at save time. | |
on_cancel | When the dialog is closed without saving, before it closes; an error keeps it open. | The form. | |
| Toolbar | actions | Each entry is a button above the grid. | No row context; prompt values under INPUT.<name>. |
| Row hooks | on_insert, on_update, on_delete | After the write succeeds — from the dialog or from grid editing. | The new row, or the deleted row. |
on_duplicate | When a row duplicated with the dialog's Duplicate is saved, instead of on_insert. | The new row, and the source row under SOURCE_<column>. | |
| Row menu (own tab) | row_menu | Each entry is a menu item on a row: right-click, or the ⋯ handle at the start of the row. | The clicked row. |
Hooks run their list in order and stop at the first error, unless an action has stop_on_error off. A toolbar or row-menu entry runs as one action: to run several steps from one button, use a chain.
For a left click on a row, use the row-click settings of the General tab (row_click_screen with row_click_binds, or row_click_route).
Action types
Every action has an id (unique in its list, also its key in a chain's context), a label (button caption) and stop_on_error.
| Type | What it does | Main fields |
|---|---|---|
run_query | Runs a query of a connector, read or write. | connector, query, param_binds, bind_result |
call_api | Calls an endpoint of an API connector. | connector, endpoint, param_binds, bind_result |
call_plugin | Calls a server-side Python function (module:function), the same entry points Nomaflow runs as steps. | callable, param_binds, bind_result |
call_action | Runs a shared action by its id. | ref, param_binds |
navigate | Opens another view: a screen (screen) or a query (to), with param_binds passed as its parameters. | connector, screen or to, param_binds |
open_url | Opens an external address — another application on the row's record. | url, new_tab |
set_field | Writes a value into a form field. | target, value or source |
confirm | Asks for confirmation; Cancel stops the chain. The message is filled like an open_url template ({COLUMN}, {INPUT.x}, built-ins), not encoded: Reset the password of {INPUT.user} on #POOL#?. | message, confirm_label, cancel_label |
notify | Shows a message, filled the same way. | message, tone (info / ok / warn / error) |
send_notification | Fires a notification rule of type action (e-mail, portal…). | rule, param_binds |
refresh | Reloads the grid. | — |
bind_result keeps the rows (or the response) of the step in the chain's context, so that a later step reads them with source = "<id>.first_row.<COLUMN>".
Open an external address
An open_url action opens another application on the record at hand — the JD Edwards form of an address book entry, a ticket in a help desk. It can sit in a row menu, on the toolbar, in a dialog tab, behind a drill column or in a chain, and can ask for values first.
urlis a template:{COLUMN}takes the value of a column of the row, a field of the form, a value asked for, or a step of the chain —{step.first_row.X}—, encoded for an address;#LOGIN_USER#and the other built-ins are filled too.https://helpdesk.example.com/tickets?customer={CUSTOMER_ID}.- An address that differs from one install to the next is written
#URL.NAME#at the start:#URL.JDE_WEB#/ShortcutLauncher?OID=P01012_W01012A&…. Each install sets the address once, in App → External addresses; without it, the action opens nothing. new_tab: on by default; off, the address replaces the page.
Only http://, https:// addresses and paths of this server are opened; anything else is refused when the configuration loads, and checked again on the filled address. A row menu whose only action is an open_url fires it from the row handle.
The row handle and drill-downs
A screen with row-menu actions shows a small handle at the start of every row, so the actions stay in reach on a wide table:
- with several actions, the handle (⋯, Row actions) opens the same menu as the right-click;
- with a single
navigateaction, the handle (a return arrow) fires it at once — its tooltip is the action's label.
Link cells. A column's drill setting (Liberty Next → Build → Screens, column, Display) names a navigate action of the row menu: the value shows as a link that fires it for the row — the customer code opens the customer, with no menu to open. A screen whose row menu holds a single navigate action does it by itself on its first key column. A wrong action name is refused when the configuration loads.
Where the target opens. By default, a navigate action opens its target in a new tab. With Drill-downs open inside the current tab in Liberty Next → Administer → App, it opens as a panel inside the current tab, over the grid: a breadcrumb names each level, Back returns to the one before, and the grid behind keeps its rows and filters. A drill from the panel nests the same way. An action decides for itself with inline = true (panel) or inline = false (new tab), set in screens.toml.
Composite types
| Type | What it does |
|---|---|
chain | A list of steps run in order, sharing one context. |
if | Runs then_steps or else_steps depending on a condition: a source, an operator (equals, not_equals, has_rows, no_rows, truthy, falsy, greater_than, less_than) and a value. |
loop | Runs steps once per item of a list taken from the context (typically the rows of an earlier step). |
return | Copies values of the context back into the form's fields — at the end of a chain, to show computed values. |
Wrap in chain puts an existing action inside a chain, to add steps around it.
Values passed to an action
run_query, call_api, call_plugin, call_action, navigate and send_notification take a list of param_binds: for each parameter of the target, a fixed value, or a source read at call time — a column of the row, a form field, INPUT.<name>, <step>.first_row.<COLUMN>, or a built-in such as #LOGIN_USER# / #SYSDATE# — with an optional default. See Parameter binding.
Prompt before running
run_query, call_api, call_plugin, call_action, navigate and chain can open a small form before they run:
| Field | Role |
|---|---|
| prompt_fields | The inputs to ask for — each with its name, label, dictionary entry, default, required / hidden / read-only flags and conditions. |
| prompt_title (and its translations) | The window's title; defaults to the action's label. |
| prompt_cols | Number of columns of the form (2 by default). |
The values entered are available as INPUT.<name> to the action and to every later step of the same chain. Cancel stops the chain without an error.
Shared actions
An action used by several screens is defined once in Liberty Next → Build → Actions: an id, a label, a description, declared params, optional prompt_fields, and its steps (the same action types). The page lists the shared actions with Find usages, Clone and Delete; a row opens the action designer.
A screen runs it with call_action: ref names the shared action, and its param_binds fill the action's INPUT.<param> values.
Examples
Recompute, then reload the grid
[[screens.crm.customers.actions]]
type = "chain"
id = "recompute"
label = "Recompute balances"
steps = [
{ type = "run_query", id = "compute", connector = "crm", query = "compute_balances" },
{ type = "refresh", id = "reload" },
{ type = "notify", id = "done", message = "Balances recomputed.", tone = "ok" },
]
Confirm before deleting
[[screens.crm.customers.row_menu]]
type = "chain"
id = "delete_customer"
label = "Delete customer"
steps = [
{ type = "confirm", id = "ask", message = "Delete this customer and its deals?", confirm_label = "Delete" },
{ type = "run_query", id = "delete", connector = "crm", query = "customers_delete",
param_binds = [{ param = "CUSTOMER_ID", source = "CUSTOMER_ID" }] },
{ type = "refresh", id = "reload" },
]
Cancel on the confirmation stops the chain: nothing is deleted.
Open the deals of a customer
[[screens.crm.customers.row_menu]]
type = "navigate"
id = "view_deals"
label = "View deals"
connector = "crm"
screen = "deals"
param_binds = [{ param = "CUSTOMER_ID", source = "CUSTOMER_ID" }]
The deals screen opens with its filters seeded from the binds.
Stamp audit columns
For CREATED_BY / CREATED_AT columns, no hook is needed: the dictionary rules LOGIN and SYSDATE, or the {{LOGIN}} / {{SYSTIMESTAMP}} tokens in the insert query, fill them on the server — see Dictionary → Rules. To log every write in a history table, set audit_table on the General tab.
Saving
The Actions and Row menu tabs edit the screen's lists; the screen editor's Save writes them with the rest of the screen and reloads the configuration — the next click runs the new version.
Common pitfalls
| Mistake | Symptom | Fix |
|---|---|---|
| Two toolbar entries meant to run one after the other. | They are two separate buttons. | Put the steps in one chain. |
A toolbar action reading source = "CUSTOMER_ID". | The toolbar has no row: the value is empty. | Move the action to the row menu, or ask for the value with a prompt (INPUT.CUSTOMER_ID). |
confirm placed after the delete. | The question comes once the row is gone. | confirm first in the chain. |
A step reads <id>.first_row.X from a step without bind_result. | The value is empty. | Turn on bind_result on the step that produces the rows. |
value = "#LOGIN_USER#". | The text is written as it is. | Use source. |
What's next
- Nested tabs — embed another screen's form or grid in a dialog tab.
- Parameter binding —
param_binds, built-ins and tokens. - Notifications — the rules a
send_notificationfires.