@rglabs/butterfly 2.0.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.md +201 -0
- package/README.md +371 -0
- package/dist/commands/add.d.ts +23 -0
- package/dist/commands/add.js +303 -0
- package/dist/commands/code.d.ts +11 -0
- package/dist/commands/code.js +72 -0
- package/dist/commands/create-object.d.ts +6 -0
- package/dist/commands/create-object.js +293 -0
- package/dist/commands/create-report.d.ts +6 -0
- package/dist/commands/create-report.js +154 -0
- package/dist/commands/diff.d.ts +4 -0
- package/dist/commands/diff.js +238 -0
- package/dist/commands/download.d.ts +4 -0
- package/dist/commands/download.js +374 -0
- package/dist/commands/layout.d.ts +12 -0
- package/dist/commands/layout.js +83 -0
- package/dist/commands/record.d.ts +21 -0
- package/dist/commands/record.js +483 -0
- package/dist/commands/run-poc.d.ts +3 -0
- package/dist/commands/run-poc.js +18 -0
- package/dist/commands/setup.d.ts +3 -0
- package/dist/commands/setup.js +66 -0
- package/dist/commands/start-poc.d.ts +3 -0
- package/dist/commands/start-poc.js +55 -0
- package/dist/commands/sync-docs.d.ts +3 -0
- package/dist/commands/sync-docs.js +27 -0
- package/dist/commands/translate.d.ts +13 -0
- package/dist/commands/translate.js +401 -0
- package/dist/commands/upload.d.ts +3 -0
- package/dist/commands/upload.js +150 -0
- package/dist/commands/workflow-info.d.ts +13 -0
- package/dist/commands/workflow-info.js +161 -0
- package/dist/components/ConflictResolver.d.ts +12 -0
- package/dist/components/ConflictResolver.js +77 -0
- package/dist/components/DiffView.d.ts +11 -0
- package/dist/components/DiffView.js +101 -0
- package/dist/components/DownloadProgress.d.ts +11 -0
- package/dist/components/DownloadProgress.js +29 -0
- package/dist/components/RecordPreview.d.ts +11 -0
- package/dist/components/RecordPreview.js +91 -0
- package/dist/components/SetupForm.d.ts +8 -0
- package/dist/components/SetupForm.js +56 -0
- package/dist/components/UploadProgress.d.ts +13 -0
- package/dist/components/UploadProgress.js +42 -0
- package/dist/diff/adapters/index.d.ts +8 -0
- package/dist/diff/adapters/index.js +18 -0
- package/dist/diff/adapters/objectsAdapter.d.ts +13 -0
- package/dist/diff/adapters/objectsAdapter.js +177 -0
- package/dist/diff/adapters/reportsAdapter.d.ts +14 -0
- package/dist/diff/adapters/reportsAdapter.js +212 -0
- package/dist/diff/adapters/types.d.ts +19 -0
- package/dist/diff/adapters/types.js +2 -0
- package/dist/diff/engine.d.ts +19 -0
- package/dist/diff/engine.js +57 -0
- package/dist/diff/types.d.ts +34 -0
- package/dist/diff/types.js +110 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +117 -0
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/api.d.ts +85 -0
- package/dist/utils/api.js +1031 -0
- package/dist/utils/auth.d.ts +4 -0
- package/dist/utils/auth.js +22 -0
- package/dist/utils/bfySplitter.d.ts +12 -0
- package/dist/utils/bfySplitter.js +151 -0
- package/dist/utils/docs.d.ts +16 -0
- package/dist/utils/docs.js +186 -0
- package/dist/utils/errorLogger.d.ts +6 -0
- package/dist/utils/errorLogger.js +29 -0
- package/dist/utils/files.d.ts +14 -0
- package/dist/utils/files.js +772 -0
- package/dist/utils/lockManager.d.ts +15 -0
- package/dist/utils/lockManager.js +126 -0
- package/dist/utils/resourceHandlers.d.ts +50 -0
- package/dist/utils/resourceHandlers.js +684 -0
- package/dist/utils/resourceMapping.d.ts +32 -0
- package/dist/utils/resourceMapping.js +210 -0
- package/dist/utils/singleResourceDownload.d.ts +14 -0
- package/dist/utils/singleResourceDownload.js +261 -0
- package/dist/utils/summaryGenerator.d.ts +2 -0
- package/dist/utils/summaryGenerator.js +183 -0
- package/dist/utils/uploadHandler.d.ts +31 -0
- package/dist/utils/uploadHandler.js +263 -0
- package/docs/AI_API.md +93 -0
- package/docs/CLAUDE.md +216 -0
- package/docs/PROJECT_SPECIFIC.md +1 -0
- package/docs/RECORD_COMMAND.md +262 -0
- package/docs/WORKFLOW_API.md +480 -0
- package/docs/bfy-splitting.md +126 -0
- package/docs/cli-commands.md +333 -0
- package/docs/examples/README.md +95 -0
- package/docs/examples/order-system.md +147 -0
- package/docs/examples/product-catalog.md +195 -0
- package/docs/examples/reports.md +187 -0
- package/docs/excel-export.md +216 -0
- package/docs/field-types/README.md +29 -0
- package/docs/field-types/calculated.md +147 -0
- package/docs/field-types/code-mappings.md +84 -0
- package/docs/field-types/custom.md +340 -0
- package/docs/object-specs/README.md +136 -0
- package/docs/object-specs/code-parameters.md +151 -0
- package/docs/object-specs/creating.md +203 -0
- package/docs/object-specs/js-code-examples.md +208 -0
- package/docs/object-specs/js-field-updates.md +168 -0
- package/docs/objects/README.md +89 -0
- package/docs/objects/creating.md +127 -0
- package/docs/page-layout.md +361 -0
- package/docs/permissions.md +260 -0
- package/docs/reports.md +197 -0
- package/docs/state-machines.md +544 -0
- package/docs/tasks/create-object.md +81 -0
- package/docs/translations.md +346 -0
- package/docs/twig-helpers.md +283 -0
- package/docs/webservices.md +159 -0
- package/docs/workspaces.md +176 -0
- package/package.json +59 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Calculated Field Type
|
|
2
|
+
|
|
3
|
+
Computed field using Twig expressions. Value is calculated server-side.
|
|
4
|
+
|
|
5
|
+
## Type
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
type: "calculated"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Parameters
|
|
12
|
+
|
|
13
|
+
| Field | Type | Description |
|
|
14
|
+
|-------|------|-------------|
|
|
15
|
+
| `val_1` | string | Twig code for calculation |
|
|
16
|
+
|
|
17
|
+
## File Export
|
|
18
|
+
|
|
19
|
+
When downloaded, `val_1` is exported to `code.bfy`.
|
|
20
|
+
|
|
21
|
+
## Basic Example
|
|
22
|
+
|
|
23
|
+
Calculate total from price and quantity:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
butterfly-cli record add object_specs --data '{
|
|
27
|
+
"object_id": 128,
|
|
28
|
+
"name": "Total",
|
|
29
|
+
"column_name": "total",
|
|
30
|
+
"type": "calculated",
|
|
31
|
+
"val_1": "{{ info.price * info.quantity }}"
|
|
32
|
+
}'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Available Variables
|
|
36
|
+
|
|
37
|
+
| Variable | Description |
|
|
38
|
+
|----------|-------------|
|
|
39
|
+
| `info` | Current record data (e.g., `info.price`, `info.quantity`) |
|
|
40
|
+
| `_user` | Current logged-in user |
|
|
41
|
+
| `_GET` | GET parameters |
|
|
42
|
+
| `_POST` | POST parameters |
|
|
43
|
+
|
|
44
|
+
## Examples
|
|
45
|
+
|
|
46
|
+
### Simple Math
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
butterfly-cli record add object_specs --data '{
|
|
50
|
+
"object_id": 128,
|
|
51
|
+
"name": "Tax Amount",
|
|
52
|
+
"column_name": "tax_amount",
|
|
53
|
+
"type": "calculated",
|
|
54
|
+
"val_1": "{{ info.subtotal * 0.18 }}"
|
|
55
|
+
}'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### String Concatenation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
butterfly-cli record add object_specs --data '{
|
|
62
|
+
"object_id": 128,
|
|
63
|
+
"name": "Full Name",
|
|
64
|
+
"column_name": "full_name",
|
|
65
|
+
"type": "calculated",
|
|
66
|
+
"val_1": "{{ info.first_name ~ \" \" ~ info.last_name }}"
|
|
67
|
+
}'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Conditional Value
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
butterfly-cli record add object_specs --data '{
|
|
74
|
+
"object_id": 128,
|
|
75
|
+
"name": "Status Label",
|
|
76
|
+
"column_name": "status_label",
|
|
77
|
+
"type": "calculated",
|
|
78
|
+
"val_1": "{% if info.status == 1 %}Active{% else %}Inactive{% endif %}"
|
|
79
|
+
}'
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Date Formatting
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
butterfly-cli record add object_specs --data '{
|
|
86
|
+
"object_id": 128,
|
|
87
|
+
"name": "Formatted Date",
|
|
88
|
+
"column_name": "formatted_date",
|
|
89
|
+
"type": "calculated",
|
|
90
|
+
"val_1": "{{ info.created_at|date(\"d/m/Y\") }}"
|
|
91
|
+
}'
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Database Query
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
butterfly-cli record add object_specs --data '{
|
|
98
|
+
"object_id": 128,
|
|
99
|
+
"name": "Order Count",
|
|
100
|
+
"column_name": "order_count",
|
|
101
|
+
"type": "calculated",
|
|
102
|
+
"val_1": "{% set count = db().table(\"orders\").where(\"customer_id\", info.id).count() %}{{ count }}"
|
|
103
|
+
}'
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Related Record Lookup
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
butterfly-cli record add object_specs --data '{
|
|
110
|
+
"object_id": 128,
|
|
111
|
+
"name": "Category Name",
|
|
112
|
+
"column_name": "category_name",
|
|
113
|
+
"type": "calculated",
|
|
114
|
+
"val_1": "{% set cat = db().table(\"categories\").where(\"id\", info.category_id).first() %}{{ cat.name|default(\"-\") }}"
|
|
115
|
+
}'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Price with Currency
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
butterfly-cli record add object_specs --data '{
|
|
122
|
+
"object_id": 128,
|
|
123
|
+
"name": "Price Display",
|
|
124
|
+
"column_name": "price_display",
|
|
125
|
+
"type": "calculated",
|
|
126
|
+
"val_1": "{{ info.price|number_format(2, \",\", \".\") }} TL"
|
|
127
|
+
}'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Complex Calculation
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
butterfly-cli record add object_specs --data '{
|
|
134
|
+
"object_id": 128,
|
|
135
|
+
"name": "Grand Total",
|
|
136
|
+
"column_name": "grand_total",
|
|
137
|
+
"type": "calculated",
|
|
138
|
+
"val_1": "{% set subtotal = info.price * info.quantity %}{% set discount = subtotal * (info.discount_percent / 100) %}{% set tax = (subtotal - discount) * 0.18 %}{{ subtotal - discount + tax }}"
|
|
139
|
+
}'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Notes
|
|
143
|
+
|
|
144
|
+
- Calculated fields are read-only in the form
|
|
145
|
+
- Values are recalculated on each view/save
|
|
146
|
+
- Use `|default()` filter for null handling
|
|
147
|
+
- Complex calculations should be tested with the `code` command first
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Field Type Code Parameter Mappings
|
|
2
|
+
|
|
3
|
+
The CLI automatically exports code parameters from field specs based on their field types. Only parameters that contain actual code/configuration are exported as separate files.
|
|
4
|
+
|
|
5
|
+
## Field Types That Export Code Files
|
|
6
|
+
|
|
7
|
+
| Field Type | Parameter | Exported File | Description |
|
|
8
|
+
|------------|-----------|---------------|-------------|
|
|
9
|
+
| `calculated` | `val_1` | `code.bfy` | Twig calculation code |
|
|
10
|
+
| `custom` | `val_1` | `template_code.bfy` | Twig template code |
|
|
11
|
+
| `custom` | `val_2` | `processing_code.bfy` | Twig processing code |
|
|
12
|
+
| `filter` | `val_3` | `filter_code.bfy` | Twig filter code |
|
|
13
|
+
| `nested` | `val_1` | `configuration.yaml` | YAML configuration |
|
|
14
|
+
| `nested_single` | `val_1` | `configuration.yaml` | YAML configuration |
|
|
15
|
+
|
|
16
|
+
## Object Spec Fields That Export Code Files
|
|
17
|
+
|
|
18
|
+
| Field | Exported File | Description |
|
|
19
|
+
|-------|---------------|-------------|
|
|
20
|
+
| `js_code` | `code.js` | JavaScript code |
|
|
21
|
+
| `css_code` | `style.css` | CSS code |
|
|
22
|
+
|
|
23
|
+
## Field Types That DO NOT Export Code Files
|
|
24
|
+
|
|
25
|
+
- **code**: Despite the name, this field type only stores dropdown selections for code language and AI tasks, not actual code content
|
|
26
|
+
- All other field types: Only contain string, dropdown, integer, or checkbox parameters
|
|
27
|
+
|
|
28
|
+
## Object Files Exported
|
|
29
|
+
|
|
30
|
+
| File | Description |
|
|
31
|
+
|------|-------------|
|
|
32
|
+
| `object.json` | Complete object definition |
|
|
33
|
+
| `listing_query.bfy` | Object's listing query (if present) |
|
|
34
|
+
|
|
35
|
+
## Report Files Exported
|
|
36
|
+
|
|
37
|
+
| File | Description |
|
|
38
|
+
|------|-------------|
|
|
39
|
+
| `report.json` | Report definition from `cms_reports` |
|
|
40
|
+
| `main_query.bfy` | **DEPRECATED** - legacy file, do not use |
|
|
41
|
+
| `categories.json` | All report categories (shared file) |
|
|
42
|
+
|
|
43
|
+
### Report Query Files
|
|
44
|
+
|
|
45
|
+
| File | Description |
|
|
46
|
+
|------|-------------|
|
|
47
|
+
| `query.json` | Query definition from `cms_report_queries` |
|
|
48
|
+
| `query_code.bfy` | Twig code from `query` field |
|
|
49
|
+
| `script.js` | JavaScript from `js_code` field (if exists) |
|
|
50
|
+
|
|
51
|
+
### Report Spec Files
|
|
52
|
+
|
|
53
|
+
| File | Description |
|
|
54
|
+
|------|-------------|
|
|
55
|
+
| `spec.json` | Spec definition from `cms_report_specs` |
|
|
56
|
+
| `code.js` | JavaScript from `js_code` field (if exists) |
|
|
57
|
+
|
|
58
|
+
## Directory Structure
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
butterfly-resources/
|
|
62
|
+
└── objects/
|
|
63
|
+
└── [butterfly|app]/
|
|
64
|
+
└── [table_name]/
|
|
65
|
+
├── object.json
|
|
66
|
+
├── listing_query.bfy
|
|
67
|
+
└── [field_name]/
|
|
68
|
+
├── spec.json
|
|
69
|
+
├── code.bfy # For calculated
|
|
70
|
+
├── template_code.bfy # For custom (val_1)
|
|
71
|
+
├── processing_code.bfy # For custom (val_2)
|
|
72
|
+
├── filter_code.bfy # For filter
|
|
73
|
+
├── configuration.yaml # For nested/nested_single
|
|
74
|
+
├── code.js # If js_code exists
|
|
75
|
+
└── style.css # If css_code exists
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Usage Notes
|
|
79
|
+
|
|
80
|
+
1. **Report specs use the same field types** as object specs. Use the same `type` and `val_*` parameter conventions.
|
|
81
|
+
|
|
82
|
+
2. **When creating reports**, always use `cms_report_queries` for Twig query code. The `query` field in `cms_reports` is deprecated.
|
|
83
|
+
|
|
84
|
+
3. **Code files can be uploaded** using `butterfly-cli upload <path>`.
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# Custom Field Type
|
|
2
|
+
|
|
3
|
+
Custom field with Twig template for display and processing code for form submissions.
|
|
4
|
+
|
|
5
|
+
## Type
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
type: "custom"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Parameters
|
|
12
|
+
|
|
13
|
+
| Field | Type | Description |
|
|
14
|
+
|-------|------|-------------|
|
|
15
|
+
| `val_1` | string | Template code (Twig) - rendered in form |
|
|
16
|
+
| `val_2` | string | Processing code (Twig) - executed on submit |
|
|
17
|
+
|
|
18
|
+
## File Export
|
|
19
|
+
|
|
20
|
+
When downloaded:
|
|
21
|
+
- `val_1` → `template_code.bfy`
|
|
22
|
+
- `val_2` → `processing_code.bfy`
|
|
23
|
+
|
|
24
|
+
## Basic Example
|
|
25
|
+
|
|
26
|
+
Button that sets a field value:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
butterfly-cli record add object_specs --data '{
|
|
30
|
+
"object_id": 128,
|
|
31
|
+
"name": "Process",
|
|
32
|
+
"column_name": "process_action",
|
|
33
|
+
"type": "custom",
|
|
34
|
+
"val_1": "<button type=\"submit\" name=\"process\" class=\"btn btn-primary\">Process</button>",
|
|
35
|
+
"val_2": "{% if _POST.process %}{{ setValue(\"status\", \"processed\") }}{% endif %}"
|
|
36
|
+
}'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Template Code (val_1)
|
|
40
|
+
|
|
41
|
+
The template is rendered in the edit form. Available variables:
|
|
42
|
+
|
|
43
|
+
| Variable | Description |
|
|
44
|
+
|----------|-------------|
|
|
45
|
+
| `info` | Current record data (e.g., `info.title`, `info.status`) |
|
|
46
|
+
| `_user` | Current logged-in user |
|
|
47
|
+
| `id` | Current record ID |
|
|
48
|
+
|
|
49
|
+
### Display Information
|
|
50
|
+
|
|
51
|
+
```twig
|
|
52
|
+
<div class="alert alert-info">
|
|
53
|
+
Created by: {{ info.created_by_name }}<br>
|
|
54
|
+
Created at: {{ info.created_at|date("d/m/Y H:i") }}
|
|
55
|
+
</div>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Button with Confirmation
|
|
59
|
+
|
|
60
|
+
```twig
|
|
61
|
+
<button type="submit" name="approve" class="btn btn-success"
|
|
62
|
+
onclick="return confirm('Are you sure?')">
|
|
63
|
+
Approve
|
|
64
|
+
</button>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Input Masking
|
|
68
|
+
|
|
69
|
+
```twig
|
|
70
|
+
<input type="text" name="phone" id="phone" class="form-control" value="{{ info.phone }}">
|
|
71
|
+
<script>
|
|
72
|
+
Inputmask('(599) 999 99 99').mask($('#phone'));
|
|
73
|
+
</script>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Processing Code (val_2)
|
|
77
|
+
|
|
78
|
+
Executed when form is submitted. Available functions:
|
|
79
|
+
|
|
80
|
+
| Function | Description |
|
|
81
|
+
|----------|-------------|
|
|
82
|
+
| `setValue(column, value)` | Set field value |
|
|
83
|
+
| `getValue(column)` | Get field value |
|
|
84
|
+
| `errorMessage(msg)` | Show error and stop |
|
|
85
|
+
| `crud()` | CRUD operations on other tables |
|
|
86
|
+
| `db()` | Database queries |
|
|
87
|
+
|
|
88
|
+
### Set Value
|
|
89
|
+
|
|
90
|
+
```twig
|
|
91
|
+
{% if _POST.approve %}
|
|
92
|
+
{{ setValue('status', 'approved') }}
|
|
93
|
+
{{ setValue('approved_at', 'now'|date('Y-m-d H:i:s')) }}
|
|
94
|
+
{{ setValue('approved_by', _user.id) }}
|
|
95
|
+
{% endif %}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Insert Related Record
|
|
99
|
+
|
|
100
|
+
```twig
|
|
101
|
+
{% if _POST.create_invoice %}
|
|
102
|
+
{% set response = crud()
|
|
103
|
+
.table('invoices')
|
|
104
|
+
.insert({
|
|
105
|
+
"order_id": getValue('id'),
|
|
106
|
+
"amount": getValue('total'),
|
|
107
|
+
"status": "draft"
|
|
108
|
+
})
|
|
109
|
+
%}
|
|
110
|
+
{% if response.success %}
|
|
111
|
+
{{ setValue('invoice_id', response.id) }}
|
|
112
|
+
{% else %}
|
|
113
|
+
{{ errorMessage(response.message) }}
|
|
114
|
+
{% endif %}
|
|
115
|
+
{% endif %}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Update Related Record
|
|
119
|
+
|
|
120
|
+
```twig
|
|
121
|
+
{% if _POST.update_stock %}
|
|
122
|
+
{% set response = crud()
|
|
123
|
+
.table('products')
|
|
124
|
+
.update({
|
|
125
|
+
"id": getValue('product_id'),
|
|
126
|
+
"stock": getValue('new_stock')
|
|
127
|
+
})
|
|
128
|
+
%}
|
|
129
|
+
{% endif %}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Validation
|
|
133
|
+
|
|
134
|
+
```twig
|
|
135
|
+
{% if _POST.submit %}
|
|
136
|
+
{% if getValue('quantity') < 1 %}
|
|
137
|
+
{{ errorMessage('Quantity must be at least 1') }}
|
|
138
|
+
{% endif %}
|
|
139
|
+
{% if getValue('price') <= 0 %}
|
|
140
|
+
{{ errorMessage('Price must be positive') }}
|
|
141
|
+
{% endif %}
|
|
142
|
+
{% endif %}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Query and Update
|
|
146
|
+
|
|
147
|
+
```twig
|
|
148
|
+
{% if _POST.apply_discount %}
|
|
149
|
+
{% set product = db().table('products').where('id', getValue('product_id')).first() %}
|
|
150
|
+
{% set discounted = product.price * 0.9 %}
|
|
151
|
+
{{ setValue('final_price', discounted) }}
|
|
152
|
+
{% endif %}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Complete Examples
|
|
156
|
+
|
|
157
|
+
### Approval Button
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
butterfly-cli record add object_specs --data '{
|
|
161
|
+
"object_id": 128,
|
|
162
|
+
"name": "Approval",
|
|
163
|
+
"column_name": "approval_action",
|
|
164
|
+
"type": "custom",
|
|
165
|
+
"val_1": "{% if info.status != \"approved\" %}<button type=\"submit\" name=\"approve\" class=\"btn btn-success\">Approve</button>{% else %}<span class=\"badge bg-success\">Approved</span>{% endif %}",
|
|
166
|
+
"val_2": "{% if _POST.approve %}{{ setValue(\"status\", \"approved\") }}{{ setValue(\"approved_at\", \"now\"|date(\"Y-m-d H:i:s\")) }}{% endif %}"
|
|
167
|
+
}'
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Status Workflow
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
butterfly-cli record add object_specs --data '{
|
|
174
|
+
"object_id": 128,
|
|
175
|
+
"name": "Actions",
|
|
176
|
+
"column_name": "workflow_actions",
|
|
177
|
+
"type": "custom",
|
|
178
|
+
"val_1": "{% if info.status == \"draft\" %}<button type=\"submit\" name=\"submit_review\" class=\"btn btn-primary\">Submit for Review</button>{% elseif info.status == \"review\" %}<button type=\"submit\" name=\"approve\" class=\"btn btn-success\">Approve</button> <button type=\"submit\" name=\"reject\" class=\"btn btn-danger\">Reject</button>{% endif %}",
|
|
179
|
+
"val_2": "{% if _POST.submit_review %}{{ setValue(\"status\", \"review\") }}{% elseif _POST.approve %}{{ setValue(\"status\", \"approved\") }}{% elseif _POST.reject %}{{ setValue(\"status\", \"rejected\") }}{% endif %}"
|
|
180
|
+
}'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Notes
|
|
184
|
+
|
|
185
|
+
- Custom fields don't create database columns
|
|
186
|
+
- Use for actions, computed displays, and form submissions
|
|
187
|
+
- Template code runs on every page load
|
|
188
|
+
- Processing code runs only on form submit
|
|
189
|
+
|
|
190
|
+
> **IMPORTANT - Form Input Naming:** Custom fields use `column_name=1` internally to enable the field. When adding form inputs in `template_code`, you MUST use a different `name` attribute than the field's `column_name`. For example, if the custom field's `column_name` is `my_field`, use `<input name="my_field_value" />` instead of `<input name="my_field" />` to avoid conflicts.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Advanced Processing Code Patterns
|
|
195
|
+
|
|
196
|
+
### Block After (Post-Save Processing)
|
|
197
|
+
|
|
198
|
+
By default, `processing_code` runs **BEFORE** form data is saved. If you use `setValue()` on a field that's in the form, the form POST value will override it.
|
|
199
|
+
|
|
200
|
+
To run code **AFTER** save, use `{% block after %}`:
|
|
201
|
+
|
|
202
|
+
```twig
|
|
203
|
+
{% block after %}
|
|
204
|
+
{{ setValue('calculated_total', getValue('quantity') * getValue('price')) }}
|
|
205
|
+
{{ setValue('updated_at', 'now'|date('Y-m-d H:i:s')) }}
|
|
206
|
+
{% endblock %}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
> **Important:** `{% block after %}` is **isolated** - it cannot access variables from the main processing_code block. Use `getValue()` or `db()` queries to get data.
|
|
210
|
+
|
|
211
|
+
#### Execution Order
|
|
212
|
+
|
|
213
|
+
1. `processing_code` (main block) - runs BEFORE save
|
|
214
|
+
2. Form POST data is saved to database
|
|
215
|
+
3. `{% block after %}` - runs AFTER save (isolated scope)
|
|
216
|
+
|
|
217
|
+
#### Wrong vs Correct
|
|
218
|
+
|
|
219
|
+
```twig
|
|
220
|
+
{# WRONG - variable from main block NOT accessible #}
|
|
221
|
+
{% set myValue = 5 %}
|
|
222
|
+
{% block after %}
|
|
223
|
+
{{ setValue('test_id', myValue) }} {# ERROR: myValue is undefined #}
|
|
224
|
+
{% endblock %}
|
|
225
|
+
|
|
226
|
+
{# CORRECT - use getValue() or hardcoded values #}
|
|
227
|
+
{% block after %}
|
|
228
|
+
{{ setValue('test_id', 5) }}
|
|
229
|
+
{{ setValue('total', getValue('quantity') * getValue('price')) }}
|
|
230
|
+
|
|
231
|
+
{# Fetch data using db() #}
|
|
232
|
+
{% set related = db().table('other_table').where('id', getValue('related_id')).first() %}
|
|
233
|
+
{{ setValue('related_name', related.name) }}
|
|
234
|
+
{% endblock %}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Page Refresh After Save
|
|
238
|
+
|
|
239
|
+
To refresh the page after save (edit operations only):
|
|
240
|
+
|
|
241
|
+
```twig
|
|
242
|
+
{{ registry('page_refresh', 1) }}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Use when:
|
|
246
|
+
- Twig conditions in template_code depend on saved values
|
|
247
|
+
- UI elements need to update based on new state
|
|
248
|
+
- Calculated/displayed fields need immediate refresh
|
|
249
|
+
|
|
250
|
+
> **Note:** Add operations already refresh/redirect by default.
|
|
251
|
+
|
|
252
|
+
### Accessing Current Record Data
|
|
253
|
+
|
|
254
|
+
| Context | Method | Example |
|
|
255
|
+
|---------|--------|---------|
|
|
256
|
+
| `template_code` | `info.column` | `{{ info.title }}` |
|
|
257
|
+
| `processing_code` | `getValue('column')` | `{{ getValue('title') }}` |
|
|
258
|
+
|
|
259
|
+
```twig
|
|
260
|
+
{# In template_code.bfy #}
|
|
261
|
+
{{ info.title }}
|
|
262
|
+
{{ info.status }}
|
|
263
|
+
{% if info.is_active == 1 %}Active{% endif %}
|
|
264
|
+
|
|
265
|
+
{# In processing_code.bfy #}
|
|
266
|
+
{% set title = getValue('title') %}
|
|
267
|
+
{% if getValue('status') == 'pending' %}
|
|
268
|
+
{{ setValue('status', 'processed') }}
|
|
269
|
+
{% endif %}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Getting Request Parameters
|
|
273
|
+
|
|
274
|
+
```twig
|
|
275
|
+
{# Get POST or GET parameter #}
|
|
276
|
+
{% set userId = getParameter('user_id') %}
|
|
277
|
+
|
|
278
|
+
{# Conditional logic #}
|
|
279
|
+
{% if getParameter('action') == 'approve' %}
|
|
280
|
+
{{ setValue('status', 'approved') }}
|
|
281
|
+
{% endif %}
|
|
282
|
+
|
|
283
|
+
{# Multiple parameters #}
|
|
284
|
+
{% set data = {
|
|
285
|
+
"name": getParameter('name'),
|
|
286
|
+
"email": getParameter('email'),
|
|
287
|
+
"phone": getParameter('phone')
|
|
288
|
+
} %}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### CRUD Operations in Processing Code
|
|
292
|
+
|
|
293
|
+
#### Insert
|
|
294
|
+
|
|
295
|
+
```twig
|
|
296
|
+
{% set response = crud()
|
|
297
|
+
.table('TARGET_TABLE')
|
|
298
|
+
.insert({
|
|
299
|
+
"field_name": "value"
|
|
300
|
+
})
|
|
301
|
+
%}
|
|
302
|
+
|
|
303
|
+
{% if response.success %}
|
|
304
|
+
{{ response.id }}
|
|
305
|
+
{% else %}
|
|
306
|
+
{{ errorMessage(response.message) }}
|
|
307
|
+
{% endif %}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### Update
|
|
311
|
+
|
|
312
|
+
```twig
|
|
313
|
+
{% set response = crud()
|
|
314
|
+
.table('TARGET_TABLE')
|
|
315
|
+
.update({
|
|
316
|
+
"id": "RECORD_ID",
|
|
317
|
+
"field_name": "value"
|
|
318
|
+
})
|
|
319
|
+
%}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### Delete
|
|
323
|
+
|
|
324
|
+
```twig
|
|
325
|
+
{% set response = crud()
|
|
326
|
+
.table('TARGET_TABLE')
|
|
327
|
+
.delete({
|
|
328
|
+
"id": "RECORD_ID"
|
|
329
|
+
})
|
|
330
|
+
%}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
#### For Webservices (No Auth)
|
|
334
|
+
|
|
335
|
+
```twig
|
|
336
|
+
{% set response = crud('default', false)
|
|
337
|
+
.table('TARGET_TABLE')
|
|
338
|
+
.insert({...})
|
|
339
|
+
%}
|
|
340
|
+
```
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Object Specs
|
|
2
|
+
|
|
3
|
+
Object specs define the fields (columns) of an object. Each spec represents a form field and database column.
|
|
4
|
+
|
|
5
|
+
## Table: `object_specs`
|
|
6
|
+
|
|
7
|
+
## Required Fields
|
|
8
|
+
|
|
9
|
+
| Field | Type | Description |
|
|
10
|
+
|-------|------|-------------|
|
|
11
|
+
| `object_id` | int | Parent object ID |
|
|
12
|
+
| `name` | string | Display label |
|
|
13
|
+
| `column_name` | string | Database column name |
|
|
14
|
+
| `type` | string | Field type (see [Field Types](../field-types/README.md)) |
|
|
15
|
+
|
|
16
|
+
## Common Fields
|
|
17
|
+
|
|
18
|
+
| Field | Type | Default | Description |
|
|
19
|
+
|-------|------|---------|-------------|
|
|
20
|
+
| `required` | int | `0` | `1` = required field |
|
|
21
|
+
| `list_column` | int | `0` | `1` = show in list view |
|
|
22
|
+
| `search_column` | int | `0` | `1` = searchable |
|
|
23
|
+
| `edit_order_no` | int | null | Order in edit form |
|
|
24
|
+
| `list_order_no` | int | null | Order in list view |
|
|
25
|
+
| `default_value` | string | null | Default value |
|
|
26
|
+
| `description` | string | null | Help text |
|
|
27
|
+
|
|
28
|
+
## Display Fields
|
|
29
|
+
|
|
30
|
+
| Field | Type | Description |
|
|
31
|
+
|-------|------|-------------|
|
|
32
|
+
| `width` | int | Field width |
|
|
33
|
+
| `height` | int | Field height (for textarea) |
|
|
34
|
+
| `column_size` | string | Bootstrap column size (e.g., "col-md-6") |
|
|
35
|
+
| `section_title` | string | Section header above field |
|
|
36
|
+
| `edit_position` | int | Position: `0`=main, `1`=sidebar |
|
|
37
|
+
| `edit_place_no` | int | Place number within position |
|
|
38
|
+
|
|
39
|
+
## Validation Fields
|
|
40
|
+
|
|
41
|
+
| Field | Type | Description |
|
|
42
|
+
|-------|------|-------------|
|
|
43
|
+
| `validation_type` | string | Validation rule |
|
|
44
|
+
| `manipulation_type` | string | Data manipulation |
|
|
45
|
+
| `is_readonly` | int | `1` = read-only field |
|
|
46
|
+
| `is_sensitive` | int | `1` = sensitive data (masked) |
|
|
47
|
+
|
|
48
|
+
## Code Fields
|
|
49
|
+
|
|
50
|
+
| Field | Type | Description | Export File |
|
|
51
|
+
|-------|------|-------------|-------------|
|
|
52
|
+
| `js_code` | string | JavaScript for field behavior | `code.js` |
|
|
53
|
+
| `css_code` | string | Custom CSS styles | `style.css` |
|
|
54
|
+
|
|
55
|
+
## Type-Specific Value Fields
|
|
56
|
+
|
|
57
|
+
| Field | Description |
|
|
58
|
+
|-------|-------------|
|
|
59
|
+
| `val_1` | Type-specific parameter 1 |
|
|
60
|
+
| `val_2` | Type-specific parameter 2 |
|
|
61
|
+
| `val_3` | Type-specific parameter 3 |
|
|
62
|
+
| `val_4` | Type-specific parameter 4 |
|
|
63
|
+
| `val_5` | Type-specific parameter 5 |
|
|
64
|
+
|
|
65
|
+
See [Field Types](../field-types/README.md) for what each `val_*` means per type.
|
|
66
|
+
|
|
67
|
+
## Creating a Spec
|
|
68
|
+
|
|
69
|
+
### Basic String Field
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
butterfly-cli record add object_specs --data '{
|
|
73
|
+
"object_id": 128,
|
|
74
|
+
"name": "Title",
|
|
75
|
+
"column_name": "title",
|
|
76
|
+
"type": "string",
|
|
77
|
+
"required": 1,
|
|
78
|
+
"list_column": 1,
|
|
79
|
+
"edit_order_no": 1
|
|
80
|
+
}'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Dropdown Field
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
butterfly-cli record add object_specs --data '{
|
|
87
|
+
"object_id": 128,
|
|
88
|
+
"name": "Status",
|
|
89
|
+
"column_name": "status",
|
|
90
|
+
"type": "from_list",
|
|
91
|
+
"val_1": "active:Active,inactive:Inactive,pending:Pending",
|
|
92
|
+
"edit_order_no": 2
|
|
93
|
+
}'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Foreign Key (dropdown)
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
butterfly-cli record add object_specs --data '{
|
|
100
|
+
"object_id": 128,
|
|
101
|
+
"name": "Category",
|
|
102
|
+
"column_name": "category_id",
|
|
103
|
+
"type": "dropdown",
|
|
104
|
+
"val_1": "categories",
|
|
105
|
+
"val_2": "id",
|
|
106
|
+
"val_3": "name",
|
|
107
|
+
"edit_order_no": 3
|
|
108
|
+
}'
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Get Specs for an Object
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
butterfly-cli record get object_specs --column object_id --value 128
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Update a Spec
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
butterfly-cli record edit object_specs --id 1071 --data '{
|
|
121
|
+
"required": 1,
|
|
122
|
+
"list_column": 1
|
|
123
|
+
}'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Delete a Spec
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
butterfly-cli record delete object_specs --id 1071
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Related
|
|
133
|
+
|
|
134
|
+
- [Creating Specs Guide](./creating.md)
|
|
135
|
+
- [Code Parameters](./code-parameters.md)
|
|
136
|
+
- [Field Types Reference](../field-types/README.md)
|