@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,195 @@
|
|
|
1
|
+
# Product Catalog Example
|
|
2
|
+
|
|
3
|
+
Complete example for creating an e-commerce product catalog.
|
|
4
|
+
|
|
5
|
+
## Step 1: Create Categories Object
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Create object
|
|
9
|
+
butterfly-cli record add objects --data '{
|
|
10
|
+
"name": "Product Categories",
|
|
11
|
+
"table_name": "product_categories",
|
|
12
|
+
"has_order": 1
|
|
13
|
+
}'
|
|
14
|
+
# Note the ID (e.g., 150)
|
|
15
|
+
|
|
16
|
+
# Add fields
|
|
17
|
+
butterfly-cli record add object_specs --data '{"object_id":150,"name":"Name","column_name":"name","type":"string","required":1,"list_column":1,"edit_order_no":1}'
|
|
18
|
+
butterfly-cli record add object_specs --data '{"object_id":150,"name":"Slug","column_name":"slug","type":"slug","edit_order_no":2}'
|
|
19
|
+
butterfly-cli record add object_specs --data '{"object_id":150,"name":"Parent","column_name":"parent_id","type":"dropdown","val_1":"product_categories","val_2":"id","val_3":"name","edit_order_no":3}'
|
|
20
|
+
butterfly-cli record add object_specs --data '{"object_id":150,"name":"Active","column_name":"is_active","type":"checkbox","default_value":"1","edit_order_no":4}'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Step 2: Create Products Object
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Create object
|
|
27
|
+
butterfly-cli record add objects --data '{
|
|
28
|
+
"name": "Products",
|
|
29
|
+
"table_name": "products",
|
|
30
|
+
"has_trash": 1
|
|
31
|
+
}'
|
|
32
|
+
# Note the ID (e.g., 151)
|
|
33
|
+
|
|
34
|
+
# Basic Info Section
|
|
35
|
+
butterfly-cli record add object_specs --data '{
|
|
36
|
+
"object_id": 151,
|
|
37
|
+
"name": "Title",
|
|
38
|
+
"column_name": "title",
|
|
39
|
+
"type": "string",
|
|
40
|
+
"required": 1,
|
|
41
|
+
"list_column": 1,
|
|
42
|
+
"search_column": 1,
|
|
43
|
+
"section_title": "Basic Information",
|
|
44
|
+
"edit_order_no": 1
|
|
45
|
+
}'
|
|
46
|
+
|
|
47
|
+
butterfly-cli record add object_specs --data '{
|
|
48
|
+
"object_id": 151,
|
|
49
|
+
"name": "SKU",
|
|
50
|
+
"column_name": "sku",
|
|
51
|
+
"type": "string",
|
|
52
|
+
"list_column": 1,
|
|
53
|
+
"column_size": "col-md-6",
|
|
54
|
+
"edit_order_no": 2
|
|
55
|
+
}'
|
|
56
|
+
|
|
57
|
+
butterfly-cli record add object_specs --data '{
|
|
58
|
+
"object_id": 151,
|
|
59
|
+
"name": "Category",
|
|
60
|
+
"column_name": "category_id",
|
|
61
|
+
"type": "dropdown",
|
|
62
|
+
"val_1": "product_categories",
|
|
63
|
+
"val_2": "id",
|
|
64
|
+
"val_3": "name",
|
|
65
|
+
"val_4": "is_active = 1",
|
|
66
|
+
"column_size": "col-md-6",
|
|
67
|
+
"edit_order_no": 3
|
|
68
|
+
}'
|
|
69
|
+
|
|
70
|
+
butterfly-cli record add object_specs --data '{
|
|
71
|
+
"object_id": 151,
|
|
72
|
+
"name": "Description",
|
|
73
|
+
"column_name": "description",
|
|
74
|
+
"type": "textarea",
|
|
75
|
+
"height": 150,
|
|
76
|
+
"edit_order_no": 4
|
|
77
|
+
}'
|
|
78
|
+
|
|
79
|
+
# Pricing Section
|
|
80
|
+
butterfly-cli record add object_specs --data '{
|
|
81
|
+
"object_id": 151,
|
|
82
|
+
"name": "Price",
|
|
83
|
+
"column_name": "price",
|
|
84
|
+
"type": "decimal",
|
|
85
|
+
"required": 1,
|
|
86
|
+
"section_title": "Pricing",
|
|
87
|
+
"column_size": "col-md-4",
|
|
88
|
+
"edit_order_no": 5
|
|
89
|
+
}'
|
|
90
|
+
|
|
91
|
+
butterfly-cli record add object_specs --data '{
|
|
92
|
+
"object_id": 151,
|
|
93
|
+
"name": "Sale Price",
|
|
94
|
+
"column_name": "sale_price",
|
|
95
|
+
"type": "decimal",
|
|
96
|
+
"column_size": "col-md-4",
|
|
97
|
+
"edit_order_no": 6
|
|
98
|
+
}'
|
|
99
|
+
|
|
100
|
+
butterfly-cli record add object_specs --data '{
|
|
101
|
+
"object_id": 151,
|
|
102
|
+
"name": "Tax Rate %",
|
|
103
|
+
"column_name": "tax_rate",
|
|
104
|
+
"type": "decimal",
|
|
105
|
+
"default_value": "18",
|
|
106
|
+
"column_size": "col-md-4",
|
|
107
|
+
"edit_order_no": 7
|
|
108
|
+
}'
|
|
109
|
+
|
|
110
|
+
# Inventory Section
|
|
111
|
+
butterfly-cli record add object_specs --data '{
|
|
112
|
+
"object_id": 151,
|
|
113
|
+
"name": "Stock",
|
|
114
|
+
"column_name": "stock",
|
|
115
|
+
"type": "integer",
|
|
116
|
+
"default_value": "0",
|
|
117
|
+
"section_title": "Inventory",
|
|
118
|
+
"column_size": "col-md-6",
|
|
119
|
+
"edit_order_no": 8
|
|
120
|
+
}'
|
|
121
|
+
|
|
122
|
+
butterfly-cli record add object_specs --data '{
|
|
123
|
+
"object_id": 151,
|
|
124
|
+
"name": "Low Stock Alert",
|
|
125
|
+
"column_name": "low_stock_threshold",
|
|
126
|
+
"type": "integer",
|
|
127
|
+
"default_value": "5",
|
|
128
|
+
"column_size": "col-md-6",
|
|
129
|
+
"edit_order_no": 9
|
|
130
|
+
}'
|
|
131
|
+
|
|
132
|
+
# Media
|
|
133
|
+
butterfly-cli record add object_specs --data '{
|
|
134
|
+
"object_id": 151,
|
|
135
|
+
"name": "Image",
|
|
136
|
+
"column_name": "image",
|
|
137
|
+
"type": "image",
|
|
138
|
+
"section_title": "Media",
|
|
139
|
+
"edit_order_no": 10
|
|
140
|
+
}'
|
|
141
|
+
|
|
142
|
+
# Sidebar fields
|
|
143
|
+
butterfly-cli record add object_specs --data '{
|
|
144
|
+
"object_id": 151,
|
|
145
|
+
"name": "Status",
|
|
146
|
+
"column_name": "status",
|
|
147
|
+
"type": "from_list",
|
|
148
|
+
"val_1": "draft:Draft,active:Active,archived:Archived",
|
|
149
|
+
"default_value": "draft",
|
|
150
|
+
"edit_position": 1,
|
|
151
|
+
"edit_order_no": 1
|
|
152
|
+
}'
|
|
153
|
+
|
|
154
|
+
butterfly-cli record add object_specs --data '{
|
|
155
|
+
"object_id": 151,
|
|
156
|
+
"name": "Featured",
|
|
157
|
+
"column_name": "is_featured",
|
|
158
|
+
"type": "checkbox",
|
|
159
|
+
"edit_position": 1,
|
|
160
|
+
"edit_order_no": 2
|
|
161
|
+
}'
|
|
162
|
+
|
|
163
|
+
# Calculated field
|
|
164
|
+
butterfly-cli record add object_specs --data '{
|
|
165
|
+
"object_id": 151,
|
|
166
|
+
"name": "Final Price",
|
|
167
|
+
"column_name": "final_price",
|
|
168
|
+
"type": "calculated",
|
|
169
|
+
"val_1": "{% set base = info.sale_price > 0 ? info.sale_price : info.price %}{{ base * (1 + info.tax_rate/100) }}",
|
|
170
|
+
"edit_position": 1,
|
|
171
|
+
"edit_order_no": 3
|
|
172
|
+
}'
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Step 3: Verify
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
# Check products object
|
|
179
|
+
butterfly-cli record get objects --column table_name --value "products"
|
|
180
|
+
|
|
181
|
+
# List all product specs
|
|
182
|
+
butterfly-cli record get object_specs --column object_id --value 151
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Result
|
|
186
|
+
|
|
187
|
+
You now have:
|
|
188
|
+
- **Product Categories** with hierarchical structure
|
|
189
|
+
- **Products** with:
|
|
190
|
+
- Basic info (title, SKU, category, description)
|
|
191
|
+
- Pricing (price, sale price, tax rate)
|
|
192
|
+
- Inventory tracking
|
|
193
|
+
- Image upload
|
|
194
|
+
- Status workflow
|
|
195
|
+
- Calculated final price with tax
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Reports Example
|
|
2
|
+
|
|
3
|
+
Complete example for creating reports with queries and specs via CLI.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Reports in Butterfly consist of three related tables:
|
|
8
|
+
- `cms_reports` - Main report definition
|
|
9
|
+
- `cms_report_queries` - Sub-queries for the report
|
|
10
|
+
- `cms_report_specs` - Field specifications/columns for display
|
|
11
|
+
|
|
12
|
+
## Step 1: Create a Report
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Create the main report
|
|
16
|
+
butterfly-cli record add cms_reports --data '{
|
|
17
|
+
"name": "Sales Summary",
|
|
18
|
+
"alias": "sales_summary",
|
|
19
|
+
"query": "SELECT o.id, o.order_number, o.total, o.created_at, c.name as customer_name FROM orders o LEFT JOIN customers c ON o.customer_id = c.id WHERE 1=1 {% if filters.date_from %}AND o.created_at >= \"{{ filters.date_from }}\"{% endif %} {% if filters.date_to %}AND o.created_at <= \"{{ filters.date_to }}\"{% endif %}"
|
|
20
|
+
}'
|
|
21
|
+
# Response: SUCCESS (ID: 50)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Report Fields
|
|
25
|
+
|
|
26
|
+
| Field | Description |
|
|
27
|
+
|-------|-------------|
|
|
28
|
+
| `name` | Display name of the report |
|
|
29
|
+
| `alias` | URL-friendly identifier (used in file structure) |
|
|
30
|
+
| `query` | Main Twig/SQL query |
|
|
31
|
+
| `cms_report_category_id` | Category ID for grouping |
|
|
32
|
+
|
|
33
|
+
## Step 2: Add Report Queries
|
|
34
|
+
|
|
35
|
+
Report queries are sub-queries that can be used within the report.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Add a summary query
|
|
39
|
+
butterfly-cli record add cms_report_queries --data '{
|
|
40
|
+
"cms_report_id": 50,
|
|
41
|
+
"name": "totals",
|
|
42
|
+
"system_name": "totals",
|
|
43
|
+
"query": "SELECT COUNT(*) as order_count, SUM(total) as total_revenue FROM orders WHERE 1=1 {% if filters.date_from %}AND created_at >= \"{{ filters.date_from }}\"{% endif %}"
|
|
44
|
+
}'
|
|
45
|
+
# Response: SUCCESS (ID: 101)
|
|
46
|
+
|
|
47
|
+
# Add a query with JavaScript processing
|
|
48
|
+
butterfly-cli record add cms_report_queries --data '{
|
|
49
|
+
"cms_report_id": 50,
|
|
50
|
+
"name": "monthly_breakdown",
|
|
51
|
+
"system_name": "monthly_breakdown",
|
|
52
|
+
"query": "SELECT DATE_FORMAT(created_at, \"%Y-%m\") as month, SUM(total) as revenue FROM orders GROUP BY month ORDER BY month",
|
|
53
|
+
"js_code": "// Process results\ndata.forEach(row => { row.revenue_formatted = \"$\" + parseFloat(row.revenue).toFixed(2); });\nreturn data;"
|
|
54
|
+
}'
|
|
55
|
+
# Response: SUCCESS (ID: 102)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Report Query Fields
|
|
59
|
+
|
|
60
|
+
| Field | Description |
|
|
61
|
+
|-------|-------------|
|
|
62
|
+
| `cms_report_id` | Foreign key to parent report |
|
|
63
|
+
| `name` | Display name (used for folder naming) |
|
|
64
|
+
| `system_name` | System identifier |
|
|
65
|
+
| `query` | Twig/SQL query code |
|
|
66
|
+
| `js_code` | JavaScript for post-processing results |
|
|
67
|
+
|
|
68
|
+
## Step 3: Add Report Specs
|
|
69
|
+
|
|
70
|
+
Report specs define the columns/fields displayed in the report output.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Add column specs
|
|
74
|
+
butterfly-cli record add cms_report_specs --data '{
|
|
75
|
+
"cms_report_id": 50,
|
|
76
|
+
"field_name": "order_number",
|
|
77
|
+
"title": "Order #",
|
|
78
|
+
"order_no": 1
|
|
79
|
+
}'
|
|
80
|
+
|
|
81
|
+
butterfly-cli record add cms_report_specs --data '{
|
|
82
|
+
"cms_report_id": 50,
|
|
83
|
+
"field_name": "customer_name",
|
|
84
|
+
"title": "Customer",
|
|
85
|
+
"order_no": 2
|
|
86
|
+
}'
|
|
87
|
+
|
|
88
|
+
butterfly-cli record add cms_report_specs --data '{
|
|
89
|
+
"cms_report_id": 50,
|
|
90
|
+
"field_name": "total",
|
|
91
|
+
"title": "Total",
|
|
92
|
+
"order_no": 3,
|
|
93
|
+
"js_code": "return \"$\" + parseFloat(value).toFixed(2);"
|
|
94
|
+
}'
|
|
95
|
+
|
|
96
|
+
butterfly-cli record add cms_report_specs --data '{
|
|
97
|
+
"cms_report_id": 50,
|
|
98
|
+
"field_name": "created_at",
|
|
99
|
+
"title": "Date",
|
|
100
|
+
"order_no": 4
|
|
101
|
+
}'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Report Spec Fields
|
|
105
|
+
|
|
106
|
+
| Field | Description |
|
|
107
|
+
|-------|-------------|
|
|
108
|
+
| `cms_report_id` | Foreign key to parent report |
|
|
109
|
+
| `field_name` | Column name from query results |
|
|
110
|
+
| `title` | Display title for the column |
|
|
111
|
+
| `order_no` | Display order |
|
|
112
|
+
| `js_code` | JavaScript for formatting the field value |
|
|
113
|
+
|
|
114
|
+
## Complete Example: Inventory Report
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# 1. Create the report
|
|
118
|
+
butterfly-cli record add cms_reports --data '{
|
|
119
|
+
"name": "Inventory Status",
|
|
120
|
+
"alias": "inventory_status",
|
|
121
|
+
"query": "SELECT p.id, p.sku, p.title, p.stock, p.low_stock_threshold, (p.stock <= p.low_stock_threshold) as is_low_stock FROM products p WHERE p.status = \"active\" ORDER BY p.stock ASC"
|
|
122
|
+
}'
|
|
123
|
+
# Note the ID (e.g., 51)
|
|
124
|
+
|
|
125
|
+
# 2. Add a summary query
|
|
126
|
+
butterfly-cli record add cms_report_queries --data '{
|
|
127
|
+
"cms_report_id": 51,
|
|
128
|
+
"name": "summary",
|
|
129
|
+
"system_name": "summary",
|
|
130
|
+
"query": "SELECT COUNT(*) as total_products, SUM(CASE WHEN stock <= low_stock_threshold THEN 1 ELSE 0 END) as low_stock_count, SUM(stock) as total_stock FROM products WHERE status = \"active\""
|
|
131
|
+
}'
|
|
132
|
+
|
|
133
|
+
# 3. Add report specs
|
|
134
|
+
butterfly-cli record add cms_report_specs --data '{"cms_report_id":51,"field_name":"sku","title":"SKU","order_no":1}'
|
|
135
|
+
butterfly-cli record add cms_report_specs --data '{"cms_report_id":51,"field_name":"title","title":"Product","order_no":2}'
|
|
136
|
+
butterfly-cli record add cms_report_specs --data '{"cms_report_id":51,"field_name":"stock","title":"Stock","order_no":3}'
|
|
137
|
+
butterfly-cli record add cms_report_specs --data '{
|
|
138
|
+
"cms_report_id": 51,
|
|
139
|
+
"field_name": "is_low_stock",
|
|
140
|
+
"title": "Status",
|
|
141
|
+
"order_no": 4,
|
|
142
|
+
"js_code": "return value == 1 ? \"<span class=badge-danger>Low Stock</span>\" : \"<span class=badge-success>OK</span>\";"
|
|
143
|
+
}'
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Verify Reports
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Get report by alias
|
|
150
|
+
butterfly-cli record get cms_reports --column alias --value "inventory_status"
|
|
151
|
+
|
|
152
|
+
# List all queries for a report
|
|
153
|
+
butterfly-cli record get cms_report_queries --column cms_report_id --value 51
|
|
154
|
+
|
|
155
|
+
# List all specs for a report
|
|
156
|
+
butterfly-cli record get cms_report_specs --column cms_report_id --value 51
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## File Structure After Download
|
|
160
|
+
|
|
161
|
+
When you run `butterfly-cli download -t reports`, reports are saved as:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
data/reports/
|
|
165
|
+
├── categories.json
|
|
166
|
+
└── inventory_status/
|
|
167
|
+
├── report.json
|
|
168
|
+
├── main_query.bfy
|
|
169
|
+
├── queries/
|
|
170
|
+
│ └── summary/
|
|
171
|
+
│ ├── query.json
|
|
172
|
+
│ └── query_code.bfy
|
|
173
|
+
└── specs/
|
|
174
|
+
└── is_low_stock/
|
|
175
|
+
├── spec.json
|
|
176
|
+
└── code.js
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Editing Reports
|
|
180
|
+
|
|
181
|
+
After downloading, you can edit report files locally and upload changes using `butterfly-cli upload <path>`:
|
|
182
|
+
|
|
183
|
+
1. Edit `report.json` - Updates report metadata
|
|
184
|
+
2. Edit `main_query.bfy` - Updates main query
|
|
185
|
+
3. Edit `queries/*/query_code.bfy` - Updates query code
|
|
186
|
+
4. Edit `queries/*/script.js` - Updates query JS processing
|
|
187
|
+
5. Edit `specs/*/code.js` - Updates spec JS formatting
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Excel Export
|
|
2
|
+
|
|
3
|
+
Butterfly provides a built-in Excel export function for generating downloadable spreadsheets from Twig code.
|
|
4
|
+
|
|
5
|
+
## Where It Works
|
|
6
|
+
|
|
7
|
+
Excel export only works in:
|
|
8
|
+
- **Custom fields** (`template_code.bfy` / `processing_code.bfy`)
|
|
9
|
+
- **Calculated fields** (`code.bfy`)
|
|
10
|
+
- **Reports** (`query_code.bfy`)
|
|
11
|
+
- **Webservices** (`page_code.bfy`)
|
|
12
|
+
|
|
13
|
+
It does **NOT** work in state machine transition codes, even though they use Twig.
|
|
14
|
+
|
|
15
|
+
## Recommended Pattern: Query Parameter Trigger
|
|
16
|
+
|
|
17
|
+
The best approach is to add a query parameter to the current URL and check for it in the same Twig template:
|
|
18
|
+
|
|
19
|
+
```twig
|
|
20
|
+
{# Check if export is requested #}
|
|
21
|
+
{% if getParameter('download_excel') %}
|
|
22
|
+
{% set data = db().table('orders').where('status', 'completed').get() %}
|
|
23
|
+
{% do excel().sheet('Orders').autoTable(data).download('orders.xlsx') %}
|
|
24
|
+
{% endif %}
|
|
25
|
+
|
|
26
|
+
{# Display export button - preserves existing URL parameters #}
|
|
27
|
+
<a href="{{ currentUrlWith({'download_excel': 1}) }}" class="btn btn-primary">Export to Excel</a>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Preserving URL Parameters with currentUrlWith()
|
|
31
|
+
|
|
32
|
+
Use `currentUrlWith()` to merge new parameters with existing query string parameters. This ensures filters, pagination, and other URL parameters are preserved when triggering the export.
|
|
33
|
+
|
|
34
|
+
```twig
|
|
35
|
+
{{ currentUrlWith({'download_excel': 1}) }}
|
|
36
|
+
{# If current URL is ?page=2&sort=asc, result is ?page=2&sort=asc&download_excel=1 #}
|
|
37
|
+
|
|
38
|
+
{{ currentUrlWith({'page': 2, 'sort': 'desc'}) }}
|
|
39
|
+
{# New params override existing ones with the same key #}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Export (autoTable)
|
|
43
|
+
|
|
44
|
+
```twig
|
|
45
|
+
{% do excel().sheet('Sheet Name').autoTable(data).download('filename.xlsx') %}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## With Options
|
|
49
|
+
|
|
50
|
+
```twig
|
|
51
|
+
{% do excel().sheet('Report').autoTable(data, 'A1', {
|
|
52
|
+
labels: {field_name: 'Custom Label'},
|
|
53
|
+
types: {amount: 'currency', qty: 'number', date: 'date'},
|
|
54
|
+
widths: {description: 40},
|
|
55
|
+
decimals: {price: 2},
|
|
56
|
+
symbols: {amount: '€'},
|
|
57
|
+
exclude: ['id', 'password'],
|
|
58
|
+
only: ['name', 'email', 'total']
|
|
59
|
+
}).download('report.xlsx') %}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### autoTable Options
|
|
63
|
+
|
|
64
|
+
| Option | Description | Example |
|
|
65
|
+
|----------|--------------------------------------------------|----------------------------------|
|
|
66
|
+
| labels | Custom column headers | `{field_name: 'Custom Label'}` |
|
|
67
|
+
| types | Column data types | `{amount: 'currency'}` |
|
|
68
|
+
| widths | Column widths | `{description: 40}` |
|
|
69
|
+
| decimals | Decimal places for number types | `{price: 2}` |
|
|
70
|
+
| symbols | Currency symbols | `{amount: '€'}` |
|
|
71
|
+
| aligns | Column alignment (overrides type defaults) | `{status: 'center'}` |
|
|
72
|
+
| exclude | Fields to exclude from export | `['id', 'password']` |
|
|
73
|
+
| only | Only include these fields (whitelist) | `['name', 'email', 'total']` |
|
|
74
|
+
|
|
75
|
+
## Column Types
|
|
76
|
+
|
|
77
|
+
| Type | Output | Default Alignment | Options |
|
|
78
|
+
|----------|------------------|-------------------|------------------------|
|
|
79
|
+
| text | Plain text | left | - |
|
|
80
|
+
| currency | ₺ 1,234.56 | right | symbols: {field: '€'} |
|
|
81
|
+
| number | 1,234 | right | decimals: {field: 0} |
|
|
82
|
+
| decimal | 1,234.56 | right | decimals: {field: 2} |
|
|
83
|
+
| percent | 12.34% | right | - |
|
|
84
|
+
| date | 25.01.2025 | left | - |
|
|
85
|
+
| datetime | 25.01.2025 14:30 | left | - |
|
|
86
|
+
|
|
87
|
+
## Column Alignment
|
|
88
|
+
|
|
89
|
+
The `aligns` option allows you to override the default alignment for any column.
|
|
90
|
+
|
|
91
|
+
### Available Alignment Values
|
|
92
|
+
|
|
93
|
+
| Value | Description |
|
|
94
|
+
|--------|---------------------------------------------------------------|
|
|
95
|
+
| left | Align text to the left (default for text, date columns) |
|
|
96
|
+
| center | Center align text |
|
|
97
|
+
| right | Align text to the right (default for number/currency columns) |
|
|
98
|
+
|
|
99
|
+
### Example
|
|
100
|
+
|
|
101
|
+
```twig
|
|
102
|
+
{% set orders = db().table('orders').get() %}
|
|
103
|
+
|
|
104
|
+
{% do excel().sheet('Orders').autoTable(orders, 'A1', {
|
|
105
|
+
labels: {
|
|
106
|
+
id: 'Order ID',
|
|
107
|
+
status: 'Status',
|
|
108
|
+
total: 'Total'
|
|
109
|
+
},
|
|
110
|
+
types: {
|
|
111
|
+
total: 'currency'
|
|
112
|
+
},
|
|
113
|
+
aligns: {
|
|
114
|
+
id: 'center',
|
|
115
|
+
status: 'center'
|
|
116
|
+
}
|
|
117
|
+
}).download('orders.xlsx') %}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Manual Column Definitions (table)
|
|
121
|
+
|
|
122
|
+
For more control over columns, use the `table()` method:
|
|
123
|
+
|
|
124
|
+
```twig
|
|
125
|
+
{% do excel().sheet('Sales').table([
|
|
126
|
+
{key: 'product', label: 'Product', width: 30},
|
|
127
|
+
{key: 'qty', label: 'Quantity', type: 'number'},
|
|
128
|
+
{key: 'price', label: 'Price', type: 'currency', symbol: '₺'}
|
|
129
|
+
], data).download('sales.xlsx') %}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Column Definition Properties
|
|
133
|
+
|
|
134
|
+
| Property | Description |
|
|
135
|
+
|----------|--------------------------------|
|
|
136
|
+
| key | Field name in data |
|
|
137
|
+
| label | Column header text |
|
|
138
|
+
| width | Column width |
|
|
139
|
+
| type | Data type (see Column Types) |
|
|
140
|
+
| symbol | Currency symbol for currency type |
|
|
141
|
+
|
|
142
|
+
## Multi-Sheet Export
|
|
143
|
+
|
|
144
|
+
```twig
|
|
145
|
+
{% do excel()
|
|
146
|
+
.sheet('Summary').autoTable(summaryData)
|
|
147
|
+
.sheet('Details').autoTable(detailData)
|
|
148
|
+
.download('report.xlsx')
|
|
149
|
+
%}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Styling Methods
|
|
153
|
+
|
|
154
|
+
```twig
|
|
155
|
+
{% set e = excel().sheet('Report').autoTable(data) %}
|
|
156
|
+
{% do e.bold('A1:D1') %}
|
|
157
|
+
{% do e.background('A1:D1', 'FFFF00') %}
|
|
158
|
+
{% do e.border('A1:D10', 'medium') %}
|
|
159
|
+
{% do e.freeze('A2') %}
|
|
160
|
+
{% do e.download('styled.xlsx') %}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Available Methods
|
|
164
|
+
|
|
165
|
+
| Method | Description |
|
|
166
|
+
|----------------------------------------|------------------------------|
|
|
167
|
+
| `.sheet(name)` | Create/switch sheet |
|
|
168
|
+
| `.autoTable(data, startCell, options)` | Auto-generate table |
|
|
169
|
+
| `.table(columns, data, startCell)` | Manual column table |
|
|
170
|
+
| `.bold(range)` | Bold text |
|
|
171
|
+
| `.background(range, color)` | Background color (hex) |
|
|
172
|
+
| `.border(range, type)` | Borders: thin, medium, thick |
|
|
173
|
+
| `.freeze(cell)` | Freeze panes |
|
|
174
|
+
| `.merge(range)` | Merge cells |
|
|
175
|
+
| `.width(col, width)` | Set column width |
|
|
176
|
+
| `.wrapText(range)` | Enable text wrap |
|
|
177
|
+
| `.download(filename)` | Download file |
|
|
178
|
+
|
|
179
|
+
## Complete Example
|
|
180
|
+
|
|
181
|
+
```twig
|
|
182
|
+
{# In a report query or custom field template_code #}
|
|
183
|
+
|
|
184
|
+
{% if getParameter('export_orders') %}
|
|
185
|
+
{% set orders = db()
|
|
186
|
+
.table('orders')
|
|
187
|
+
.join('customers', 'customers.id', '=', 'orders.customer_id')
|
|
188
|
+
.select(['orders.*', 'customers.name as customer_name'])
|
|
189
|
+
.where('orders.status', 'completed')
|
|
190
|
+
.get()
|
|
191
|
+
%}
|
|
192
|
+
|
|
193
|
+
{% set e = excel().sheet('Orders') %}
|
|
194
|
+
{% do e.autoTable(orders, 'A1', {
|
|
195
|
+
labels: {
|
|
196
|
+
customer_name: 'Customer',
|
|
197
|
+
order_date: 'Date',
|
|
198
|
+
total_amount: 'Total'
|
|
199
|
+
},
|
|
200
|
+
types: {
|
|
201
|
+
order_date: 'date',
|
|
202
|
+
total_amount: 'currency'
|
|
203
|
+
},
|
|
204
|
+
symbols: {total_amount: '₺'},
|
|
205
|
+
exclude: ['id', 'customer_id', 'created_at', 'updated_at']
|
|
206
|
+
}) %}
|
|
207
|
+
{% do e.bold('A1:D1') %}
|
|
208
|
+
{% do e.freeze('A2') %}
|
|
209
|
+
{% do e.download('orders_export.xlsx') %}
|
|
210
|
+
{% endif %}
|
|
211
|
+
|
|
212
|
+
{# Export button - preserves existing URL parameters like filters #}
|
|
213
|
+
<a href="{{ currentUrlWith({'export_orders': 1}) }}" class="btn btn-success">
|
|
214
|
+
<i class="lucide-download"></i> Export to Excel
|
|
215
|
+
</a>
|
|
216
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Field Types
|
|
2
|
+
|
|
3
|
+
## Basic Types
|
|
4
|
+
string, textarea, integer, float, decimal, money, date, datetime, time, checkbox, yes_no, status, code, password, slug, color_picker, hidden_string, hidden_integer
|
|
5
|
+
|
|
6
|
+
## Selection Types
|
|
7
|
+
| Type | val_1 | val_2 | val_3 | val_4 | val_5 |
|
|
8
|
+
|------|-------|-------|-------|-------|-------|
|
|
9
|
+
| dropdown | table_name | title_column | value_column | where | - |
|
|
10
|
+
| autocomplete | table_name | search_column | value_column | where | additional_columns |
|
|
11
|
+
| from_list | options (pipe-separated) | edit_on_list | other_value | - | - |
|
|
12
|
+
|
|
13
|
+
## Multi-Select Types
|
|
14
|
+
multidropdown, multicheckbox, multicheckbox_from_list, tag, hierarchy, tree
|
|
15
|
+
|
|
16
|
+
## File Types
|
|
17
|
+
file_upload, file_upload_multiple, image_upload, image_upload_multiple, image_upload_extended
|
|
18
|
+
|
|
19
|
+
## Advanced Types
|
|
20
|
+
| Type | val_1 | val_2 | val_3 |
|
|
21
|
+
|------|-------|-------|-------|
|
|
22
|
+
| [calculated](./calculated.md) | twig_code | - | - |
|
|
23
|
+
| [custom](./custom.md) | template_code | processing_code | - |
|
|
24
|
+
| filter | - | - | filter_code |
|
|
25
|
+
| nested | yaml_config | multiple | sortable |
|
|
26
|
+
| nested_single | yaml_config | - | - |
|
|
27
|
+
|
|
28
|
+
## Column Sizes
|
|
29
|
+
`1` `1/2` `1/3` `1/4` `2/3` `3/4`
|