diff --git a/frappe/desk/treeview.py b/frappe/desk/treeview.py index dcce6f3850..b74582edc8 100644 --- a/frappe/desk/treeview.py +++ b/frappe/desk/treeview.py @@ -36,13 +36,17 @@ def get_all_nodes(doctype, label, parent, tree_method, **filters): @frappe.whitelist() -def get_children(doctype, parent="", **filters): - return _get_children(doctype, parent) +def get_children(doctype, parent="", include_disabled=False, **filters): + if isinstance(include_disabled, str): + include_disabled = frappe.sbool(include_disabled) + return _get_children(doctype, parent, include_disabled=include_disabled) -def _get_children(doctype, parent="", ignore_permissions=False): +def _get_children(doctype, parent="", ignore_permissions=False, include_disabled=False): parent_field = "parent_" + doctype.lower().replace(" ", "_") filters = [[f"ifnull(`{parent_field}`,'')", "=", parent], ["docstatus", "<", 2]] + if frappe.db.has_column(doctype, "disabled") and not include_disabled: + filters.append(["disabled", "=", False]) meta = frappe.get_meta(doctype) diff --git a/frappe/public/js/frappe/views/treeview.js b/frappe/public/js/frappe/views/treeview.js index 22810e8e35..0096a333bd 100644 --- a/frappe/public/js/frappe/views/treeview.js +++ b/frappe/public/js/frappe/views/treeview.js @@ -106,6 +106,17 @@ frappe.views.TreeView = class TreeView { $(this.page[0]).addClass("frappe-card"); } + if (frappe.meta.has_field(me.doctype, "disabled")) { + $( + "
" + ).appendTo(this.page.inner_toolbar); + this.page.inner_toolbar + .addClass("flex align-center") + .on("click", "input[type='checkbox']", function () { + me.rebuild_tree(); + }); + } + if (this.opts.show_expand_all) { this.page.add_inner_button(__("Collapse All"), function () { me.tree.load_children(me.tree.root_node, false); @@ -189,6 +200,9 @@ frappe.views.TreeView = class TreeView { if (use_value == null) { use_value = use_label; } + this.args["include_disabled"] = this.page.inner_toolbar + .find("input[type='checkbox']") + .prop("checked"); this.tree = new frappe.ui.Tree({ parent: this.body, label: use_label, diff --git a/frappe/tests/test_nestedset.py b/frappe/tests/test_nestedset.py index 340b53bf38..53304a5bb3 100644 --- a/frappe/tests/test_nestedset.py +++ b/frappe/tests/test_nestedset.py @@ -5,6 +5,7 @@ from unittest.mock import patch import frappe from frappe.core.doctype.doctype.test_doctype import new_doctype +from frappe.desk.treeview import get_children from frappe.query_builder import Field from frappe.query_builder.functions import Max from frappe.tests.utils import FrappeTestCase @@ -296,3 +297,43 @@ class TestNestedSet(FrappeTestCase): self.assertNotIn(record, str(frappe.qb.get_query(table=linked_doctype, filters=exclusive_link))) self.assertIn(record, str(frappe.qb.get_query(table=linked_doctype, filters=inclusive_link))) + + def test_disabled_records_in_treeview(self): + """ + Tests the `get_children` util for showing / skipping disabled records in treeview + """ + doctype = ( + new_doctype( + fields=[ + { + "label": "Some Field", + "fieldname": "some_fieldname", + "fieldtype": "Data", + }, + { + "label": "Disabled", + "fieldname": "disabled", + "fieldtype": "Check", + }, + ], + is_tree=True, + autoname="field:some_fieldname", + ) + .insert() + .name + ) + + for record in [ + {"some_fieldname": "Root", "disabled": 0, "is_group": 1}, + {"some_fieldname": "Sub Tree 1", "disabled": 1, "parent_" + doctype: "Root", "is_group": 0}, + ]: + d = frappe.new_doc(doctype) + d.update(record) + d.insert() + + # Check if all records are fetched when flag is set to True + self.assertEqual(len(get_children(doctype, include_disabled=True)), 2) + + # Check if disabled records are skipped is set to False + # Children of disabled records are automatically skipped in recursion + self.assertEqual(len(get_children(doctype)), 1)