diff --git a/README.md b/README.md index e7e27a0da0..53980bbef9 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ It takes care of installation, setup, upgrades, monitoring, maintenance and supp ### Docker Prerequisites: docker, docker-compose, git. Refer [Docker Documentation](https://docs.docker.com) for more details on Docker setup. -Run following commands: +Run the following commands: ``` git clone https://github.com/frappe/frappe_docker diff --git a/cypress/integration/form.js b/cypress/integration/form.js index 6319e8ae80..d83c304c71 100644 --- a/cypress/integration/form.js +++ b/cypress/integration/form.js @@ -6,7 +6,8 @@ const jump_to_field = (field_label) => { .wait(500) .type("{enter}") .wait(200) - .type("{enter}") + .findByRole("button", { name: "Go" }) + .click() .wait(1000); }; @@ -99,9 +100,7 @@ context("Form", () => { cy.new_form("User"); jump_to_field("Location"); // this is in collapsed section - cy.wait(500); type_value("Bermuda"); - cy.wait(500); cy.get_field("location").should("have.value", "Bermuda"); }); diff --git a/cypress/integration/list_view_settings.js b/cypress/integration/list_view_settings.js index 57c7f3023d..97b6cac8e3 100644 --- a/cypress/integration/list_view_settings.js +++ b/cypress/integration/list_view_settings.js @@ -2,18 +2,24 @@ context("List View Settings", () => { beforeEach(() => { cy.login(); cy.visit("/desk/website"); + cy.visit("/desk/List/DocType/List"); + cy.wait(300); + cy.clear_filters(); + cy.wait(300); + cy.get(".menu-btn-group button").click({ force: true }); + cy.get(".dropdown-menu li").filter(":visible").contains("List Settings").click(); + cy.get(".modal-dialog").should("contain", "DocType List View Settings"); + cy.findByLabelText("Disable Count").uncheck({ force: true }); + cy.findByLabelText("Disable Comment Count").uncheck({ force: true }); + cy.findByLabelText("Disable Sidebar Stats").uncheck({ force: true }); + cy.findByRole("button", { name: "Save" }).click(); + cy.reload({ force: true }); }); it("Default settings", () => { - cy.visit("/desk/List/DocType/List"); - cy.clear_filters(); cy.get(".list-count").should("contain", "20 of"); cy.get(".list-stats").should("contain", "Tags"); }); it("disable count and sidebar stats then verify", () => { - cy.wait(300); - cy.visit("/desk/List/DocType/List"); - cy.clear_filters(); - cy.wait(300); cy.get(".list-count").should("contain", "20 of"); cy.get(".frappe-list svg.es-icon.es-line").should("be.visible"); cy.get(".menu-btn-group button").click(); @@ -29,7 +35,7 @@ context("List View Settings", () => { cy.get(".list-count").should("be.empty"); cy.get(".list-sidebar .list-tags").should("not.exist"); - cy.get("[href='#es-line-chat-alt']").should("not.be.visible"); + cy.get("[href='#es-line-chat-alt']").should("not.exist"); cy.get(".menu-btn-group button").click({ force: true }); cy.get(".dropdown-menu li").filter(":visible").contains("List Settings").click(); diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index dc242bcff6..02f790fa9c 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -505,7 +505,10 @@ def get_permission_query_conditions_for_communication(user): return None else: accounts = frappe.get_all( - "User Email", filters={"parent": user}, fields=["email_account"], distinct=True, order_by="idx" + "User Email", + filters={"parent": user}, + fields=["email_account"], + distinct=True, ) if not accounts: diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json index 92df52d0aa..4e8cb320c4 100644 --- a/frappe/core/doctype/docfield/docfield.json +++ b/frappe/core/doctype/docfield/docfield.json @@ -32,6 +32,7 @@ "fetch_from", "fetch_if_empty", "visibility_section", + "button_color", "hidden", "show_on_timeline", "bold", @@ -617,6 +618,13 @@ "fieldname": "mask", "fieldtype": "Check", "label": "Mask" + }, + { + "depends_on": "eval:doc.fieldtype===\"Button\"", + "fieldname": "button_color", + "fieldtype": "Select", + "label": "Button Color", + "options": "\nDefault\nPrimary\nInfo\nSuccess\nWarning\nDanger" } ], "grid_page_length": 50, diff --git a/frappe/core/doctype/docfield/docfield.py b/frappe/core/doctype/docfield/docfield.py index 3f6d642e55..6f90b81ce9 100644 --- a/frappe/core/doctype/docfield/docfield.py +++ b/frappe/core/doctype/docfield/docfield.py @@ -18,6 +18,7 @@ class DocField(Document): allow_in_quick_entry: DF.Check allow_on_submit: DF.Check bold: DF.Check + button_color: DF.Literal["", "Default", "Primary", "Info", "Success", "Warning", "Danger"] collapsible: DF.Check collapsible_depends_on: DF.Code | None columns: DF.Int diff --git a/frappe/core/doctype/domain_settings/domain_settings.py b/frappe/core/doctype/domain_settings/domain_settings.py index e2464854e4..175ccc5a5c 100644 --- a/frappe/core/doctype/domain_settings/domain_settings.py +++ b/frappe/core/doctype/domain_settings/domain_settings.py @@ -78,7 +78,10 @@ def get_active_domains(): def _get_active_domains(): domains = frappe.get_all( - "Has Domain", filters={"parent": "Domain Settings"}, fields=["domain"], distinct=True + "Has Domain", + filters={"parent": "Domain Settings"}, + fields=["domain"], + distinct=True, ) active_domains = [row.get("domain") for row in domains] diff --git a/frappe/core/doctype/server_script/test_server_script.py b/frappe/core/doctype/server_script/test_server_script.py index 72bd7e6988..7360ca94d2 100644 --- a/frappe/core/doctype/server_script/test_server_script.py +++ b/frappe/core/doctype/server_script/test_server_script.py @@ -158,10 +158,7 @@ class TestServerScript(IntegrationTestCase): def test_permission_query(self): sql = frappe.db.get_list("ToDo", run=False) - if frappe.conf.db_type != "postgres": - self.assertTrue("where (1 = 1)" in sql.lower()) - else: - self.assertTrue("where (1 = '1')" in sql.lower()) + self.assertTrue("where (1 = 1)" in sql.lower()) self.assertTrue(isinstance(frappe.db.get_list("ToDo"), list)) def test_attribute_error(self): diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 210737e4d5..bacce751ac 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -1018,7 +1018,10 @@ def ask_pass_update(): from frappe.utils import set_default password_list = frappe.get_all( - "User Email", filters={"awaiting_password": 1, "used_oauth": 0}, pluck="parent", distinct=True + "User Email", + filters={"awaiting_password": 1, "used_oauth": 0}, + pluck="parent", + distinct=True, ) set_default("email_user_password", ",".join(password_list)) diff --git a/frappe/custom/doctype/custom_field/custom_field.json b/frappe/custom/doctype/custom_field/custom_field.json index 0a97a65c4b..cd0cc57f56 100644 --- a/frappe/custom/doctype/custom_field/custom_field.json +++ b/frappe/custom/doctype/custom_field/custom_field.json @@ -19,6 +19,7 @@ "link_filters", "column_break_6", "fieldtype", + "button_color", "precision", "hide_seconds", "hide_days", @@ -467,6 +468,13 @@ "fieldname": "placeholder", "fieldtype": "Data", "label": "Placeholder" + }, + { + "depends_on": "eval:doc.fieldtype===\"Button\"", + "fieldname": "button_color", + "fieldtype": "Select", + "label": "Button Color", + "options": "\nDefault\nPrimary\nInfo\nSuccess\nWarning\nDanger" } ], "grid_page_length": 50, @@ -474,7 +482,7 @@ "idx": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2025-10-10 11:10:23.862393", + "modified": "2025-11-12 01:14:24.753774", "modified_by": "Administrator", "module": "Custom", "name": "Custom Field", diff --git a/frappe/custom/doctype/custom_field/custom_field.py b/frappe/custom/doctype/custom_field/custom_field.py index f75dfbd58f..e90a6caf53 100644 --- a/frappe/custom/doctype/custom_field/custom_field.py +++ b/frappe/custom/doctype/custom_field/custom_field.py @@ -25,6 +25,7 @@ class CustomField(Document): allow_in_quick_entry: DF.Check allow_on_submit: DF.Check bold: DF.Check + button_color: DF.Literal["", "Default", "Primary", "Info", "Success", "Warning", "Danger"] collapsible: DF.Check collapsible_depends_on: DF.Code | None columns: DF.Int diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index 1fa7a1c4aa..295182f6f2 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -806,6 +806,7 @@ docfield_properties = { "is_virtual": "Check", "link_filters": "JSON", "placeholder": "Data", + "button_color": "Select", } doctype_link_properties = { diff --git a/frappe/custom/doctype/customize_form_field/customize_form_field.json b/frappe/custom/doctype/customize_form_field/customize_form_field.json index 69b22eaf60..499e9f4b18 100644 --- a/frappe/custom/doctype/customize_form_field/customize_form_field.json +++ b/frappe/custom/doctype/customize_form_field/customize_form_field.json @@ -54,6 +54,7 @@ "column_break_33", "read_only_depends_on", "display", + "button_color", "in_filter", "hide_seconds", "hide_days", @@ -485,6 +486,13 @@ "fieldname": "placeholder", "fieldtype": "Data", "label": "Placeholder" + }, + { + "depends_on": "eval:doc.fieldtype===\"Button\"", + "fieldname": "button_color", + "fieldtype": "Select", + "label": "Button Color", + "options": "\nDefault\nPrimary\nInfo\nSuccess\nWarning\nDanger" } ], "grid_page_length": 50, @@ -492,7 +500,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2025-10-14 13:56:58.033573", + "modified": "2025-11-12 01:13:53.053888", "modified_by": "Administrator", "module": "Custom", "name": "Customize Form Field", diff --git a/frappe/custom/doctype/customize_form_field/customize_form_field.py b/frappe/custom/doctype/customize_form_field/customize_form_field.py index 34328ae585..6d30862c4b 100644 --- a/frappe/custom/doctype/customize_form_field/customize_form_field.py +++ b/frappe/custom/doctype/customize_form_field/customize_form_field.py @@ -17,6 +17,7 @@ class CustomizeFormField(Document): allow_in_quick_entry: DF.Check allow_on_submit: DF.Check bold: DF.Check + button_color: DF.Literal["", "Default", "Primary", "Info", "Success", "Warning", "Danger"] collapsible: DF.Check collapsible_depends_on: DF.Code | None columns: DF.Int diff --git a/frappe/database/operator_map.py b/frappe/database/operator_map.py index ffdee044b6..529d91bbac 100644 --- a/frappe/database/operator_map.py +++ b/frappe/database/operator_map.py @@ -24,6 +24,17 @@ def like(key: Field, value: str) -> frappe.qb: return key.like(value) +def ilike(key: Field, value: str) -> frappe.qb: + """Wrapper method for `ILIKE` + Args: + key (str): field + value (str): criterion + Return: + frappe.qb: `frappe.qb` object with `ILIKE` + """ + return key.ilike(value) + + def func_in(key: Field, value: list | tuple) -> frappe.qb: """Wrapper method for `IN`. @@ -136,6 +147,7 @@ OPERATOR_MAP: dict[str, Callable] = { "in": func_in, "not in": func_not_in, "like": like, + "ilike": ilike, "not like": not_like, "regex": func_regex, "between": func_between, diff --git a/frappe/database/query.py b/frappe/database/query.py index 4657754522..9b71d307a3 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -1,5 +1,6 @@ import datetime import re +import warnings from functools import lru_cache from typing import TYPE_CHECKING, Any @@ -227,6 +228,7 @@ class Engine: if self.apply_permissions: self.check_read_permission() + is_select = False if update: self.query = qb.update(self.table, immutable=False) elif into: @@ -236,6 +238,7 @@ class Engine: else: self.query = qb.from_(self.table, immutable=False) self.apply_fields(fields) + is_select = True self.apply_filters(filters) self.apply_or_filters(or_filters) @@ -260,7 +263,19 @@ class Engine: self.apply_group_by(group_by) if order_by: - self.apply_order_by(order_by) + if not ( + self.is_postgres and is_select and (distinct or group_by) + ): # ignore in Postgres since order by fields need to appear in select distinct + self.apply_order_by(order_by) + else: + warnings.warn( + ( + "ORDER BY fields have been ignored because PostgreSQL requires them to " + "appear in the SELECT list when using DISTINCT or GROUP BY." + ), + UserWarning, + stacklevel=2, + ) if self.apply_permissions: self.add_permission_conditions() @@ -512,7 +527,12 @@ class Engine: ) return operator_fn(_field, nodes or ("",)) - operator_fn = OPERATOR_MAP[_operator.casefold()] + if ( + self.is_postgres and _operator.casefold() == "like" + ): # use `ILIKE` to support case insensitive search in postgres + operator_fn = OPERATOR_MAP["ilike"] + else: + operator_fn = OPERATOR_MAP[_operator.casefold()] if _value is None and isinstance(_field, Field): if operator_fn == builtin_operator.ne: filter_field_name = ( @@ -1425,7 +1445,7 @@ class Engine: if fieldtype == "Time": return "'00:00:00'" - if fieldtype in ("Float", "Int", "Currency", "Percent"): + if fieldtype in ("Float", "Int", "Currency", "Percent", "Check"): return "0" try: diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index fe2113302e..0716e49961 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -305,7 +305,12 @@ def get_references_across_doctypes_by_dynamic_link_field( for doctype, fieldname, doctype_fieldname in links: try: filters = [[doctype_fieldname, "in", to_doctypes]] if to_doctypes else [] - for linked_to in frappe.get_all(doctype, pluck=doctype_fieldname, filters=filters, distinct=1): + for linked_to in frappe.get_all( + doctype, + pluck=doctype_fieldname, + filters=filters, + distinct=1, + ): if linked_to: links_by_doctype[linked_to].append( {"doctype": doctype, "fieldname": fieldname, "doctype_fieldname": doctype_fieldname} diff --git a/frappe/desk/page/desktop/desktop.js b/frappe/desk/page/desktop/desktop.js index 880e1fafb8..20f2ffd135 100644 --- a/frappe/desk/page/desktop/desktop.js +++ b/frappe/desk/page/desktop/desktop.js @@ -285,7 +285,12 @@ class DesktopIconGrid { prepare() { this.total_pages = 1; - this.icons_data = this.icons_data.sort((a, b) => a.name.localeCompare(b.name)); + this.icons_data = this.icons_data.sort((a, b) => { + if (a.idx === b.idx) { + return a.label.localeCompare(b.label); // sort by label if idx is the same + } + return a.idx - b.idx; // sort by idx + }); this.icons_data_by_page = this.icons_data || this.split_data(this.icons_data, this.page_size.total()); } @@ -465,7 +470,7 @@ class DesktopIconGrid { if (evt.to.parentElement == evt.from.parentElement) { let reordered_icons = me.sortable.toArray(); let filters = { - parent_icon: me.parent_icon?.icon_data.label || null, + parent_icon: me.parent_icon?.icon_data.label || "" || null, }; me.reorder_icons(reordered_icons, filters); me.parent_icon?.render_folder_thumbnail(); @@ -495,11 +500,12 @@ class DesktopIconGrid { } reorder_icons(reordered_icons, filters) { reordered_icons.forEach((d, idx) => { - let icon = get_desktop_icon_by_label(d, filters); + let icon = get_desktop_icon_by_label(d); if (icon) { icon.idx = idx; } }); + frappe.boot.desktop_icons.sort((a, b) => a.idx - b.idx); } add_to_main_screen(title) { let icon = get_desktop_icon_by_label(title); @@ -509,6 +515,7 @@ class DesktopIconGrid { class DesktopIcon { constructor(icon, in_folder) { this.icon_data = icon; + this.icon_data.label = __(this.icon_data.label); this.icon_title = this.icon_data.label; this.icon_subtitle = ""; this.icon_type = this.icon_data.icon_type; diff --git a/frappe/desk/search.py b/frappe/desk/search.py index dc23bf5778..4c9a92e698 100644 --- a/frappe/desk/search.py +++ b/frappe/desk/search.py @@ -195,15 +195,9 @@ def search_widget( _relevance_expr = {"DIV": [1, {"NULLIF": [{"LOCATE": [_txt, "name"]}, 0]}]} # For MariaDB, wrap in IFNULL for sorting to push nulls to end - if frappe.db.db_type in ("mariadb", "sqlite"): - _relevance = {"IFNULL": [_relevance_expr, -9999], "as": "_relevance"} - formatted_fields.append(_relevance) - order_by = f"_relevance desc, {order_by}" - elif frappe.db.db_type == "postgres": - _relevance = {**_relevance_expr, "as": "_relevance"} - formatted_fields.append(_relevance) - # Since we are sorting by alias postgres needs to know number of column we are sorting - order_by = f"{len(formatted_fields)} desc nulls last, {order_by}" + _relevance = {"IFNULL": [_relevance_expr, -9999], "as": "_relevance"} + formatted_fields.append(_relevance) + order_by = f"_relevance desc, {order_by}" values = frappe.get_list( doctype, diff --git a/frappe/desk/treeview.py b/frappe/desk/treeview.py index 238557a4c9..50fe5b4174 100644 --- a/frappe/desk/treeview.py +++ b/frappe/desk/treeview.py @@ -57,8 +57,8 @@ def _get_children(doctype, parent="", ignore_permissions=False, include_disabled ) if frappe.db.has_column(doctype, "disabled") and not include_disabled: - qb = qb.where(Field("disabled").eq(False)) - + # used 0 instead of `false` since type of check in postgres is smallint + qb = qb.where(Field("disabled").eq(0)) # Order by name and execute return qb.orderby("name").run(as_dict=True) diff --git a/frappe/email/smtp.py b/frappe/email/smtp.py index 2f87fc166c..e19afb56bf 100644 --- a/frappe/email/smtp.py +++ b/frappe/email/smtp.py @@ -95,7 +95,7 @@ class SMTPServer: return self._session except smtplib.SMTPAuthenticationError: - self.throw_invalid_credentials_exception() + self.throw_invalid_credentials_exception(email_account=self.email_account) except OSError as e: # Invalid mail server -- due to refusing connection @@ -128,10 +128,17 @@ class SMTPServer: self._session.quit() @classmethod - def throw_invalid_credentials_exception(cls): + def throw_invalid_credentials_exception(cls, email_account=None): original_exception = get_traceback() or "\n" + error_message = ( + _("Please check your email login credentials.") + " " + original_exception.splitlines()[-1] + ) + error_title = _("Invalid Credentials") + if email_account: + error_title = _("Invalid Credentials for Email Account: {0}").format(email_account) + frappe.throw( - _("Please check your email login credentials.") + " " + original_exception.splitlines()[-1], - title=_("Invalid Credentials"), + error_message, + title=error_title, exc=InvalidEmailCredentials, ) diff --git a/frappe/email/test_smtp.py b/frappe/email/test_smtp.py index 01c55372e1..d0b9507e01 100644 --- a/frappe/email/test_smtp.py +++ b/frappe/email/test_smtp.py @@ -18,7 +18,8 @@ class TestSMTP(IntegrationTestCase): def test_get_email_account(self): existing_email_accounts = frappe.get_all( - "Email Account", fields=["name", "enable_outgoing", "default_outgoing", "append_to", "use_imap"] + "Email Account", + fields=["name", "enable_outgoing", "default_outgoing", "append_to", "use_imap"], ) unset_details = {"enable_outgoing": 0, "default_outgoing": 0, "append_to": None, "use_imap": 0} for email_account in existing_email_accounts: diff --git a/frappe/hooks.py b/frappe/hooks.py index d7495427e7..b1c7017864 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -64,7 +64,7 @@ website_route_rules = [ ] website_redirects = [ - {"source": r"/app/(.*)", "target": r"/desk/\1"}, + {"source": r"/app/(.*)", "target": r"/desk/\1", "forward_query_parameters": True}, {"source": "/apps", "target": "/desk"}, {"source": "/app", "target": "/desk"}, ] diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index d132672124..1cafc08944 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -691,6 +691,14 @@ class BaseDocument: None, ) + def _handle_hash_conflict(self): + """Regenerate hash name in case of collisions""" + self.flags.retry_count = (self.flags.retry_count or 0) + 1 + if self.flags.retry_count >= 5: + raise + self.name = None + return self.db_insert() + def db_insert(self, ignore_if_duplicate=False): """INSERT the document (with valid columns) in the database. @@ -704,10 +712,17 @@ class BaseDocument: set_new_name(self) conflict_handler = "" + returning = "" # On postgres we can't implcitly ignore PK collision # So instruct pg to ignore `name` field conflicts - if ignore_if_duplicate and frappe.db.db_type == "postgres": + if ( + (ignore_if_duplicate or self.meta.autoname == "hash") + and frappe.db.db_type == "postgres" + and (self.flags.retry_count or 0) < 5 + ): conflict_handler = "on conflict (name) do nothing" + if self.meta.autoname == "hash": + returning = "RETURNING name" if not self.creation: self.creation = self.modified = now() @@ -722,26 +737,26 @@ class BaseDocument: columns = list(d) try: - frappe.db.sql( + name = frappe.db.sql( """INSERT INTO `tab{doctype}` ({columns}) - VALUES ({values}) {conflict_handler}""".format( + VALUES ({values}) {conflict_handler} {returning}""".format( doctype=self.doctype, columns=", ".join("`" + c + "`" for c in columns), values=", ".join(["%s"] * len(columns)), conflict_handler=conflict_handler, + returning=returning, ), list(d.values()), ) + if ( + frappe.db.db_type == "postgres" and self.meta.autoname == "hash" and not name + ): # To avoid a transaction block, we regen in try (pg specific) + return self._handle_hash_conflict() except Exception as e: if frappe.db.is_primary_key_violation(e): if self.meta.autoname == "hash": # hash collision? try again - self.flags.retry_count = (self.flags.retry_count or 0) + 1 - if self.flags.retry_count > 5: - raise - self.name = None - self.db_insert() - return + return self._handle_hash_conflict() if not ignore_if_duplicate: frappe.msgprint( diff --git a/frappe/model/qb_query.py b/frappe/model/qb_query.py index 882fcc531f..526529cfa6 100644 --- a/frappe/model/qb_query.py +++ b/frappe/model/qb_query.py @@ -113,9 +113,14 @@ class DatabaseQuery: # if `filters` is a list of strings, its probably fields filters, fields = fields, filters + # Set fields to the requested field or `name` if none specified + if not fields: + fields = [pluck or "name"] + # Handle virtual doctypes before any other processing if is_virtual_doctype(self.doctype): return self._handle_virtual_doctype( + fields, filters, or_filters, start, @@ -162,10 +167,6 @@ class DatabaseQuery: if limit is None: limit = page_length - # Set fields to the requested field or `name` if none specified - if not fields: - fields = [pluck or "name"] - # Check if table exists before running query from frappe.model.meta import get_table_columns @@ -285,6 +286,7 @@ class DatabaseQuery: def _handle_virtual_doctype( self, + fields: list[str] | tuple[str, ...] | str | None, filters: dict[str, FilterValue] | FilterValue | list[list | FilterValue] | None, or_filters: dict[str, FilterValue] | FilterValue | list[list | FilterValue] | None, start: int | None, @@ -331,6 +333,7 @@ class DatabaseQuery: _page_length = page_length or limit or limit_page_length or 20 kwargs = { + "fields": fields, "filters": filters, "or_filters": or_filters, "start": start or offset or limit_start or 0, diff --git a/frappe/public/js/form_builder/components/Field.vue b/frappe/public/js/form_builder/components/Field.vue index 36804beb11..f6e31a2da3 100644 --- a/frappe/public/js/form_builder/components/Field.vue +++ b/frappe/public/js/form_builder/components/Field.vue @@ -88,9 +88,6 @@ function make_dialog(frm) { let fieldname = props.field.df.fieldname; let field_option = props.field.df.options; let filters = frm.filter_group.get_filters().map((filter) => { - // last element is a boolean which hides the filter hence not required to store in meta - filter.pop(); - // filter_group component requires options and frm.set_query requires fieldname so storing both filter[0] = field_option; return filter; diff --git a/frappe/public/js/form_builder/components/controls/ButtonControl.vue b/frappe/public/js/form_builder/components/controls/ButtonControl.vue index 6642d5dc49..460ead3055 100644 --- a/frappe/public/js/form_builder/components/controls/ButtonControl.vue +++ b/frappe/public/js/form_builder/components/controls/ButtonControl.vue @@ -1,6 +1,22 @@