Skip to main content

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​

Screen Designer · crm.customers · ActionsDIALOG HOOKS — fire while the form is openon_loadRuns right after the row's data is loaded — useful for refreshing a lookup or prefetching related rows.on_saveRuns after the dialog's main update/insert succeeds — chain extra writes on the same row.TOOLBAR — buttons above the tableactionsRun without row context — a prompt can ask the user for values first.+ Add toolbar actionROW HOOKS — fire after a row is mutatedon_insertAfter a row is inserted (dialog Save or inline grid Save).on_update · on_deleteAfter an edit / a delete. ParamBinds resolve against the new / deleted row's values.
GroupListsWhen they firesource reads from
Dialog hookson_loadOnce the dialog has loaded the row (edit) or seeded the defaults (add).The form.
on_saveAfter the dialog's main insert or update succeeds.The form at save time.
on_cancelWhen the dialog is closed without saving, before it closes; an error keeps it open.The form.
ToolbaractionsEach entry is a button above the grid.No row context; prompt values under INPUT.<name>.
Row hookson_insert, on_update, on_deleteAfter the write succeeds — from the dialog or from grid editing.The new row, or the deleted row.
on_duplicateWhen 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_menuEach 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.

TypeWhat it doesMain fields
run_queryRuns a query of a connector, read or write.connector, query, param_binds, bind_result
call_apiCalls an endpoint of an API connector.connector, endpoint, param_binds, bind_result
call_pluginCalls a server-side Python function (module:function), the same entry points Nomaflow runs as steps.callable, param_binds, bind_result
call_actionRuns a shared action by its id.ref, param_binds
navigateOpens another view: a screen (screen) or a query (to), with param_binds passed as its parameters.connector, screen or to, param_binds
open_urlOpens an external address — another application on the row's record.url, new_tab
set_fieldWrites a value into a form field.target, value or source
confirmAsks 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
notifyShows a message, filled the same way.message, tone (info / ok / warn / error)
send_notificationFires a notification rule of type action (e-mail, portal…).rule, param_binds
refreshReloads 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.

  • url is 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 navigate action, 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​

TypeWhat it does
chainA list of steps run in order, sharing one context.
ifRuns 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.
loopRuns steps once per item of a list taken from the context (typically the rows of an earlier step).
returnCopies 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:

FieldRole
prompt_fieldsThe 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_colsNumber 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​

MistakeSymptomFix
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​