@cxtms/cx-schema 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/cx-core/SKILL.md +93 -0
- package/.claude/skills/cx-core/ref-entity-accounting.md +173 -0
- package/.claude/skills/cx-core/ref-entity-commodity.md +205 -0
- package/.claude/skills/cx-core/ref-entity-contact.md +153 -0
- package/.claude/skills/cx-core/ref-entity-geography.md +119 -0
- package/.claude/skills/cx-core/ref-entity-job.md +77 -0
- package/.claude/skills/cx-core/ref-entity-order-sub.md +140 -0
- package/.claude/skills/cx-core/ref-entity-order.md +168 -0
- package/.claude/skills/cx-core/ref-entity-rate.md +174 -0
- package/.claude/skills/cx-core/ref-entity-shared.md +147 -0
- package/.claude/skills/cx-core/ref-entity-warehouse.md +110 -0
- package/.claude/skills/cx-module/SKILL.md +402 -0
- package/.claude/skills/cx-module/ref-components-data.md +286 -0
- package/.claude/skills/cx-module/ref-components-display.md +394 -0
- package/.claude/skills/cx-module/ref-components-forms.md +362 -0
- package/.claude/skills/cx-module/ref-components-interactive.md +306 -0
- package/.claude/skills/cx-module/ref-components-layout.md +295 -0
- package/.claude/skills/cx-module/ref-components-specialized.md +427 -0
- package/.claude/skills/cx-workflow/SKILL.md +330 -0
- package/.claude/skills/cx-workflow/ref-accounting.md +66 -0
- package/.claude/skills/cx-workflow/ref-communication.md +161 -0
- package/.claude/skills/cx-workflow/ref-entity.md +162 -0
- package/.claude/skills/cx-workflow/ref-expressions.md +239 -0
- package/.claude/skills/cx-workflow/ref-filetransfer.md +80 -0
- package/.claude/skills/cx-workflow/ref-flow.md +180 -0
- package/.claude/skills/cx-workflow/ref-other.md +120 -0
- package/.claude/skills/cx-workflow/ref-query.md +85 -0
- package/.claude/skills/cx-workflow/ref-utilities.md +171 -0
- package/README.md +34 -34
- package/dist/cli.js +545 -35
- package/dist/cli.js.map +1 -1
- package/dist/types.d.ts +17 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/workflowValidator.d.ts +31 -0
- package/dist/workflowValidator.d.ts.map +1 -1
- package/dist/workflowValidator.js +299 -9
- package/dist/workflowValidator.js.map +1 -1
- package/package.json +4 -3
- package/schemas/schema.graphql +2077 -321
- package/schemas/workflows/flow/aggregation.json +44 -0
- package/schemas/workflows/flow/entity.json +110 -0
- package/schemas/workflows/flow/state.json +105 -0
- package/schemas/workflows/flow/transition.json +143 -0
- package/schemas/workflows/input.json +53 -7
- package/schemas/workflows/output.json +20 -0
- package/schemas/workflows/trigger.json +4 -0
- package/schemas/workflows/variable.json +2 -6
- package/schemas/workflows/workflow.json +179 -21
- package/scripts/postinstall.js +30 -1
- package/templates/module-configuration.yaml +110 -0
- package/templates/module-form.yaml +152 -0
- package/templates/module-grid.yaml +229 -0
- package/templates/module-select.yaml +139 -0
- package/templates/module.yaml +3 -3
- package/templates/workflow-api-tracking.yaml +189 -0
- package/templates/workflow-basic.yaml +76 -0
- package/templates/workflow-document.yaml +155 -0
- package/templates/workflow-entity-trigger.yaml +90 -0
- package/templates/workflow-ftp-edi.yaml +158 -0
- package/templates/workflow-ftp-tracking.yaml +161 -0
- package/templates/workflow-mcp-tool.yaml +112 -0
- package/templates/workflow-public-api.yaml +135 -0
- package/templates/workflow-scheduled.yaml +125 -0
- package/templates/workflow-utility.yaml +96 -0
- package/templates/workflow-webhook.yaml +128 -0
- package/templates/workflow.yaml +52 -12
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
# Form & Input Components
|
|
2
|
+
|
|
3
|
+
## form
|
|
4
|
+
|
|
5
|
+
Data entry form with validation, queries, and submission. Wraps React Hook Form's FormProvider.
|
|
6
|
+
|
|
7
|
+
**Props:**
|
|
8
|
+
| Prop | Type | Description |
|
|
9
|
+
|------|------|-------------|
|
|
10
|
+
| `title` | `ILocalizeString` | Form title |
|
|
11
|
+
| `initialValues` | `object \| query config` | Initial data — static object, template, or query config |
|
|
12
|
+
| `initialValues.fromQuery` | `{name, path}` | Load initial values from a named query |
|
|
13
|
+
| `initialValues.append` | `Record<string, any>` | Merge additional defaults after query load |
|
|
14
|
+
| `validationSchema` | `Record<string, {type, required?, ...}>` | Yup-based validation rules |
|
|
15
|
+
| `queries` | `QueryDef[]` | GraphQL queries for data loading |
|
|
16
|
+
| `prefix` | `string` | Field name namespace prefix |
|
|
17
|
+
| `refreshHandler` | `string` | Remount on refresh event |
|
|
18
|
+
| `dirtyGuard` | `DirtyGuardProps` | Unsaved changes protection |
|
|
19
|
+
| `dirtyGuard.enabled` | `boolean` | Enable guard |
|
|
20
|
+
| `dirtyGuard.title` | `ILocalizeString` | Dialog title |
|
|
21
|
+
| `dirtyGuard.message` | `ILocalizeString` | Dialog message |
|
|
22
|
+
| `dirtyGuard.confirmLabel` | `ILocalizeString` | Confirm button text |
|
|
23
|
+
| `dirtyGuard.cancelLabel` | `ILocalizeString` | Cancel button text |
|
|
24
|
+
| `autoSave` | `boolean` | Auto-save on field change |
|
|
25
|
+
| `resetOnSubmit` | `boolean` | Reset form after submit |
|
|
26
|
+
| `preventDefault` | `boolean` | Prevent default form submit |
|
|
27
|
+
| `toolbar` | `component[]` | Toolbar components |
|
|
28
|
+
| `cols` | `number` | Column layout for children |
|
|
29
|
+
| `orientation` | `string` | Layout orientation |
|
|
30
|
+
|
|
31
|
+
**Events:**
|
|
32
|
+
| Event | Description |
|
|
33
|
+
|-------|-------------|
|
|
34
|
+
| `onSubmit` | Action chain on form submission |
|
|
35
|
+
| `onChange` | Action chain on any field change |
|
|
36
|
+
| `onLoad` | Action chain when form data loads |
|
|
37
|
+
| `onReset` | Action chain on form reset |
|
|
38
|
+
| `onValidate` | Action chain on validation |
|
|
39
|
+
| `onError` | Action chain on error |
|
|
40
|
+
|
|
41
|
+
**Children:** Yes — typically `field` components. Provides `formName` and `createMode` in variables.
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
component: form
|
|
45
|
+
name: orderForm
|
|
46
|
+
props:
|
|
47
|
+
title: { en-US: "Order Details" }
|
|
48
|
+
toolbar:
|
|
49
|
+
- component: button
|
|
50
|
+
name: saveBtn
|
|
51
|
+
props:
|
|
52
|
+
label: { en-US: "Save" }
|
|
53
|
+
icon: check
|
|
54
|
+
options: { type: submit, variant: primary }
|
|
55
|
+
queries:
|
|
56
|
+
- name: getOrder
|
|
57
|
+
query:
|
|
58
|
+
command: |
|
|
59
|
+
query GetOrder($id: Int!) {
|
|
60
|
+
order(id: $id) { id orderNumber status }
|
|
61
|
+
}
|
|
62
|
+
variables:
|
|
63
|
+
id: "{{ number id }}"
|
|
64
|
+
initialValues:
|
|
65
|
+
fromQuery:
|
|
66
|
+
name: getOrder
|
|
67
|
+
path: order
|
|
68
|
+
append:
|
|
69
|
+
status: "Draft"
|
|
70
|
+
validationSchema:
|
|
71
|
+
orderNumber:
|
|
72
|
+
type: string
|
|
73
|
+
required: true
|
|
74
|
+
status:
|
|
75
|
+
type: string
|
|
76
|
+
required: true
|
|
77
|
+
dirtyGuard:
|
|
78
|
+
enabled: true
|
|
79
|
+
title: { en-US: "Unsaved Changes" }
|
|
80
|
+
message: { en-US: "You have unsaved changes. Leave?" }
|
|
81
|
+
confirmLabel: { en-US: "Leave" }
|
|
82
|
+
cancelLabel: { en-US: "Stay" }
|
|
83
|
+
onSubmit:
|
|
84
|
+
- mutation:
|
|
85
|
+
command: |
|
|
86
|
+
mutation SaveOrder($input: OrderInput!) {
|
|
87
|
+
saveOrder(input: $input) { id }
|
|
88
|
+
}
|
|
89
|
+
variables:
|
|
90
|
+
input: "{{ form }}"
|
|
91
|
+
onSuccess:
|
|
92
|
+
- notification: { message: { en-US: "Saved!" }, type: success }
|
|
93
|
+
- navigateBack: { fallback: "/orders" }
|
|
94
|
+
children:
|
|
95
|
+
- component: field
|
|
96
|
+
name: orderNumber
|
|
97
|
+
props: { type: text, label: { en-US: "Order Number" }, required: true }
|
|
98
|
+
- component: field
|
|
99
|
+
name: status
|
|
100
|
+
props:
|
|
101
|
+
type: select
|
|
102
|
+
label: { en-US: "Status" }
|
|
103
|
+
items:
|
|
104
|
+
- { label: "Draft", value: "Draft" }
|
|
105
|
+
- { label: "Active", value: "Active" }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## field
|
|
111
|
+
|
|
112
|
+
Polymorphic form field — renders different input types based on `type` prop.
|
|
113
|
+
|
|
114
|
+
**Props:**
|
|
115
|
+
| Prop | Type | Description |
|
|
116
|
+
|------|------|-------------|
|
|
117
|
+
| `type` | `string` | **Required.** Field type (see table below) |
|
|
118
|
+
| `label` | `ILocalizeString` | Localized label |
|
|
119
|
+
| `placeholder` | `string` | Placeholder text (template-parsed) |
|
|
120
|
+
| `disabled` | `string \| boolean` | Disable state (template expression) |
|
|
121
|
+
| `readonly` | `boolean` | Read-only mode |
|
|
122
|
+
| `required` | `boolean` | Required field |
|
|
123
|
+
| `prefix` | `string` | Field name prefix for nested paths |
|
|
124
|
+
| `transformValue` | `{onEdit?, onLoad?}` | Template expressions to transform values |
|
|
125
|
+
| `multiple` | `boolean` | Multi-value mode (for `text`) |
|
|
126
|
+
| `autoComplete` | `string` | HTML autocomplete attribute |
|
|
127
|
+
| `rows` | `number` | Rows for textarea (default 2) |
|
|
128
|
+
| `defaultCountry` | `string` | Default country for phone type |
|
|
129
|
+
| `isClearable` | `boolean` | Allow clearing the value |
|
|
130
|
+
| `InputProps` | `object` | Passed to underlying MUI TextField |
|
|
131
|
+
|
|
132
|
+
**Field Types:**
|
|
133
|
+
| Type | Description |
|
|
134
|
+
|------|-------------|
|
|
135
|
+
| `text` | Standard text input. `multiple: true` → multi-value tags |
|
|
136
|
+
| `number` | Numeric input |
|
|
137
|
+
| `email` | Email input |
|
|
138
|
+
| `password` | Password input |
|
|
139
|
+
| `tel` / `phone` | Phone number with country selector |
|
|
140
|
+
| `textarea` | Multi-line text with `rows` prop |
|
|
141
|
+
| `checkbox` | Boolean checkbox |
|
|
142
|
+
| `radio` | Radio button (use `value` prop) |
|
|
143
|
+
| `date` | Date picker |
|
|
144
|
+
| `datetime` | Date + time picker |
|
|
145
|
+
| `rangedatetime` | Date range picker |
|
|
146
|
+
| `enhanced-rangedatetime` | Enhanced date range picker |
|
|
147
|
+
| `time` | Time picker |
|
|
148
|
+
| `select` | Dropdown select from `items[]` |
|
|
149
|
+
| `select-async` | Async search select (GraphQL-backed) |
|
|
150
|
+
| `autocomplete` | Autocomplete from `items[]` |
|
|
151
|
+
| `autocomplete-async` | Async autocomplete (GraphQL-backed) |
|
|
152
|
+
| `autocomplete-googleplaces` | Google Places autocomplete |
|
|
153
|
+
| `file` | File upload (converts to byte array) |
|
|
154
|
+
| `attachment` | File attachment |
|
|
155
|
+
| `hidden` | Hidden input |
|
|
156
|
+
| `quill` | Rich text editor (Quill) |
|
|
157
|
+
| `object` | JSON object editor |
|
|
158
|
+
| `yaml` | YAML editor |
|
|
159
|
+
|
|
160
|
+
**Select/Async options (under `options`):**
|
|
161
|
+
| Prop | Type | Description |
|
|
162
|
+
|------|------|-------------|
|
|
163
|
+
| `items` | `{label, value}[]` | Static select items |
|
|
164
|
+
| `allowMultiple` | `boolean` | Multi-select mode |
|
|
165
|
+
| `allowClear` | `boolean` | Show clear button |
|
|
166
|
+
| `allowSearch` | `boolean` | Searchable dropdown |
|
|
167
|
+
| `valueFieldName` | `string` | Result field holding the value |
|
|
168
|
+
| `itemLabelTemplate` | `string` | Handlebars template for labels |
|
|
169
|
+
| `itemValueTemplate` | `string` | Handlebars template for values |
|
|
170
|
+
| `navigateActionPermission` | `string` | Permission for edit icon |
|
|
171
|
+
| `searchQuery` | `{name, path, params}` | Paginated search query ref |
|
|
172
|
+
| `valueQuery` | `{name, path, params}` | Single-value lookup query ref |
|
|
173
|
+
| `variant` | `string` | Select variant |
|
|
174
|
+
|
|
175
|
+
**Events:**
|
|
176
|
+
| Event | Description |
|
|
177
|
+
|-------|-------------|
|
|
178
|
+
| `onClick` | Fires on click |
|
|
179
|
+
| `onChange` | Fires on value change (data: `changedValues`, `checked`) |
|
|
180
|
+
| `onBlur` | Fires on blur |
|
|
181
|
+
| `onFocus` | Fires on focus |
|
|
182
|
+
| `onKeyPress` | Fires on keypress (data: `key`, `keyCode`) |
|
|
183
|
+
| `onSelectValue` | Fires on select-async value selection |
|
|
184
|
+
| `onEditClick` | Fires when edit icon clicked (select-async, permission-gated) |
|
|
185
|
+
|
|
186
|
+
```yaml
|
|
187
|
+
# Text field
|
|
188
|
+
- component: field
|
|
189
|
+
name: companyName
|
|
190
|
+
props:
|
|
191
|
+
type: text
|
|
192
|
+
label: { en-US: "Company Name" }
|
|
193
|
+
required: true
|
|
194
|
+
placeholder: "Enter company name"
|
|
195
|
+
|
|
196
|
+
# Select field
|
|
197
|
+
- component: field
|
|
198
|
+
name: status
|
|
199
|
+
props:
|
|
200
|
+
type: select
|
|
201
|
+
label: { en-US: "Status" }
|
|
202
|
+
items:
|
|
203
|
+
- { label: "Active", value: "active" }
|
|
204
|
+
- { label: "Inactive", value: "inactive" }
|
|
205
|
+
|
|
206
|
+
# Async select with search
|
|
207
|
+
- component: field
|
|
208
|
+
name: customerId
|
|
209
|
+
props:
|
|
210
|
+
type: select-async
|
|
211
|
+
label: { en-US: "Customer" }
|
|
212
|
+
options:
|
|
213
|
+
valueFieldName: contactId
|
|
214
|
+
itemLabelTemplate: "{{contactName}}"
|
|
215
|
+
itemValueTemplate: "{{contactId}}"
|
|
216
|
+
allowSearch: true
|
|
217
|
+
allowClear: true
|
|
218
|
+
searchQuery:
|
|
219
|
+
name: getContacts
|
|
220
|
+
path: contacts.items
|
|
221
|
+
params:
|
|
222
|
+
search: "{{ string search }}"
|
|
223
|
+
take: "{{ number pageSize }}"
|
|
224
|
+
skip: "{{ number skip }}"
|
|
225
|
+
valueQuery:
|
|
226
|
+
name: getContact
|
|
227
|
+
path: contact
|
|
228
|
+
params:
|
|
229
|
+
contactId: "{{ contactId }}"
|
|
230
|
+
queries:
|
|
231
|
+
- name: getContacts
|
|
232
|
+
query:
|
|
233
|
+
command: >-
|
|
234
|
+
query($search: String!, $take: Int!, $skip: Int!) {
|
|
235
|
+
contacts(search: $search, take: $take, skip: $skip) {
|
|
236
|
+
items { contactId contactName } totalCount
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
- name: getContact
|
|
240
|
+
query:
|
|
241
|
+
command: >-
|
|
242
|
+
query($contactId: Int!) {
|
|
243
|
+
contact(contactId: $contactId) { contactId contactName }
|
|
244
|
+
}
|
|
245
|
+
variables:
|
|
246
|
+
contactId: "{{ number contactId }}"
|
|
247
|
+
|
|
248
|
+
# Date field with transform
|
|
249
|
+
- component: field
|
|
250
|
+
name: effectiveDate
|
|
251
|
+
props:
|
|
252
|
+
type: date
|
|
253
|
+
label: { en-US: "Effective Date" }
|
|
254
|
+
transformValue:
|
|
255
|
+
onLoad: "{{ format effectiveDate YYYY-MM-DD }}"
|
|
256
|
+
|
|
257
|
+
# Conditional visibility
|
|
258
|
+
- component: field
|
|
259
|
+
name: notes
|
|
260
|
+
props:
|
|
261
|
+
type: textarea
|
|
262
|
+
label: { en-US: "Notes" }
|
|
263
|
+
rows: 4
|
|
264
|
+
disabled: "{{ eval !canEdit }}"
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## field-collection
|
|
270
|
+
|
|
271
|
+
Dynamic array/list editor for repeating field groups. Supports add/remove/reorder with drag-and-drop.
|
|
272
|
+
|
|
273
|
+
**Props:**
|
|
274
|
+
| Prop | Type | Default | Description |
|
|
275
|
+
|------|------|---------|-------------|
|
|
276
|
+
| `fieldName` | `string` | — | **Required.** Form array field binding |
|
|
277
|
+
| `itemTemplate` | `ComponentProps` | — | Template for each item |
|
|
278
|
+
| `itemType` | `object \| string \| number \| boolean` | `object` | Item type |
|
|
279
|
+
| `options.allowAdd` | `boolean` | `true` | Show add button |
|
|
280
|
+
| `options.allowRemove` | `boolean` | `true` | Show remove buttons |
|
|
281
|
+
| `options.allowRemoveAll` | `boolean` | `false` | Show remove all button |
|
|
282
|
+
| `options.allowReorder` | `boolean` | `true` | Enable drag-and-drop |
|
|
283
|
+
| `options.minItems` | `number` | `0` | Minimum items (auto-created) |
|
|
284
|
+
| `options.maxItems` | `number` | `∞` | Maximum items |
|
|
285
|
+
| `addButton.label` | `ILocalizeString` | `Add Item` | Add button label |
|
|
286
|
+
| `addButton.icon` | `string` | `plus` | Add button icon |
|
|
287
|
+
| `addButton.position` | `top \| bottom \| both` | `bottom` | Add button placement |
|
|
288
|
+
| `defaultItem` | `any` | — | Template for new items |
|
|
289
|
+
| `layout` | `list \| grid \| accordion` | `list` | Layout mode |
|
|
290
|
+
| `cols` | `number` | `1` | Grid columns |
|
|
291
|
+
| `groupMode` | `boolean` | `false` | Enable grouping |
|
|
292
|
+
| `groupBy` | `string` | — | Field path to group by |
|
|
293
|
+
| `groups` | `{key, label, icon?}[]` | — | Group definitions |
|
|
294
|
+
| `showIndex` | `boolean` | `false` | Show item index |
|
|
295
|
+
| `showDragHandle` | `boolean` | `false` | Show drag handles |
|
|
296
|
+
|
|
297
|
+
**Children:** Uses `itemTemplate` (not `children`). Each item gets `item`, `index`, `collection` variables.
|
|
298
|
+
|
|
299
|
+
```yaml
|
|
300
|
+
component: field-collection
|
|
301
|
+
name: lineItems
|
|
302
|
+
props:
|
|
303
|
+
fieldName: lineItems
|
|
304
|
+
options:
|
|
305
|
+
allowAdd: true
|
|
306
|
+
allowRemove: true
|
|
307
|
+
allowReorder: true
|
|
308
|
+
minItems: 1
|
|
309
|
+
maxItems: 50
|
|
310
|
+
addButton:
|
|
311
|
+
label: { en-US: "Add Line Item" }
|
|
312
|
+
icon: plus
|
|
313
|
+
position: bottom
|
|
314
|
+
defaultItem:
|
|
315
|
+
description: ""
|
|
316
|
+
quantity: 1
|
|
317
|
+
unitPrice: 0
|
|
318
|
+
layout: list
|
|
319
|
+
itemTemplate:
|
|
320
|
+
component: row
|
|
321
|
+
name: lineItemRow
|
|
322
|
+
props: { spacing: 2 }
|
|
323
|
+
children:
|
|
324
|
+
- component: field
|
|
325
|
+
name: description
|
|
326
|
+
props: { type: text, label: { en-US: "Description" } }
|
|
327
|
+
- component: field
|
|
328
|
+
name: quantity
|
|
329
|
+
props: { type: number, label: { en-US: "Qty" } }
|
|
330
|
+
- component: field
|
|
331
|
+
name: unitPrice
|
|
332
|
+
props: { type: number, label: { en-US: "Unit Price" } }
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## barcodeScanner
|
|
338
|
+
|
|
339
|
+
Headless barcode/keyboard scanner listener. Captures rapid keystrokes and fires on scan.
|
|
340
|
+
|
|
341
|
+
**Props:**
|
|
342
|
+
| Prop | Type | Default | Description |
|
|
343
|
+
|------|------|---------|-------------|
|
|
344
|
+
| `minBarcodeLength` | `number` | `4` | Min chars to qualify as scan |
|
|
345
|
+
| `onScan` | `action[]` | — | **Required.** Action on scan detection |
|
|
346
|
+
|
|
347
|
+
**Renders:** Nothing (empty fragment). Listens on `document` keypress.
|
|
348
|
+
|
|
349
|
+
**Scan data:** `result: { data: string, format: 'input' }`
|
|
350
|
+
|
|
351
|
+
```yaml
|
|
352
|
+
component: barcodeScanner
|
|
353
|
+
name: scanner
|
|
354
|
+
props:
|
|
355
|
+
minBarcodeLength: 6
|
|
356
|
+
onScan:
|
|
357
|
+
- setFields:
|
|
358
|
+
barcode: "{{ result.data }}"
|
|
359
|
+
- notification:
|
|
360
|
+
message: { en-US: "Scanned: {{ result.data }}" }
|
|
361
|
+
type: info
|
|
362
|
+
```
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# Interactive & Navigation Components
|
|
2
|
+
|
|
3
|
+
## button
|
|
4
|
+
|
|
5
|
+
MUI Button with icon, label, loading state, and action dispatch.
|
|
6
|
+
|
|
7
|
+
**Props:**
|
|
8
|
+
| Prop | Type | Description |
|
|
9
|
+
|------|------|-------------|
|
|
10
|
+
| `label` | `ILocalizeString` | Button text (localized, template-parsed) |
|
|
11
|
+
| `icon` | `string` | Icon name (template-parsed) |
|
|
12
|
+
| `stopPropagation` | `boolean` | Stop click event propagation |
|
|
13
|
+
| `options.variant` | `string` | Visual variant (see mapping below) |
|
|
14
|
+
| `options.disabled` | `boolean \| string` | Disable state (template expression) |
|
|
15
|
+
| `options.type` | `submit \| reset \| button` | Button type |
|
|
16
|
+
| `options.sx` | `SxProps` | MUI sx styles |
|
|
17
|
+
| `options.className` | `string` | CSS class |
|
|
18
|
+
|
|
19
|
+
**Variant mapping:**
|
|
20
|
+
| YAML Value | MUI Rendered |
|
|
21
|
+
|------------|-------------|
|
|
22
|
+
| `primary` | `contained` + primary color |
|
|
23
|
+
| `secondary` | `outlined` + secondary color |
|
|
24
|
+
| `outline-primary` | `outlined` + primary color |
|
|
25
|
+
| `outline-secondary` | `outlined` + secondary color |
|
|
26
|
+
| `danger` | `contained` + error color |
|
|
27
|
+
| `success` | `contained` + success color |
|
|
28
|
+
| `warning` | `contained` + warning color |
|
|
29
|
+
| `info` | `contained` + info color |
|
|
30
|
+
| `link` / `text` | `text` variant |
|
|
31
|
+
| `contained-primary` | compound format supported |
|
|
32
|
+
|
|
33
|
+
**Events:** `onClick` — dispatches action chain with loading spinner while executing.
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
# Primary submit button
|
|
37
|
+
- component: button
|
|
38
|
+
name: saveBtn
|
|
39
|
+
props:
|
|
40
|
+
label: { en-US: "Save" }
|
|
41
|
+
icon: check
|
|
42
|
+
options:
|
|
43
|
+
type: submit
|
|
44
|
+
variant: primary
|
|
45
|
+
|
|
46
|
+
# Danger button with confirmation
|
|
47
|
+
- component: button
|
|
48
|
+
name: deleteBtn
|
|
49
|
+
props:
|
|
50
|
+
label: { en-US: "Delete" }
|
|
51
|
+
icon: trash
|
|
52
|
+
options:
|
|
53
|
+
variant: danger
|
|
54
|
+
onClick:
|
|
55
|
+
- confirm:
|
|
56
|
+
title: { en-US: "Delete Item?" }
|
|
57
|
+
message: { en-US: "This action cannot be undone." }
|
|
58
|
+
- mutation:
|
|
59
|
+
command: "mutation($id: Int!) { deleteItem(id: $id) { success } }"
|
|
60
|
+
variables: { id: "{{ number id }}" }
|
|
61
|
+
onSuccess:
|
|
62
|
+
- notification: { message: { en-US: "Deleted" }, type: success }
|
|
63
|
+
- navigateBack: { fallback: "/items" }
|
|
64
|
+
|
|
65
|
+
# Conditional disabled state
|
|
66
|
+
- component: button
|
|
67
|
+
name: approveBtn
|
|
68
|
+
props:
|
|
69
|
+
label: { en-US: "Approve" }
|
|
70
|
+
icon: check-circle
|
|
71
|
+
options:
|
|
72
|
+
variant: success
|
|
73
|
+
disabled: "{{ eval status !== 'Pending' }}"
|
|
74
|
+
onClick:
|
|
75
|
+
- mutation:
|
|
76
|
+
command: "mutation($id: Int!) { approveOrder(id: $id) { success } }"
|
|
77
|
+
variables: { id: "{{ number id }}" }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## dropdown
|
|
83
|
+
|
|
84
|
+
Action dropdown menu (not a form select). MUI Button + Menu with permission-gated items.
|
|
85
|
+
|
|
86
|
+
**Props:**
|
|
87
|
+
| Prop | Type | Description |
|
|
88
|
+
|------|------|-------------|
|
|
89
|
+
| `label` | `ILocalizeString` | Trigger button label |
|
|
90
|
+
| `icon` | `string` | Trigger button icon |
|
|
91
|
+
| `name` | `string` | Component name |
|
|
92
|
+
| `items` | `MenuItem[]` | Menu items |
|
|
93
|
+
| `items[].label` | `ILocalizeString` | Item label |
|
|
94
|
+
| `items[].value` | `any` | Item key |
|
|
95
|
+
| `items[].disabled` | `string \| boolean` | Disable (template expression) |
|
|
96
|
+
| `items[].permission` | `string` | Permission gate — hidden if not granted |
|
|
97
|
+
| `items[].onClick` | `action[]` | Per-item action |
|
|
98
|
+
| `options.size` | `string` | Button size (default: `medium`) |
|
|
99
|
+
| `options.variant` | `string` | Button variant (default: `outlined`) |
|
|
100
|
+
|
|
101
|
+
**Events:** `onClick` (button level), `items[].onClick` (per item)
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
component: dropdown
|
|
105
|
+
name: actionsDropdown
|
|
106
|
+
props:
|
|
107
|
+
label: { en-US: "Actions" }
|
|
108
|
+
icon: activity
|
|
109
|
+
options:
|
|
110
|
+
variant: secondary
|
|
111
|
+
items:
|
|
112
|
+
- label: { en-US: "Export CSV" }
|
|
113
|
+
onClick:
|
|
114
|
+
- notification: { message: { en-US: "Exporting..." }, type: info }
|
|
115
|
+
- label: { en-US: "Import" }
|
|
116
|
+
permission: "Module/Import"
|
|
117
|
+
onClick:
|
|
118
|
+
- dialog:
|
|
119
|
+
component: Module/ImportDialog
|
|
120
|
+
- label: { en-US: "Archive All" }
|
|
121
|
+
disabled: "{{ eval selectedItems.length === 0 }}"
|
|
122
|
+
onClick:
|
|
123
|
+
- confirm: { title: { en-US: "Archive?" }, message: { en-US: "Archive selected items?" } }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## menuButton
|
|
129
|
+
|
|
130
|
+
Collapsible menu with custom component children. Paper container with click toggle.
|
|
131
|
+
|
|
132
|
+
**Props:**
|
|
133
|
+
| Prop | Type | Description |
|
|
134
|
+
|------|------|-------------|
|
|
135
|
+
| `label` | `ILocalizeString` | Trigger element text |
|
|
136
|
+
| `options` | `object` | HTML attributes on trigger div |
|
|
137
|
+
| `options.allowCreate` | `boolean` | Show children with `create` in name |
|
|
138
|
+
|
|
139
|
+
**Children:** Yes — each child rendered as a MenuItem via ComponentRender. Children with `create` in name are gated by `allowCreate`.
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
component: menuButton
|
|
143
|
+
name: quickActions
|
|
144
|
+
props:
|
|
145
|
+
label: { en-US: "Quick Actions" }
|
|
146
|
+
options:
|
|
147
|
+
allowCreate: true
|
|
148
|
+
children:
|
|
149
|
+
- component: button
|
|
150
|
+
name: createOrder
|
|
151
|
+
props: { label: { en-US: "Create Order" }, icon: plus }
|
|
152
|
+
- component: button
|
|
153
|
+
name: viewReports
|
|
154
|
+
props: { label: { en-US: "View Reports" }, icon: bar-chart }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## link
|
|
160
|
+
|
|
161
|
+
HTML anchor link with template-parsed URL and label.
|
|
162
|
+
|
|
163
|
+
**Props:**
|
|
164
|
+
| Prop | Type | Description |
|
|
165
|
+
|------|------|-------------|
|
|
166
|
+
| `label` | `string` | Display text (template-parsed, localized) |
|
|
167
|
+
| `to` | `string` | URL href (template-parsed) |
|
|
168
|
+
| `options` | `object` | Additional `<a>` attributes (target, rel, etc.) |
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
component: link
|
|
172
|
+
name: externalLink
|
|
173
|
+
props:
|
|
174
|
+
label: "View on External System"
|
|
175
|
+
to: "https://external.com/entity/{{ entityId }}"
|
|
176
|
+
options:
|
|
177
|
+
target: _blank
|
|
178
|
+
rel: noopener noreferrer
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## redirect
|
|
184
|
+
|
|
185
|
+
Programmatic navigation — renders nothing (or spinner with delay).
|
|
186
|
+
|
|
187
|
+
**Props:**
|
|
188
|
+
| Prop | Type | Default | Description |
|
|
189
|
+
|------|------|---------|-------------|
|
|
190
|
+
| `path` | `string` | — | **Required.** Destination (template-parsed) |
|
|
191
|
+
| `params` | `Record<string, any>` | — | Query parameters |
|
|
192
|
+
| `delay` | `number` | `0` | Delay in ms before redirect |
|
|
193
|
+
| `replace` | `boolean` | `false` | Use replace instead of push |
|
|
194
|
+
| `condition` | `any` | — | Template expression; skip redirect if falsy |
|
|
195
|
+
|
|
196
|
+
**Path types:**
|
|
197
|
+
- `http://...` / `https://...` — External redirect
|
|
198
|
+
- `~path` — System path (bypasses org prefix)
|
|
199
|
+
- `/path` — Org-relative path (prepends `/org/{orgId}/v2/`)
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
# Conditional redirect
|
|
203
|
+
component: redirect
|
|
204
|
+
name: createRedirect
|
|
205
|
+
props:
|
|
206
|
+
condition: "{{ eval !id }}"
|
|
207
|
+
path: "/orders/create"
|
|
208
|
+
|
|
209
|
+
# External redirect with delay
|
|
210
|
+
component: redirect
|
|
211
|
+
name: externalRedirect
|
|
212
|
+
props:
|
|
213
|
+
path: "https://external.com/order/{{ externalId }}"
|
|
214
|
+
delay: 2000
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## navbar
|
|
220
|
+
|
|
221
|
+
Vertical navigation menu with accordion submenus. Uses `@menu/vertical-menu`.
|
|
222
|
+
|
|
223
|
+
**Props:**
|
|
224
|
+
| Prop | Type | Description |
|
|
225
|
+
|------|------|-------------|
|
|
226
|
+
| `items` | `component[]` | Primary nav items (navbarItem, navbarLink, navDropdown) |
|
|
227
|
+
| `contextItems` | `component[]` | Additional nav items (bottom section) |
|
|
228
|
+
|
|
229
|
+
**Children:** No — uses `items` and `contextItems` props.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## navbarItem
|
|
234
|
+
|
|
235
|
+
Nav section with optional label header. Child of `navbar`.
|
|
236
|
+
|
|
237
|
+
**Props:**
|
|
238
|
+
| Prop | Type | Description |
|
|
239
|
+
|------|------|-------------|
|
|
240
|
+
| `label` | `ILocalizeString` | Section header label |
|
|
241
|
+
|
|
242
|
+
**Children:** Yes — rendered as section content.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## navbarLink
|
|
247
|
+
|
|
248
|
+
Single navigation link. Child of `navbarItem` or `navDropdown`.
|
|
249
|
+
|
|
250
|
+
**Props:**
|
|
251
|
+
| Prop | Type | Description |
|
|
252
|
+
|------|------|-------------|
|
|
253
|
+
| `to` | `string` | Target path (template-parsed, locale-prefixed) |
|
|
254
|
+
| `label` | `ILocalizeString` | Link display text |
|
|
255
|
+
| `icon` | `string` | Menu item icon |
|
|
256
|
+
|
|
257
|
+
**Events:** `onClick`
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## navDropdown
|
|
262
|
+
|
|
263
|
+
Collapsible submenu. Child of `navbarItem`. Auto-expands if child path matches current URL.
|
|
264
|
+
|
|
265
|
+
**Props:**
|
|
266
|
+
| Prop | Type | Description |
|
|
267
|
+
|------|------|-------------|
|
|
268
|
+
| `label` | `ILocalizeString` | Submenu label |
|
|
269
|
+
| `icon` | `string` | Submenu icon |
|
|
270
|
+
|
|
271
|
+
**Children:** Yes — typically `navbarLink` items.
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
# Full navbar example
|
|
275
|
+
component: navbar
|
|
276
|
+
name: mainNav
|
|
277
|
+
props:
|
|
278
|
+
items:
|
|
279
|
+
- component: navbarItem
|
|
280
|
+
name: mainSection
|
|
281
|
+
props:
|
|
282
|
+
label: { en-US: "Main" }
|
|
283
|
+
children:
|
|
284
|
+
- component: navbarLink
|
|
285
|
+
name: dashboard
|
|
286
|
+
props:
|
|
287
|
+
to: "/dashboard"
|
|
288
|
+
label: { en-US: "Dashboard" }
|
|
289
|
+
icon: home
|
|
290
|
+
- component: navDropdown
|
|
291
|
+
name: ordersMenu
|
|
292
|
+
props:
|
|
293
|
+
label: { en-US: "Orders" }
|
|
294
|
+
icon: package
|
|
295
|
+
children:
|
|
296
|
+
- component: navbarLink
|
|
297
|
+
name: allOrders
|
|
298
|
+
props:
|
|
299
|
+
to: "/orders"
|
|
300
|
+
label: { en-US: "All Orders" }
|
|
301
|
+
- component: navbarLink
|
|
302
|
+
name: createOrder
|
|
303
|
+
props:
|
|
304
|
+
to: "/orders/create"
|
|
305
|
+
label: { en-US: "Create Order" }
|
|
306
|
+
```
|