diff --git a/frappe/core/doctype/doctype/doctype.js b/frappe/core/doctype/doctype/doctype.js index b4d3fb9a89..3f1b5bb7ad 100644 --- a/frappe/core/doctype/doctype/doctype.js +++ b/frappe/core/doctype/doctype/doctype.js @@ -66,4 +66,92 @@ frappe.ui.form.on('DocType', { autoname: function(frm) { frm.set_df_property('fields', 'reqd', frm.doc.autoname !== 'Prompt'); } -}) +}); + +frappe.ui.form.on("DocField", { + form_render(frm, doctype, docname) { + // Render two select fields for Fetch From instead of Small Text for better UX + let field = frm.cur_grid.grid_form.fields_dict.fetch_from; + $(field.input_area).hide(); + + let $doctype_select = $(``); + let $wrapper = $('
'); + $wrapper.append($doctype_select, $field_select); + field.$input_wrapper.append($wrapper); + $doctype_select.wrap('
'); + $field_select.wrap('
'); + + let row = frappe.get_doc(doctype, docname); + let curr_value = { doctype: null, fieldname: null }; + if (row.fetch_from) { + let [doctype, fieldname] = row.fetch_from.split("."); + curr_value.doctype = doctype; + curr_value.fieldname = fieldname; + } + let curr_df_link_doctype = row.fieldtype == "Link" ? row.options : null; + + let doctypes = frm.doc.fields + .filter(df => df.fieldtype == "Link") + .filter(df => df.options && df.options != curr_df_link_doctype) + .map(df => ({ + label: `${df.options} (${df.fieldname})`, + value: df.fieldname + })); + $doctype_select.add_options([ + { label: __("Select DocType"), value: "", selected: true }, + ...doctypes + ]); + + $doctype_select.on("change", () => { + row.fetch_from = ""; + frm.dirty(); + update_fieldname_options(); + }); + + function update_fieldname_options() { + $field_select.find("option").remove(); + + let link_fieldname = $doctype_select.val(); + if (!link_fieldname) return; + let link_field = frm.doc.fields.find( + df => df.fieldname === link_fieldname + ); + let link_doctype = link_field.options; + frappe.model.with_doctype(link_doctype, () => { + let fields = frappe.meta + .get_docfields(link_doctype, null, { + fieldtype: ["not in", frappe.model.no_value_type] + }) + .map(df => ({ + label: `${df.label} (${df.fieldtype})`, + value: df.fieldname + })); + $field_select.add_options([ + { + label: __("Select Field"), + value: "", + selected: true, + disabled: true + }, + ...fields + ]); + + if (curr_value.fieldname) { + $field_select.val(curr_value.fieldname); + } + }); + } + + $field_select.on("change", () => { + let fetch_from = `${$doctype_select.val()}.${$field_select.val()}`; + row.fetch_from = fetch_from; + frm.dirty(); + }); + + if (curr_value.doctype) { + $doctype_select.val(curr_value.doctype); + update_fieldname_options(); + } + } +}); diff --git a/frappe/public/js/frappe/form/controls/select.js b/frappe/public/js/frappe/form/controls/select.js index 042d86814d..7df2bbfbaa 100644 --- a/frappe/public/js/frappe/form/controls/select.js +++ b/frappe/public/js/frappe/form/controls/select.js @@ -113,6 +113,7 @@ frappe.ui.form.ControlSelect = class ControlSelect extends frappe.ui.form.Contro var is_value_null = is_null(v.value); var is_label_null = is_null(v.label); var is_disabled = Boolean(v.disabled); + var is_selected = Boolean(v.selected); if (is_value_null && is_label_null) { value = v; @@ -126,6 +127,7 @@ frappe.ui.form.ControlSelect = class ControlSelect extends frappe.ui.form.Contro $('