codymaster 4.5.4 → 4.8.0
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/CHANGELOG.md +46 -1
- package/README.md +86 -31
- package/dist/backends/viking-backend.js +235 -0
- package/dist/backends/viking-http-client.js +176 -0
- package/dist/browse-server.js +251 -0
- package/dist/cli/command-registry.js +26 -0
- package/dist/cli/commands/agent.js +120 -0
- package/dist/cli/commands/dashboard.js +93 -0
- package/dist/cli/commands/design-studio.js +111 -0
- package/dist/cli/commands/distro.js +25 -0
- package/dist/cli/commands/engineering.js +488 -0
- package/dist/cli/commands/project.js +324 -0
- package/dist/cli/commands/skill-chain.js +269 -0
- package/dist/cli/commands/system.js +89 -0
- package/dist/cli/commands/task.js +254 -0
- package/dist/cli/update-check.js +83 -0
- package/dist/cm-config.js +110 -0
- package/dist/cm-suggest.js +77 -0
- package/dist/continuity.js +8 -0
- package/dist/distro-validate.js +54 -0
- package/dist/guardian-core.js +74 -0
- package/dist/index.js +36 -2759
- package/dist/mcp-context-server.js +60 -1
- package/dist/mcp-skills-tools.js +81 -0
- package/dist/retro-summary.js +70 -0
- package/dist/second-opinion-providers.js +79 -0
- package/dist/sprint-pipeline.js +228 -0
- package/dist/storage-backend.js +63 -0
- package/dist/utils/cli-utils.js +76 -0
- package/dist/utils/skill-utils.js +32 -0
- package/install.sh +286 -58
- package/package.json +16 -5
- package/scripts/build-skills.mjs +51 -0
- package/scripts/gate-0-repo-hygiene.js +75 -0
- package/scripts/postinstall.js +56 -1
- package/scripts/security-scan.js +1 -1
- package/scripts/validate-skills.mjs +42 -0
- package/scripts/viking-demo.ts +105 -0
- package/skills/CLAUDE.md +2 -2
- package/skills/_shared/helpers.md +10 -0
- package/skills/cm-ads-tracker/SKILL.md +3 -6
- package/skills/cm-browse/SKILL.md +28 -0
- package/skills/cm-conductor-worktrees/SKILL.md +24 -0
- package/skills/cm-content-factory/SKILL.md +1 -1
- package/skills/cm-content-factory/landing/docs/content/changelog.md +36 -0
- package/skills/cm-content-factory/landing/docs/content/deployment.md +46 -0
- package/skills/cm-content-factory/landing/docs/content/execution-flow.md +67 -0
- package/skills/cm-content-factory/landing/docs/content/openspace.md +27 -0
- package/skills/cm-content-factory/landing/docs/content/openviking.md +33 -0
- package/skills/cm-content-factory/landing/docs/content/use-cases.md +26 -0
- package/skills/cm-content-factory/landing/docs/content/v5-intro.md +28 -0
- package/skills/cm-content-factory/landing/docs/index.html +240 -0
- package/skills/cm-content-factory/landing/index.html +99 -99
- package/skills/cm-content-factory/landing/script.js +42 -0
- package/skills/cm-content-factory/landing/translations.js +400 -400
- package/skills/cm-continuity/SKILL.md +33 -6
- package/skills/cm-design-studio/SKILL.md +30 -0
- package/skills/cm-ecosystem-roadmap/SKILL.md +11 -0
- package/skills/cm-engineering-meta/SKILL.md +69 -0
- package/skills/cm-growth-hacking/SKILL.md +1 -12
- package/skills/cm-guardian-runtime/SKILL.md +22 -0
- package/skills/cm-mcp-engineering/SKILL.md +18 -0
- package/skills/cm-notebooklm/SKILL.md +1 -17
- package/skills/cm-post-deploy-canary/SKILL.md +18 -0
- package/skills/cm-qa-visual-cli/SKILL.md +18 -0
- package/skills/cm-retro-cli/SKILL.md +19 -0
- package/skills/cm-second-opinion-cli/SKILL.md +19 -0
- package/skills/cm-secret-shield/SKILL.md +2 -2
- package/skills/cm-sprint-bus/SKILL.md +29 -0
- package/skills/cm-start/SKILL.md +11 -2
- package/skills/cm-tdd/SKILL.md +61 -74
- package/skills/profiles/README.md +21 -0
- package/skills/profiles/core.txt +23 -0
- package/skills/profiles/design.txt +6 -0
- package/skills/profiles/full.txt +58 -0
- package/skills/profiles/growth.txt +10 -0
- package/skills/profiles/knowledge.txt +7 -0
- package/scripts/test-gemini.js +0 -13
- package/skills/cm-frappe-agent/SKILL.md +0 -134
- package/skills/cm-frappe-agent/agents/doctype-architect.md +0 -596
- package/skills/cm-frappe-agent/agents/erpnext-customizer.md +0 -643
- package/skills/cm-frappe-agent/agents/frappe-backend.md +0 -814
- package/skills/cm-frappe-agent/agents/frappe-custom-frontend.md +0 -557
- package/skills/cm-frappe-agent/agents/frappe-debugger.md +0 -625
- package/skills/cm-frappe-agent/agents/frappe-fixer.md +0 -275
- package/skills/cm-frappe-agent/agents/frappe-frontend.md +0 -660
- package/skills/cm-frappe-agent/agents/frappe-installer.md +0 -158
- package/skills/cm-frappe-agent/agents/frappe-performance.md +0 -307
- package/skills/cm-frappe-agent/agents/frappe-planner.md +0 -419
- package/skills/cm-frappe-agent/agents/frappe-remote-ops.md +0 -153
- package/skills/cm-frappe-agent/agents/github-workflow.md +0 -286
- package/skills/cm-frappe-agent/commands/frappe-app.md +0 -351
- package/skills/cm-frappe-agent/commands/frappe-backend.md +0 -162
- package/skills/cm-frappe-agent/commands/frappe-bench.md +0 -254
- package/skills/cm-frappe-agent/commands/frappe-debug.md +0 -263
- package/skills/cm-frappe-agent/commands/frappe-doctype-create.md +0 -272
- package/skills/cm-frappe-agent/commands/frappe-doctype-field.md +0 -310
- package/skills/cm-frappe-agent/commands/frappe-erpnext.md +0 -210
- package/skills/cm-frappe-agent/commands/frappe-fix.md +0 -59
- package/skills/cm-frappe-agent/commands/frappe-frontend.md +0 -210
- package/skills/cm-frappe-agent/commands/frappe-fullstack.md +0 -243
- package/skills/cm-frappe-agent/commands/frappe-github.md +0 -57
- package/skills/cm-frappe-agent/commands/frappe-install.md +0 -52
- package/skills/cm-frappe-agent/commands/frappe-plan.md +0 -442
- package/skills/cm-frappe-agent/commands/frappe-remote.md +0 -58
- package/skills/cm-frappe-agent/commands/frappe-test.md +0 -356
- package/skills/cm-frappe-agent/docs/README.md +0 -51
- package/skills/cm-frappe-agent/docs/agents-catalog.md +0 -113
- package/skills/cm-frappe-agent/docs/architecture.md +0 -149
- package/skills/cm-frappe-agent/docs/commands-catalog.md +0 -82
- package/skills/cm-frappe-agent/docs/resources-catalog.md +0 -66
- package/skills/cm-frappe-agent/docs/sitemap-urls.txt +0 -52
- package/skills/cm-frappe-agent/docs/sitemap.md +0 -81
- package/skills/cm-frappe-agent/docs/sop/user-guide.md +0 -178
- package/skills/cm-frappe-agent/docs/sop/vibe-coding-guide.md +0 -122
- package/skills/cm-frappe-agent/resources/7-layer-architecture.md +0 -985
- package/skills/cm-frappe-agent/resources/bench_commands.md +0 -73
- package/skills/cm-frappe-agent/resources/code-patterns-guide.md +0 -948
- package/skills/cm-frappe-agent/resources/common_pitfalls.md +0 -266
- package/skills/cm-frappe-agent/resources/doctype-registry.md +0 -158
- package/skills/cm-frappe-agent/resources/installation-guide.md +0 -289
- package/skills/cm-frappe-agent/resources/rest-api-patterns.md +0 -182
- package/skills/cm-frappe-agent/resources/scaffold_checklist.md +0 -82
- package/skills/cm-frappe-agent/resources/upgrade_patterns.md +0 -113
- package/skills/cm-frappe-agent/resources/web-form-patterns.md +0 -252
- package/skills/cm-frappe-agent/skills/bench-commands/SKILL.md +0 -621
- package/skills/cm-frappe-agent/skills/client-scripts/SKILL.md +0 -642
- package/skills/cm-frappe-agent/skills/doctype-patterns/SKILL.md +0 -576
- package/skills/cm-frappe-agent/skills/frappe-api/SKILL.md +0 -740
- package/skills/cm-frappe-agent/skills/remote-operations/SKILL.md +0 -47
- package/skills/cm-frappe-agent/skills/server-scripts/SKILL.md +0 -608
- package/skills/cm-frappe-agent/skills/web-forms/SKILL.md +0 -46
- package/skills/frappe-app-builder.zip +0 -0
|
@@ -1,642 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: client-scripts
|
|
3
|
-
description: Frappe client-side JavaScript patterns for form events, field manipulation, dialogs, and UI customization. Use when writing form scripts, handling field changes, creating dialogs, or customizing the Frappe desk interface.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Frappe Client Scripts Reference
|
|
7
|
-
|
|
8
|
-
Complete reference for client-side JavaScript development in Frappe Framework.
|
|
9
|
-
|
|
10
|
-
## When to Use This Skill
|
|
11
|
-
|
|
12
|
-
- Writing form scripts (refresh, validate, field events)
|
|
13
|
-
- Manipulating form fields (show/hide, require, read-only)
|
|
14
|
-
- Creating dialogs and prompts
|
|
15
|
-
- Making API calls from client
|
|
16
|
-
- Customizing list views
|
|
17
|
-
- Adding custom buttons
|
|
18
|
-
- Handling child table events
|
|
19
|
-
|
|
20
|
-
## Form Script Location
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
my_app/
|
|
24
|
-
└── my_module/
|
|
25
|
-
└── doctype/
|
|
26
|
-
└── my_doctype/
|
|
27
|
-
└── my_doctype.js # Client script
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Form Events
|
|
31
|
-
|
|
32
|
-
### Complete Event Reference
|
|
33
|
-
|
|
34
|
-
```javascript
|
|
35
|
-
frappe.ui.form.on('My DocType', {
|
|
36
|
-
// === LOAD EVENTS ===
|
|
37
|
-
|
|
38
|
-
setup: function(frm) {
|
|
39
|
-
// Called once when form is created (before data loads)
|
|
40
|
-
// Use for: setting queries, initializing variables
|
|
41
|
-
frm.set_query('customer', () => ({ filters: { status: 'Active' } }));
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
onload: function(frm) {
|
|
45
|
-
// Called when form data is loaded (before refresh)
|
|
46
|
-
// Use for: setting defaults for new docs
|
|
47
|
-
if (frm.is_new()) {
|
|
48
|
-
frm.set_value('posting_date', frappe.datetime.nowdate());
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
onload_post_render: function(frm) {
|
|
53
|
-
// Called after form is rendered
|
|
54
|
-
// Use for: DOM manipulation, focus setting
|
|
55
|
-
frm.get_field('customer').focus();
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
refresh: function(frm) {
|
|
59
|
-
// Called every time form refreshes
|
|
60
|
-
// Use for: custom buttons, field toggles, indicators
|
|
61
|
-
if (!frm.is_new()) {
|
|
62
|
-
frm.add_custom_button(__('Action'), () => do_action(frm));
|
|
63
|
-
}
|
|
64
|
-
frm.toggle_display('section_name', frm.doc.show_section);
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
// === SAVE EVENTS ===
|
|
68
|
-
|
|
69
|
-
validate: function(frm) {
|
|
70
|
-
// Called before save - return false to prevent
|
|
71
|
-
if (frm.doc.end_date < frm.doc.start_date) {
|
|
72
|
-
frappe.msgprint(__('End Date cannot be before Start Date'));
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
before_save: function(frm) {
|
|
78
|
-
// Called after validate, before server request
|
|
79
|
-
frm.doc.last_updated_by = frappe.session.user;
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
after_save: function(frm) {
|
|
83
|
-
// Called after successful save
|
|
84
|
-
frappe.show_alert({
|
|
85
|
-
message: __('Saved successfully'),
|
|
86
|
-
indicator: 'green'
|
|
87
|
-
});
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
// === WORKFLOW EVENTS ===
|
|
91
|
-
|
|
92
|
-
before_submit: function(frm) {
|
|
93
|
-
// Called before document submission
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
on_submit: function(frm) {
|
|
97
|
-
// Called after successful submission
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
before_cancel: function(frm) {
|
|
101
|
-
// Called before cancellation
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
after_cancel: function(frm) {
|
|
105
|
-
// Called after cancellation
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
// === FIELD EVENTS ===
|
|
109
|
-
|
|
110
|
-
customer: function(frm) {
|
|
111
|
-
// Called when 'customer' field changes
|
|
112
|
-
if (frm.doc.customer) {
|
|
113
|
-
fetch_customer_details(frm);
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
posting_date: function(frm) {
|
|
118
|
-
// Called when 'posting_date' field changes
|
|
119
|
-
calculate_due_date(frm);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Field Manipulation
|
|
125
|
-
|
|
126
|
-
### Display Properties
|
|
127
|
-
|
|
128
|
-
```javascript
|
|
129
|
-
// Show/hide field
|
|
130
|
-
frm.toggle_display('fieldname', true); // Show
|
|
131
|
-
frm.toggle_display('fieldname', false); // Hide
|
|
132
|
-
frm.toggle_display(['field1', 'field2'], condition);
|
|
133
|
-
|
|
134
|
-
// Set read-only
|
|
135
|
-
frm.set_df_property('fieldname', 'read_only', 1);
|
|
136
|
-
frm.toggle_enable('fieldname', false); // Disable
|
|
137
|
-
|
|
138
|
-
// Set required
|
|
139
|
-
frm.set_df_property('fieldname', 'reqd', 1);
|
|
140
|
-
frm.toggle_reqd('fieldname', true);
|
|
141
|
-
frm.toggle_reqd(['field1', 'field2'], condition);
|
|
142
|
-
|
|
143
|
-
// Set hidden
|
|
144
|
-
frm.set_df_property('fieldname', 'hidden', 1);
|
|
145
|
-
|
|
146
|
-
// Change label
|
|
147
|
-
frm.set_df_property('fieldname', 'label', 'New Label');
|
|
148
|
-
|
|
149
|
-
// Change description
|
|
150
|
-
frm.set_df_property('fieldname', 'description', 'Help text');
|
|
151
|
-
|
|
152
|
-
// Change options (for Select)
|
|
153
|
-
frm.set_df_property('fieldname', 'options', 'Option1\nOption2\nOption3');
|
|
154
|
-
|
|
155
|
-
// Refresh after changes
|
|
156
|
-
frm.refresh_field('fieldname');
|
|
157
|
-
frm.refresh_fields();
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Set Values
|
|
161
|
-
|
|
162
|
-
```javascript
|
|
163
|
-
// Set single value
|
|
164
|
-
frm.set_value('fieldname', value);
|
|
165
|
-
|
|
166
|
-
// Set multiple values
|
|
167
|
-
frm.set_value({
|
|
168
|
-
'field1': 'value1',
|
|
169
|
-
'field2': 'value2',
|
|
170
|
-
'field3': 'value3'
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// Set with callback
|
|
174
|
-
frm.set_value('fieldname', value).then(() => {
|
|
175
|
-
// After value is set
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// Clear field
|
|
179
|
-
frm.set_value('fieldname', null);
|
|
180
|
-
frm.set_value('fieldname', '');
|
|
181
|
-
|
|
182
|
-
// Set default value
|
|
183
|
-
frm.set_df_property('fieldname', 'default', 'default_value');
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Link Field Queries
|
|
187
|
-
|
|
188
|
-
```javascript
|
|
189
|
-
// Basic filter
|
|
190
|
-
frm.set_query('customer', function() {
|
|
191
|
-
return {
|
|
192
|
-
filters: {
|
|
193
|
-
status: 'Active',
|
|
194
|
-
customer_type: 'Company'
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// Dynamic filter based on form values
|
|
200
|
-
frm.set_query('item_code', function() {
|
|
201
|
-
return {
|
|
202
|
-
filters: {
|
|
203
|
-
item_group: frm.doc.item_group,
|
|
204
|
-
is_stock_item: 1
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// Filter in child table
|
|
210
|
-
frm.set_query('item_code', 'items', function(doc, cdt, cdn) {
|
|
211
|
-
let row = locals[cdt][cdn];
|
|
212
|
-
return {
|
|
213
|
-
filters: {
|
|
214
|
-
warehouse: row.warehouse || doc.default_warehouse
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// Custom query (server method)
|
|
220
|
-
frm.set_query('supplier', function() {
|
|
221
|
-
return {
|
|
222
|
-
query: 'my_app.api.get_suppliers',
|
|
223
|
-
filters: {
|
|
224
|
-
region: frm.doc.region
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
// Clear query
|
|
230
|
-
frm.set_query('fieldname', null);
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
## Custom Buttons
|
|
234
|
-
|
|
235
|
-
```javascript
|
|
236
|
-
refresh: function(frm) {
|
|
237
|
-
// Simple button
|
|
238
|
-
frm.add_custom_button(__('Do Something'), function() {
|
|
239
|
-
do_something(frm);
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Button in group/dropdown
|
|
243
|
-
frm.add_custom_button(__('Action 1'), function() {
|
|
244
|
-
action_1(frm);
|
|
245
|
-
}, __('Actions'));
|
|
246
|
-
|
|
247
|
-
frm.add_custom_button(__('Action 2'), function() {
|
|
248
|
-
action_2(frm);
|
|
249
|
-
}, __('Actions'));
|
|
250
|
-
|
|
251
|
-
// Primary button (highlighted)
|
|
252
|
-
frm.add_custom_button(__('Submit'), function() {
|
|
253
|
-
submit_doc(frm);
|
|
254
|
-
}).addClass('btn-primary');
|
|
255
|
-
|
|
256
|
-
// Button with icon
|
|
257
|
-
let btn = frm.add_custom_button(__('Print'), function() {
|
|
258
|
-
print_doc(frm);
|
|
259
|
-
});
|
|
260
|
-
btn.prepend('<i class="fa fa-print"></i> ');
|
|
261
|
-
|
|
262
|
-
// Conditional buttons
|
|
263
|
-
if (frm.doc.status === 'Draft') {
|
|
264
|
-
frm.add_custom_button(__('Submit for Review'), function() {
|
|
265
|
-
submit_for_review(frm);
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Remove button
|
|
270
|
-
frm.remove_custom_button(__('Do Something'));
|
|
271
|
-
frm.remove_custom_button(__('Action 1'), __('Actions'));
|
|
272
|
-
|
|
273
|
-
// Clear all buttons
|
|
274
|
-
frm.clear_custom_buttons();
|
|
275
|
-
|
|
276
|
-
// Page actions
|
|
277
|
-
frm.page.set_primary_action(__('Save'), function() {
|
|
278
|
-
frm.save();
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
frm.page.set_secondary_action(__('Cancel'), function() {
|
|
282
|
-
frappe.set_route('List', 'My DocType');
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
## Child Table Operations
|
|
288
|
-
|
|
289
|
-
### Events
|
|
290
|
-
|
|
291
|
-
```javascript
|
|
292
|
-
frappe.ui.form.on('My DocType Item', {
|
|
293
|
-
// Row added
|
|
294
|
-
items_add: function(frm, cdt, cdn) {
|
|
295
|
-
let row = locals[cdt][cdn];
|
|
296
|
-
row.warehouse = frm.doc.default_warehouse;
|
|
297
|
-
frm.refresh_field('items');
|
|
298
|
-
},
|
|
299
|
-
|
|
300
|
-
// Before row removed (can prevent)
|
|
301
|
-
before_items_remove: function(frm, cdt, cdn) {
|
|
302
|
-
let row = locals[cdt][cdn];
|
|
303
|
-
if (row.is_mandatory) {
|
|
304
|
-
frappe.throw(__('Cannot remove mandatory item'));
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
|
|
308
|
-
// Row removed
|
|
309
|
-
items_remove: function(frm, cdt, cdn) {
|
|
310
|
-
calculate_total(frm);
|
|
311
|
-
},
|
|
312
|
-
|
|
313
|
-
// Field in row changes
|
|
314
|
-
qty: function(frm, cdt, cdn) {
|
|
315
|
-
let row = locals[cdt][cdn];
|
|
316
|
-
row.amount = flt(row.qty) * flt(row.rate);
|
|
317
|
-
frm.refresh_field('items');
|
|
318
|
-
calculate_total(frm);
|
|
319
|
-
},
|
|
320
|
-
|
|
321
|
-
rate: function(frm, cdt, cdn) {
|
|
322
|
-
let row = locals[cdt][cdn];
|
|
323
|
-
row.amount = flt(row.qty) * flt(row.rate);
|
|
324
|
-
frm.refresh_field('items');
|
|
325
|
-
calculate_total(frm);
|
|
326
|
-
},
|
|
327
|
-
|
|
328
|
-
item_code: function(frm, cdt, cdn) {
|
|
329
|
-
let row = locals[cdt][cdn];
|
|
330
|
-
if (row.item_code) {
|
|
331
|
-
frappe.call({
|
|
332
|
-
method: 'my_app.api.get_item_details',
|
|
333
|
-
args: { item_code: row.item_code },
|
|
334
|
-
callback: function(r) {
|
|
335
|
-
if (r.message) {
|
|
336
|
-
frappe.model.set_value(cdt, cdn, {
|
|
337
|
-
'rate': r.message.rate,
|
|
338
|
-
'uom': r.message.uom,
|
|
339
|
-
'description': r.message.description
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
function calculate_total(frm) {
|
|
349
|
-
let total = 0;
|
|
350
|
-
frm.doc.items.forEach(item => {
|
|
351
|
-
total += flt(item.amount);
|
|
352
|
-
});
|
|
353
|
-
frm.set_value('total', total);
|
|
354
|
-
}
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
### Manipulating Rows
|
|
358
|
-
|
|
359
|
-
```javascript
|
|
360
|
-
// Add row
|
|
361
|
-
let row = frm.add_child('items', {
|
|
362
|
-
item_code: 'ITEM-001',
|
|
363
|
-
qty: 10,
|
|
364
|
-
rate: 100
|
|
365
|
-
});
|
|
366
|
-
frm.refresh_field('items');
|
|
367
|
-
|
|
368
|
-
// Get row by index
|
|
369
|
-
let first_row = frm.doc.items[0];
|
|
370
|
-
|
|
371
|
-
// Get row by name
|
|
372
|
-
let row = locals['My DocType Item'][cdn];
|
|
373
|
-
|
|
374
|
-
// Update row
|
|
375
|
-
frappe.model.set_value(cdt, cdn, 'fieldname', value);
|
|
376
|
-
frappe.model.set_value(cdt, cdn, {
|
|
377
|
-
'field1': 'value1',
|
|
378
|
-
'field2': 'value2'
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
// Remove row
|
|
382
|
-
frm.get_field('items').grid.grid_rows[0].remove();
|
|
383
|
-
frm.refresh_field('items');
|
|
384
|
-
|
|
385
|
-
// Remove all rows
|
|
386
|
-
frm.clear_table('items');
|
|
387
|
-
frm.refresh_field('items');
|
|
388
|
-
|
|
389
|
-
// Iterate rows
|
|
390
|
-
frm.doc.items.forEach((item, idx) => {
|
|
391
|
-
console.log(idx, item.item_code);
|
|
392
|
-
});
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
## Dialogs
|
|
396
|
-
|
|
397
|
-
### Simple Prompt
|
|
398
|
-
|
|
399
|
-
```javascript
|
|
400
|
-
// Single field
|
|
401
|
-
frappe.prompt(
|
|
402
|
-
{
|
|
403
|
-
fieldname: 'reason',
|
|
404
|
-
fieldtype: 'Small Text',
|
|
405
|
-
label: 'Reason',
|
|
406
|
-
reqd: 1
|
|
407
|
-
},
|
|
408
|
-
function(values) {
|
|
409
|
-
console.log(values.reason);
|
|
410
|
-
},
|
|
411
|
-
__('Enter Reason'),
|
|
412
|
-
__('Submit')
|
|
413
|
-
);
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
### Multi-field Prompt
|
|
417
|
-
|
|
418
|
-
```javascript
|
|
419
|
-
frappe.prompt([
|
|
420
|
-
{
|
|
421
|
-
fieldname: 'customer',
|
|
422
|
-
fieldtype: 'Link',
|
|
423
|
-
options: 'Customer',
|
|
424
|
-
label: 'Customer',
|
|
425
|
-
reqd: 1
|
|
426
|
-
},
|
|
427
|
-
{
|
|
428
|
-
fieldname: 'date',
|
|
429
|
-
fieldtype: 'Date',
|
|
430
|
-
label: 'Date',
|
|
431
|
-
default: frappe.datetime.nowdate()
|
|
432
|
-
},
|
|
433
|
-
{
|
|
434
|
-
fieldname: 'priority',
|
|
435
|
-
fieldtype: 'Select',
|
|
436
|
-
label: 'Priority',
|
|
437
|
-
options: 'Low\nMedium\nHigh',
|
|
438
|
-
default: 'Medium'
|
|
439
|
-
}
|
|
440
|
-
], function(values) {
|
|
441
|
-
process_data(values);
|
|
442
|
-
}, __('Enter Details'), __('Process'));
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
### Custom Dialog
|
|
446
|
-
|
|
447
|
-
```javascript
|
|
448
|
-
let dialog = new frappe.ui.Dialog({
|
|
449
|
-
title: __('Custom Dialog'),
|
|
450
|
-
fields: [
|
|
451
|
-
{
|
|
452
|
-
fieldname: 'customer',
|
|
453
|
-
fieldtype: 'Link',
|
|
454
|
-
options: 'Customer',
|
|
455
|
-
label: __('Customer'),
|
|
456
|
-
reqd: 1,
|
|
457
|
-
get_query: function() {
|
|
458
|
-
return { filters: { status: 'Active' } };
|
|
459
|
-
},
|
|
460
|
-
change: function() {
|
|
461
|
-
// Field change handler
|
|
462
|
-
let value = dialog.get_value('customer');
|
|
463
|
-
if (value) {
|
|
464
|
-
dialog.set_value('customer_name', 'Loading...');
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
},
|
|
468
|
-
{ fieldtype: 'Column Break' },
|
|
469
|
-
{
|
|
470
|
-
fieldname: 'customer_name',
|
|
471
|
-
fieldtype: 'Data',
|
|
472
|
-
label: __('Customer Name'),
|
|
473
|
-
read_only: 1
|
|
474
|
-
},
|
|
475
|
-
{ fieldtype: 'Section Break', label: 'Items' },
|
|
476
|
-
{
|
|
477
|
-
fieldname: 'items',
|
|
478
|
-
fieldtype: 'Table',
|
|
479
|
-
label: __('Items'),
|
|
480
|
-
cannot_add_rows: false,
|
|
481
|
-
in_place_edit: true,
|
|
482
|
-
fields: [
|
|
483
|
-
{
|
|
484
|
-
fieldname: 'item',
|
|
485
|
-
fieldtype: 'Link',
|
|
486
|
-
options: 'Item',
|
|
487
|
-
in_list_view: 1,
|
|
488
|
-
label: __('Item')
|
|
489
|
-
},
|
|
490
|
-
{
|
|
491
|
-
fieldname: 'qty',
|
|
492
|
-
fieldtype: 'Float',
|
|
493
|
-
in_list_view: 1,
|
|
494
|
-
label: __('Qty')
|
|
495
|
-
}
|
|
496
|
-
]
|
|
497
|
-
}
|
|
498
|
-
],
|
|
499
|
-
size: 'large', // small, large, extra-large
|
|
500
|
-
primary_action_label: __('Submit'),
|
|
501
|
-
primary_action: function(values) {
|
|
502
|
-
console.log(values);
|
|
503
|
-
dialog.hide();
|
|
504
|
-
process_dialog(values);
|
|
505
|
-
},
|
|
506
|
-
secondary_action_label: __('Cancel')
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
dialog.show();
|
|
510
|
-
|
|
511
|
-
// Set values
|
|
512
|
-
dialog.set_value('customer', 'CUST-001');
|
|
513
|
-
dialog.set_values({
|
|
514
|
-
'customer': 'CUST-001',
|
|
515
|
-
'date': frappe.datetime.nowdate()
|
|
516
|
-
});
|
|
517
|
-
|
|
518
|
-
// Get values
|
|
519
|
-
let values = dialog.get_values();
|
|
520
|
-
let customer = dialog.get_value('customer');
|
|
521
|
-
|
|
522
|
-
// Access fields
|
|
523
|
-
let field = dialog.get_field('customer');
|
|
524
|
-
field.set_description('Select active customer');
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
### Confirmation Dialog
|
|
528
|
-
|
|
529
|
-
```javascript
|
|
530
|
-
frappe.confirm(
|
|
531
|
-
__('Are you sure you want to delete this?'),
|
|
532
|
-
function() {
|
|
533
|
-
// On Yes
|
|
534
|
-
delete_record();
|
|
535
|
-
},
|
|
536
|
-
function() {
|
|
537
|
-
// On No (optional)
|
|
538
|
-
}
|
|
539
|
-
);
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
## API Calls
|
|
543
|
-
|
|
544
|
-
### frappe.call
|
|
545
|
-
|
|
546
|
-
```javascript
|
|
547
|
-
// Basic call
|
|
548
|
-
frappe.call({
|
|
549
|
-
method: 'my_app.api.get_data',
|
|
550
|
-
args: {
|
|
551
|
-
customer: frm.doc.customer
|
|
552
|
-
},
|
|
553
|
-
callback: function(r) {
|
|
554
|
-
if (r.message) {
|
|
555
|
-
frm.set_value('data', r.message);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
// With loading indicator
|
|
561
|
-
frappe.call({
|
|
562
|
-
method: 'my_app.api.process',
|
|
563
|
-
args: { data: frm.doc },
|
|
564
|
-
freeze: true,
|
|
565
|
-
freeze_message: __('Processing...'),
|
|
566
|
-
callback: function(r) {
|
|
567
|
-
frappe.msgprint(__('Done!'));
|
|
568
|
-
},
|
|
569
|
-
error: function(r) {
|
|
570
|
-
frappe.msgprint(__('Error occurred'));
|
|
571
|
-
}
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
// Async/await
|
|
575
|
-
async function getData() {
|
|
576
|
-
const r = await frappe.call({
|
|
577
|
-
method: 'my_app.api.get_data',
|
|
578
|
-
args: { id: 123 }
|
|
579
|
-
});
|
|
580
|
-
return r.message;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// Promise chain
|
|
584
|
-
frappe.call({
|
|
585
|
-
method: 'my_app.api.get_data'
|
|
586
|
-
}).then(r => {
|
|
587
|
-
return frappe.call({
|
|
588
|
-
method: 'my_app.api.process',
|
|
589
|
-
args: { data: r.message }
|
|
590
|
-
});
|
|
591
|
-
}).then(r => {
|
|
592
|
-
console.log('Done', r.message);
|
|
593
|
-
});
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
## Messages & Alerts
|
|
597
|
-
|
|
598
|
-
```javascript
|
|
599
|
-
// Toast alert
|
|
600
|
-
frappe.show_alert({
|
|
601
|
-
message: __('Success!'),
|
|
602
|
-
indicator: 'green' // green, blue, orange, red
|
|
603
|
-
}, 5); // seconds
|
|
604
|
-
|
|
605
|
-
// Message dialog
|
|
606
|
-
frappe.msgprint({
|
|
607
|
-
title: __('Information'),
|
|
608
|
-
message: __('This is important'),
|
|
609
|
-
indicator: 'blue'
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
// Error (stops execution)
|
|
613
|
-
frappe.throw(__('Cannot proceed'));
|
|
614
|
-
|
|
615
|
-
// Confirmation required
|
|
616
|
-
frappe.validated = false; // In validate event
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
## Utilities
|
|
620
|
-
|
|
621
|
-
```javascript
|
|
622
|
-
// Date/Time
|
|
623
|
-
frappe.datetime.nowdate(); // "2024-01-15"
|
|
624
|
-
frappe.datetime.now_datetime(); // "2024-01-15 10:30:00"
|
|
625
|
-
frappe.datetime.add_days("2024-01-15", 7);
|
|
626
|
-
frappe.datetime.add_months("2024-01-15", 1);
|
|
627
|
-
|
|
628
|
-
// Formatting
|
|
629
|
-
frappe.format(1234.56, {fieldtype: 'Currency'});
|
|
630
|
-
format_currency(1234.56, 'USD');
|
|
631
|
-
flt(value); // Float
|
|
632
|
-
cint(value); // Integer
|
|
633
|
-
|
|
634
|
-
// Navigation
|
|
635
|
-
frappe.set_route('Form', 'Customer', 'CUST-001');
|
|
636
|
-
frappe.set_route('List', 'Customer');
|
|
637
|
-
frappe.new_doc('Customer');
|
|
638
|
-
|
|
639
|
-
// Translation
|
|
640
|
-
__('Translate this');
|
|
641
|
-
__('Hello {0}', [name]);
|
|
642
|
-
```
|