|
1 | 1 | --- |
2 | 2 | title: Action Triggers |
3 | | -description: The client-side interaction protocol. Handling clicks, navigation, and API calls via JSON events. |
| 3 | +description: How user interactions trigger Server-Side logic or Client-Side transitions. |
4 | 4 | --- |
5 | 5 |
|
| 6 | +Actions are the verbs of the system (Save, Submit, Approve). |
6 | 7 |
|
7 | | -In ObjectUI, interactivity is defined by **Actions**, not functions. |
| 8 | +## 1. Action Types |
8 | 9 |
|
9 | | -Because the UI Definition must be strictly serializable (JSON), we cannot pass JavaScript functions like `onClick={() => alert('Hello')}`. Instead, we declare **Action Objects** that the ObjectUI Runtime Engine interprets and executes. |
| 10 | +### Standard Actions |
| 11 | +Built-in CRUD operations. |
| 12 | +* `standard_new` |
| 13 | +* `standard_edit` |
| 14 | +* `standard_delete` |
10 | 15 |
|
11 | | -## 1. The Action Protocol |
| 16 | +### Flow Actions |
| 17 | +Launches a Screen Flow (Wizard). |
| 18 | +* **Target:** `flow:approval_wizard` |
| 19 | +* **Input:** Passes current `recordId`. |
12 | 20 |
|
13 | | -An Action is a JSON object describing *what* should happen. Events like `onClick` or `onSuccess` accept either a single Action or an **Chain of Actions** (Array). |
| 21 | +### API Actions |
| 22 | +Calls a REST endpoint directly. |
| 23 | +* **Target:** `api:sync_with_erp` |
| 24 | +* **Feedback:** Shows toast message on success/failure. |
14 | 25 |
|
15 | | -### Basic Structure |
| 26 | +### URL Actions |
| 27 | +Navigates to an external link. |
| 28 | +* **Target:** `url:https://google.com?q={name}` |
16 | 29 |
|
17 | | -```typescript |
18 | | -interface ActionDef { |
19 | | - /** The operation identifier */ |
20 | | - action: string; |
21 | | - |
22 | | - /** Arguments for the operation */ |
23 | | - params?: Record<string, any>; |
24 | | - |
25 | | - /** Ask for user confirmation before executing */ |
26 | | - confirm?: { |
27 | | - title: string; |
28 | | - message: string; |
29 | | - variant?: 'danger' | 'info'; |
30 | | - }; |
31 | | - |
32 | | - /** Condition to execute (Expression) */ |
33 | | - when?: string; |
34 | | -} |
| 30 | +## 2. Parameter Mapping |
| 31 | +You can map context data to action parameters. |
35 | 32 |
|
| 33 | +```yaml |
| 34 | +actions: |
| 35 | + - name: google_search |
| 36 | + label: Search on Google |
| 37 | + type: url |
| 38 | + url: "https://google.com/search?q={name}" |
36 | 39 | ``` |
37 | | - |
38 | | -### Example: A Delete Button |
39 | | - |
40 | | -```json |
41 | | -{ |
42 | | - "type": "button", |
43 | | - "props": { |
44 | | - "label": "Delete Project", |
45 | | - "variant": "destructive", |
46 | | - "onClick": [ |
47 | | - { |
48 | | - "action": "api.mutation", |
49 | | - "confirm": { |
50 | | - "title": "Are you sure?", |
51 | | - "message": "This action cannot be undone.", |
52 | | - "variant": "danger" |
53 | | - }, |
54 | | - "params": { |
55 | | - "object": "project", |
56 | | - "method": "delete", |
57 | | - "id": "${record._id}" |
58 | | - } |
59 | | - }, |
60 | | - { |
61 | | - "action": "toast.success", |
62 | | - "params": { "message": "Project deleted successfully." } |
63 | | - }, |
64 | | - { |
65 | | - "action": "navigate", |
66 | | - "params": { "url": "/projects" } |
67 | | - } |
68 | | - ] |
69 | | - } |
70 | | -} |
71 | | - |
72 | | -``` |
73 | | - |
74 | | -## 2. Standard Action Library |
75 | | - |
76 | | -The ObjectUI Runtime comes with a built-in standard library of actions. You do not need to write code for these. |
77 | | - |
78 | | -### UI & Navigation |
79 | | - |
80 | | -| Action | Params | Description | |
81 | | -| --- | --- | --- | |
82 | | -| `Maps` | `url`, `target` | Go to a URL or ObjectUI Route. | |
83 | | -| `toast.success` | `message`, `duration` | Show a green success notification. | |
84 | | -| `toast.error` | `message` | Show a red error notification. | |
85 | | -| `modal.open` | `layout`, `title` | Open a JSON Layout in a dialog. | |
86 | | -| `modal.close` | - | Close the top-most dialog. | |
87 | | -| `drawer.open` | `layout`, `width` | Open a slide-over panel. | |
88 | | -| `copy` | `text` | Copy text to clipboard. | |
89 | | - |
90 | | -### Data & API |
91 | | - |
92 | | -| Action | Params | Description | |
93 | | -| --- | --- | --- | |
94 | | -| `api.query` | `query`, `bind` | Run an ObjectQL query and bind result to a variable. | |
95 | | -| `api.mutation` | `object`, `method`, `data` | Execute a create/update/delete. | |
96 | | -| `form.submit` | `formId` | Trigger validation and submission of a specific form. | |
97 | | -| `form.reset` | `formId` | Reset form fields to default values. | |
98 | | -| `record.refresh` | - | Re-fetch the current record from the server. | |
99 | | - |
100 | | -## 3. Action Context & Variables |
101 | | - |
102 | | -Actions run in a **Context**. You can access dynamic data using the `${variable}` syntax. |
103 | | - |
104 | | -* **`${record}`**: The current data record (row) being displayed. |
105 | | -* **`${user}`**: The current logged-in user session. |
106 | | -* **`${scope}`**: Temporary variables passed from parent components. |
107 | | -* **`${result}`**: The return value of the *previous* action in the chain. |
108 | | - |
109 | | -### Example: Using Previous Result |
110 | | - |
111 | | -```json |
112 | | -[ |
113 | | - // Step 1: Create a record |
114 | | - { |
115 | | - "action": "api.mutation", |
116 | | - "params": { "object": "task", "method": "create", "data": {...} } |
117 | | - }, |
118 | | - // Step 2: Navigate to the new ID |
119 | | - { |
120 | | - "action": "navigate", |
121 | | - "params": { "url": "/tasks/${result.id}" } |
122 | | - } |
123 | | -] |
124 | | - |
125 | | -``` |
126 | | - |
127 | | -## 4. Client-Side Logic (`action.script`) |
128 | | - |
129 | | -Sometimes standard actions aren't enough. You need custom calculation or logic. |
130 | | -ObjectUI provides a **Sandboxed Script Action**. |
131 | | - |
132 | | -> **Warning:** This is *not* `eval()`. It is a safe, limited expression parser. It cannot access `window`, `document`, or making arbitrary network requests. |
133 | | -
|
134 | | -```json |
135 | | -{ |
136 | | - "action": "script", |
137 | | - "params": { |
138 | | - "code": "if (record.amount > 1000) { return 'high_value'; } return 'standard';" |
139 | | - }, |
140 | | - "output_to": "temp.category" |
141 | | -} |
142 | | - |
143 | | -``` |
144 | | - |
145 | | -## 5. Action Containers |
146 | | - |
147 | | -Often, actions are grouped into a generic "Toolbar" or "Menu". |
148 | | - |
149 | | -### Toolbar (`layout.toolbar`) |
150 | | - |
151 | | -```json |
152 | | -{ |
153 | | - "type": "layout.toolbar", |
154 | | - "children": [ |
155 | | - { |
156 | | - "type": "button", |
157 | | - "props": { "label": "Edit", "icon": "edit" }, |
158 | | - "events": { "onClick": { "action": "modal.open", "params": { "layout": "edit_form" } } } |
159 | | - }, |
160 | | - { |
161 | | - "type": "button", |
162 | | - "props": { "label": "More", "icon": "more_horizontal" }, |
163 | | - "children": [ |
164 | | - // Dropdown Menu Items |
165 | | - { "label": "Duplicate", "action": "api.mutation", ... }, |
166 | | - { "label": "Archive", "action": "api.mutation", ... } |
167 | | - ] |
168 | | - } |
169 | | - ] |
170 | | -} |
171 | | - |
172 | | -``` |
173 | | - |
174 | | -## 6. Extending Actions |
175 | | - |
176 | | -You can register custom actions in your frontend application code. This allows you to bridge the gap between the JSON Protocol and specific React capabilities. |
177 | | - |
178 | | -```typescript |
179 | | -// src/app.tsx |
180 | | -import { registerAction } from '@objectui/runtime'; |
181 | | - |
182 | | -registerAction('custom.printLabel', async (context, params) => { |
183 | | - const zpl = generateZPL(context.record); |
184 | | - await sendToBluetoothPrinter(zpl); |
185 | | -}); |
186 | | - |
187 | | -``` |
188 | | - |
189 | | -**Usage in JSON:** |
190 | | - |
191 | | -```json |
192 | | -{ |
193 | | - "action": "custom.printLabel", |
194 | | - "params": { "format": "4x6" } |
195 | | -} |
196 | | - |
197 | | -``` |
198 | | - |
199 | | -## Summary |
200 | | - |
201 | | -The Action Protocol turns imperative behavior into declarative configuration. |
202 | | - |
203 | | -1. **Chaining:** Actions execute sequentially. |
204 | | -2. **Context Aware:** They can read the current record state. |
205 | | -3. **Safe:** No raw JavaScript injection; only whitelisted actions. |
206 | | -4. **Confirmations:** Built-in UI patterns for dangerous operations. |
0 commit comments