From b5ebf062cb9ca52f0f6f21f7dd37cf0f8d562f4f Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 27 Jan 2022 15:21:47 +0530 Subject: [PATCH 1/4] refactor: replace Link field with Select field --- frappe/desk/doctype/form_tour/form_tour.js | 111 ++++++++++-------- frappe/desk/doctype/form_tour/form_tour.py | 65 +++------- .../form_tour_step/form_tour_step.json | 49 ++------ frappe/public/js/frappe/form/form_tour.js | 2 +- 4 files changed, 90 insertions(+), 137 deletions(-) diff --git a/frappe/desk/doctype/form_tour/form_tour.js b/frappe/desk/doctype/form_tour/form_tour.js index 6a7c736fac..2e149c2c47 100644 --- a/frappe/desk/doctype/form_tour/form_tour.js +++ b/frappe/desk/doctype/form_tour/form_tour.js @@ -53,73 +53,84 @@ frappe.ui.form.on('Form Tour', { }; }); - frm.set_query("field", "steps", function() { - return { - query: "frappe.desk.doctype.form_tour.form_tour.get_docfield_list", - filters: { - doctype: frm.doc.reference_doctype, - hidden: 0 - } - }; - }); - - frm.set_query("parent_field", "steps", function() { - return { - query: "frappe.desk.doctype.form_tour.form_tour.get_docfield_list", - filters: { - doctype: frm.doc.reference_doctype, - fieldtype: "Table", - hidden: 0, - } - }; - }); - frm.trigger('reference_doctype'); }, reference_doctype(frm) { if (!frm.doc.reference_doctype) return; - frappe.db.get_list('DocField', { - filters: { - parent: frm.doc.reference_doctype, - parenttype: 'DocType', - fieldtype: 'Table' - }, - fields: ['options'] - }).then(res => { - if (Array.isArray(res)) { - frm.child_doctypes = res.map(r => r.options); - } + frappe.model.with_doctype(frm.doc.reference_doctype, () => { + let fields = frappe.meta + .get_docfields(frm.doc.reference_doctype, null, { + hidden: 0 + }) + .map(df => ({ + label: `${df.label || 'No Label'} (${df.fieldtype})`, + value: df.fieldname + })); + + frm.fields_dict.steps.grid.update_docfield_property( + "fieldname", + "options", + [""].concat(fields) + ); + + let parent_fields = frappe.meta + .get_docfields(frm.doc.reference_doctype, null, { + fieldtype: "Table", + hidden: 0 + }) + .map(df => ({ + label: `${df.label || 'No Label'} (${df.fieldtype})`, + value: df.fieldname + })); + + frm.fields_dict.steps.grid.update_docfield_property( + "parent_fieldname", + "options", + [""].concat(parent_fields) + ); }); } }); frappe.ui.form.on('Form Tour Step', { - parent_field(frm, cdt, cdn) { + form_render(frm, cdt, cdn) { + if (locals[cdt][cdn].is_table_field) { + frm.trigger('parent_fieldname', cdt, cdn); + } + }, + parent_fieldname(frm, cdt, cdn) { const child_row = locals[cdt][cdn]; - frappe.model.set_value(cdt, cdn, 'field', ''); - const field_control = get_child_field("steps", cdn, "field"); - field_control.get_query = function() { - return { - query: "frappe.desk.doctype.form_tour.form_tour.get_docfield_list", - filters: { - doctype: child_row.child_doctype, + + const parent_fieldname_df = frappe + .get_meta(frm.doc.reference_doctype) + .fields.find(df => df.fieldname == child_row.parent_fieldname); + + frappe.model.with_doctype(parent_fieldname_df.options, () => { + let fields = frappe.meta + .get_docfields(parent_fieldname_df.options, null, { hidden: 0 - } - }; - }; + }) + .map(df => ({ + label: `${df.label || 'No Label'} (${df.fieldtype})`, + value: df.fieldname + })); + + frm.fields_dict.steps.grid.update_docfield_property( + "fieldname", + "options", + [""].concat(fields) + ); + + if (child_row.fieldname) { + frappe.model.set_value(cdt, cdn, 'fieldname', child_row.fieldname); + } + }); } }); -function get_child_field(child_table, child_name, fieldname) { - // gets the field from grid row form - const grid = cur_frm.fields_dict[child_table].grid; - const grid_row = grid.grid_rows_by_docname[child_name]; - return grid_row.grid_form.fields_dict[fieldname]; -} - async function check_if_single(doctype) { const { message } = await frappe.db.get_value('DocType', doctype, 'issingle'); return message.issingle || 0; diff --git a/frappe/desk/doctype/form_tour/form_tour.py b/frappe/desk/doctype/form_tour/form_tour.py index 82d47224dd..6248b43e62 100644 --- a/frappe/desk/doctype/form_tour/form_tour.py +++ b/frappe/desk/doctype/form_tour/form_tour.py @@ -5,58 +5,23 @@ import frappe from frappe.model.document import Document from frappe.modules.export_file import export_to_files + class FormTour(Document): - def before_insert(self): - if not self.is_standard: - return + def before_save(self): + meta = frappe.get_meta(self.reference_doctype) + for step in self.steps: + if step.is_table_field and step.parent_fieldname: + parent_field_df = meta.get_field(step.parent_fieldname) + step.child_doctype = parent_field_df.options - # while syncing, set proper docfield reference - for d in self.steps: - if not frappe.db.exists('DocField', d.field): - d.field = frappe.db.get_value('DocField', { - 'fieldname': d.fieldname, 'parent': self.reference_doctype, 'fieldtype': d.fieldtype - }, "name") - - if d.is_table_field and not frappe.db.exists('DocField', d.parent_field): - d.parent_field = frappe.db.get_value('DocField', { - 'fieldname': d.parent_fieldname, 'parent': self.reference_doctype, 'fieldtype': 'Table' - }, "name") + field_df = frappe.get_meta(step.child_doctype).get_field(step.fieldname) + step.label = field_df.label + step.fieldtype = field_df.fieldtype + else: + field_df = meta.get_field(step.fieldname) + step.label = field_df.label + step.fieldtype = field_df.fieldtype def on_update(self): if frappe.conf.developer_mode and self.is_standard: - export_to_files([['Form Tour', self.name]], self.module) - - def before_export(self, doc): - for d in doc.steps: - d.field = "" - d.parent_field = "" - -@frappe.whitelist() -@frappe.validate_and_sanitize_search_inputs -def get_docfield_list(doctype, txt, searchfield, start, page_len, filters): - or_filters = [ - ['fieldname', 'like', '%' + txt + '%'], - ['label', 'like', '%' + txt + '%'], - ['fieldtype', 'like', '%' + txt + '%'] - ] - - parent_doctype = filters.get('doctype') - fieldtype = filters.get('fieldtype') - if not fieldtype: - excluded_fieldtypes = ['Column Break'] - excluded_fieldtypes += filters.get('excluded_fieldtypes', []) - fieldtype_filter = ['not in', excluded_fieldtypes] - else: - fieldtype_filter = fieldtype - - docfields = frappe.get_all( - doctype, - fields=["name as value", "label", "fieldtype"], - filters={'parent': parent_doctype, 'fieldtype': fieldtype_filter}, - or_filters=or_filters, - limit_start=start, - limit_page_length=page_len, - order_by="idx", - as_list=1, - ) - return docfields + export_to_files([["Form Tour", self.name]], self.module) diff --git a/frappe/desk/doctype/form_tour_step/form_tour_step.json b/frappe/desk/doctype/form_tour_step/form_tour_step.json index 3b6c91a208..7eb6eab223 100644 --- a/frappe/desk/doctype/form_tour_step/form_tour_step.json +++ b/frappe/desk/doctype/form_tour_step/form_tour_step.json @@ -6,19 +6,17 @@ "field_order": [ "is_table_field", "section_break_2", - "parent_field", - "field", + "parent_fieldname", + "fieldname", "title", "description", "column_break_2", "position", "label", + "fieldtype", "has_next_condition", "next_step_condition", "section_break_13", - "fieldname", - "parent_fieldname", - "fieldtype", "child_doctype" ], "fields": [ @@ -38,23 +36,13 @@ "reqd": 1 }, { - "depends_on": "eval: (!doc.is_table_field || (doc.is_table_field && doc.parent_field))", - "fieldname": "field", - "fieldtype": "Link", - "label": "Field", - "options": "DocField", + "depends_on": "eval: (!doc.is_table_field || (doc.is_table_field && doc.parent_fieldname))", + "fieldname": "fieldname", + "fieldtype": "Select", + "label": "Fieldname", "reqd": 1 }, { - "fetch_from": "field.fieldname", - "fieldname": "fieldname", - "fieldtype": "Data", - "hidden": 1, - "label": "Fieldname", - "read_only": 1 - }, - { - "fetch_from": "field.label", "fieldname": "label", "fieldtype": "Data", "in_list_view": 1, @@ -88,10 +76,8 @@ }, { "default": "0", - "fetch_from": "field.fieldtype", "fieldname": "fieldtype", "fieldtype": "Data", - "hidden": 1, "label": "Fieldtype", "read_only": 1 }, @@ -105,14 +91,6 @@ "fieldname": "section_break_2", "fieldtype": "Section Break" }, - { - "depends_on": "is_table_field", - "fieldname": "parent_field", - "fieldtype": "Link", - "label": "Parent Field", - "mandatory_depends_on": "is_table_field", - "options": "DocField" - }, { "fieldname": "section_break_13", "fieldtype": "Section Break", @@ -120,7 +98,6 @@ "label": "Hidden Fields" }, { - "fetch_from": "parent_field.options", "fieldname": "child_doctype", "fieldtype": "Data", "hidden": 1, @@ -128,18 +105,17 @@ "read_only": 1 }, { - "fetch_from": "parent_field.fieldname", + "depends_on": "is_table_field", "fieldname": "parent_fieldname", - "fieldtype": "Data", - "hidden": 1, - "label": "Parent Fieldname", - "read_only": 1 + "fieldtype": "Select", + "label": "Parent Field", + "mandatory_depends_on": "is_table_field" } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-06-06 20:52:21.076972", + "modified": "2022-01-27 15:18:36.481801", "modified_by": "Administrator", "module": "Desk", "name": "Form Tour Step", @@ -147,5 +123,6 @@ "permissions": [], "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/frappe/public/js/frappe/form/form_tour.js b/frappe/public/js/frappe/form/form_tour.js index 7fefb59ac6..2bb888e17c 100644 --- a/frappe/public/js/frappe/form/form_tour.js +++ b/frappe/public/js/frappe/form/form_tour.js @@ -151,7 +151,7 @@ frappe.ui.form.FormTour = class FormTour { const curr_step = step_info; const next_step = this.tour.steps[curr_step.idx]; - const is_next_field_in_curr_table = next_step.parent_field == curr_step.field; + const is_next_field_in_curr_table = next_step.parent_fieldname == curr_step.fieldname; if (!is_next_field_in_curr_table) return; From a5613720ed991d6bbab391592095e4742dcea422 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 28 Jan 2022 17:32:50 +0530 Subject: [PATCH 2/4] refactor: use set_fields_as_options --- frappe/desk/doctype/form_tour/form_tour.js | 53 ++++++++-------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/frappe/desk/doctype/form_tour/form_tour.js b/frappe/desk/doctype/form_tour/form_tour.js index 2e149c2c47..19fe623f60 100644 --- a/frappe/desk/doctype/form_tour/form_tour.js +++ b/frappe/desk/doctype/form_tour/form_tour.js @@ -59,36 +59,27 @@ frappe.ui.form.on('Form Tour', { reference_doctype(frm) { if (!frm.doc.reference_doctype) return; - frappe.model.with_doctype(frm.doc.reference_doctype, () => { - let fields = frappe.meta - .get_docfields(frm.doc.reference_doctype, null, { - hidden: 0 - }) - .map(df => ({ - label: `${df.label || 'No Label'} (${df.fieldtype})`, - value: df.fieldname - })); - + frm.set_fields_as_options( + "fieldname", + frm.doc.reference_doctype, + df => !df.hidden + ).then(options => { frm.fields_dict.steps.grid.update_docfield_property( "fieldname", "options", - [""].concat(fields) + [""].concat(options) ); + }); - let parent_fields = frappe.meta - .get_docfields(frm.doc.reference_doctype, null, { - fieldtype: "Table", - hidden: 0 - }) - .map(df => ({ - label: `${df.label || 'No Label'} (${df.fieldtype})`, - value: df.fieldname - })); - + frm.set_fields_as_options( + 'parent_fieldname', + frm.doc.reference_doctype, + (df) => df.fieldtype == "Table" && !df.hidden, + ).then(options => { frm.fields_dict.steps.grid.update_docfield_property( "parent_fieldname", "options", - [""].concat(parent_fields) + [""].concat(options) ); }); @@ -108,22 +99,16 @@ frappe.ui.form.on('Form Tour Step', { .get_meta(frm.doc.reference_doctype) .fields.find(df => df.fieldname == child_row.parent_fieldname); - frappe.model.with_doctype(parent_fieldname_df.options, () => { - let fields = frappe.meta - .get_docfields(parent_fieldname_df.options, null, { - hidden: 0 - }) - .map(df => ({ - label: `${df.label || 'No Label'} (${df.fieldtype})`, - value: df.fieldname - })); - + frm.set_fields_as_options( + 'fieldname', + parent_fieldname_df.options, + (df) => !df.hidden, + ).then(options => { frm.fields_dict.steps.grid.update_docfield_property( "fieldname", "options", - [""].concat(fields) + [""].concat(options) ); - if (child_row.fieldname) { frappe.model.set_value(cdt, cdn, 'fieldname', child_row.fieldname); } From 105f8d8bc7868ae59922a895ad071d0927fadc9c Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Mon, 31 Jan 2022 11:24:08 +0530 Subject: [PATCH 3/4] fix: form tour ui test --- frappe/tests/ui_test_helpers.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py index b299df522c..67c58a1154 100644 --- a/frappe/tests/ui_test_helpers.py +++ b/frappe/tests/ui_test_helpers.py @@ -148,9 +148,6 @@ def create_form_tour(): if frappe.db.exists('Form Tour', {'name': 'Test Form Tour'}): return - def get_docfield_name(filters): - return frappe.db.get_value('DocField', filters, "name") - tour = frappe.get_doc({ 'doctype': 'Form Tour', 'title': 'Test Form Tour', @@ -161,7 +158,6 @@ def create_form_tour(): "description": "Test Description 1", "has_next_condition": 1, "next_step_condition": "eval: doc.first_name", - "field": get_docfield_name({'parent': 'Contact', 'fieldname': 'first_name'}), "fieldname": "first_name", "fieldtype": "Data" },{ @@ -169,21 +165,18 @@ def create_form_tour(): "description": "Test Description 2", "has_next_condition": 1, "next_step_condition": "eval: doc.last_name", - "field": get_docfield_name({'parent': 'Contact', 'fieldname': 'last_name'}), "fieldname": "last_name", "fieldtype": "Data" },{ "title": "Test Title 3", "description": "Test Description 3", - "field": get_docfield_name({'parent': 'Contact', 'fieldname': 'phone_nos'}), "fieldname": "phone_nos", "fieldtype": "Table" },{ "title": "Test Title 4", "description": "Test Description 4", "is_table_field": 1, - "parent_field": get_docfield_name({'parent': 'Contact', 'fieldname': 'phone_nos'}), - "field": get_docfield_name({'parent': 'Contact Phone', 'fieldname': 'phone'}), + "parent_fieldname": "phone_nos", "next_step_condition": "eval: doc.phone", "has_next_condition": 1, "fieldname": "phone", From 05bb38ea46fce3f0bed2a317cf630b6fd5e77b0d Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Wed, 9 Feb 2022 12:32:26 +0530 Subject: [PATCH 4/4] chore: fetch name only if first_document is checked --- frappe/desk/doctype/form_tour/form_tour.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/desk/doctype/form_tour/form_tour.js b/frappe/desk/doctype/form_tour/form_tour.js index 19fe623f60..d6390d7613 100644 --- a/frappe/desk/doctype/form_tour/form_tour.js +++ b/frappe/desk/doctype/form_tour/form_tour.js @@ -15,12 +15,12 @@ frappe.ui.form.on('Form Tour', { frm.add_custom_button(__('Show Tour'), async () => { const issingle = await check_if_single(frm.doc.reference_doctype); - const name = await get_first_document(frm.doc.reference_doctype); let route_changed = null; - + if (issingle) { route_changed = frappe.set_route('Form', frm.doc.reference_doctype); } else if (frm.doc.first_document) { + const name = await get_first_document(frm.doc.reference_doctype); route_changed = frappe.set_route('Form', frm.doc.reference_doctype, name); } else { route_changed = frappe.set_route('Form', frm.doc.reference_doctype, 'new');