Skip to content

Actions & row actions

A view can carry toolbar actions (buttons above the grid), row actions (per-row buttons or menu items), a quick-search box, and pre-execute filters. This page covers all four, plus the CSP-safe dispatch envelope that lets server SQL drive the client.

<Actions>
<Action Name="ExportCsv" Icon="fa fa-file-csv" ExportHandler="Csv">exportTable('Customer');</Action>
</Actions>
<RowActions>
<Action Name="Deactivate" Icon="fa fa-ban" Color="warning" Confirm="Sure?" DisplayExpression="row.IsActive == true">
<Sql>UPDATE Sales.Customers SET IsActive = 0 WHERE Id = @Id;</Sql>
</Action>
<Action Name="AdjustCredit" Icon="fa fa-sliders">
<Sql>UPDATE Sales.Customers SET CreditLimit = @NewLimit WHERE Id = @Id;</Sql>
<Prompt Message="New credit limit" ConfirmLabel="Apply">
<Number Name="NewLimit" Label="New Credit Limit" Required="true" MinValue="0" />
</Prompt>
</Action>
<Action Name="Site" Icon="fa fa-globe" Url="{Website}" Target="_blank" DisplayColumn="Website" />
</RowActions>

A toolbar <Action> carries an OnClick script (element body), optional Icon, Confirm, ExportHandler. A row <Action> resolves its body by precedence <Sql> > Url (link) > OnClick/script, plus Name, Icon, Color, Confirm, Target, Permission, DisplayExpression/DisplayColumn (conditional visibility — see expressions), and an optional <Prompt> (Message, ConfirmLabel + editor fields collected before the action runs).

Dispatch callbacks (server-driven client actions)

Section titled “Dispatch callbacks (server-driven client actions)”

A <Sql> block (in a row action, submit, delete, or an RPC) can drive a client-side action instead of just returning a value. Return a result set whose first column is named FunctionName; the engine serializes each row into a CSP-safe Dispatch envelope ({ FunctionName, Param1, Param2, … }, positional in column order, SQL NULL → JS null) and the React UI runs each row through a closed registry — no eval, no inline JS. Multiple rows run in sequence (each awaited, so a workflow transition completes before a following refresh). Names must match ^[A-Za-z_][A-Za-z0-9_]*$.

-- Validation message that keeps the form/grid open:
SELECT 'showAlert' FunctionName, 'error', 'Invalid Work Package Dates',
'Each work package must stay within project start/end dates.';
-- Refresh the grid after a successful update:
UPDATE … ; SELECT 'refreshTable' FunctionName;

Supported FunctionName values and their positional params:

FunctionName Params Effect
refreshTable Reload the surrounding grid/record
showAlert severity, title, message Blocking dialog; severity = error/success/info/warning
showSuccess title, message Blocking success dialog
showError title, message Blocking error dialog
swal title, message, severity Legacy alias for showAlert (severity defaults to error)
closeModal Dismiss the surrounding modal
navigate url Same-origin redirect (internal routes navigate in-app; javascript: refused)
historyBack Browser back
openWindow url, target, features window.open (defaults _blank, noopener,noreferrer; javascript: refused)
transitionWorkflow instanceId, transitionLabel, returnUrl Advance a workflow instance, then navigate to returnUrl
workflowSubmitApproval instanceId, nodeKey, decision, comment Submit an approval decision, then refresh
startWorkflowsBatch definitionName, entityType, entityIdsJson, contextLabel, redirectUrl, initialDataJson Start a workflow per id (JSON array of ids), report, then redirect

The client registry lives in src/ui/genie-engine-ui/src/components/genieActions.ts; it is wired into every mutation handler so any <Sql> that returns this shape is dispatched automatically. The workflow functions integrate with Wizards & workflows.

Marking one or more columns Search="true" enables a search box in the table toolbar. On submit (Enter or the Search button) the typed term is applied server-side as a single LIKE '%term%' predicate OR-gated across all searchable columns, then AND-combined with any active column filters — e.g. (Name LIKE @t OR Email LIKE @t) AND Status = @s. The box appears only when the view declares at least one searchable column; the term itself is always parameterized and the searchable set is derived from the view config server-side (the client never picks the columns). SQL-backed views only.

<Filters Toggle="Collapsed"> <!-- Active | Collapsed -->
<Select Name="CustomerType" Label="Type"><DataSet Type="static"></DataSet></Select>
<Date Name="RegisteredFrom" Label="Registered from" />
</Filters>

Filter fields become @parameters available to <Sql> (guard with (@Param IS NULL OR …)). Children are editor fields (or <Filter Name="" Type="" /> shorthand); an optional <Layout> lays them out. Filter <Select>s use the same dataset system as editor fields.

Worked example: sample/Inventory/models/views/Products.view.xml — toolbar CSV export, row actions with <Sql> + a <Prompt> + refreshTable/showAlert dispatch, quick-search columns, and model/sql/static <Filters>.