From 638dbb6bcd57865eed020ea9fcc6465ac8348e31 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 6 Mar 2024 14:49:11 +0530 Subject: [PATCH 001/118] fix: disable transaction commits during doc events - Events like doc.save and doc.submit need to be atomic - Document hooks can make it not so atomic. This is extending server script behaviour where server script hooks are not allowed to commit/rollback. --- frappe/database/database.py | 16 +++++++++++++--- frappe/model/document.py | 6 +++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index fc0f5f50cf..03f4cacff4 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -95,8 +95,12 @@ class Database: self.before_rollback = CallbackManager() self.after_rollback = CallbackManager() - # self.db_type: str - # self.last_query (lazy) attribute of last sql query executed + # Setting this to true will disable full rollback and commit + # You can still use savepoint with partial rollback. + self.disable_transaction_control = False + + # self.db_type: str + # self.last_query (lazy) attribute of last sql query executed def setup_type_map(self): pass @@ -1028,6 +1032,10 @@ class Database: def commit(self): """Commit current transaction. Calls SQL `COMMIT`.""" + if self.disable_transaction_control: + self.logger.error("Commit issued during disabled transaction state ignored") + return + self.before_rollback.reset() self.after_rollback.reset() @@ -1042,7 +1050,7 @@ class Database: """`ROLLBACK` current transaction. Optionally rollback to a known save_point.""" if save_point: self.sql(f"rollback to savepoint {save_point}") - else: + elif not self.disable_transaction_control: self.before_commit.reset() self.after_commit.reset() @@ -1052,6 +1060,8 @@ class Database: self.begin() self.after_rollback.run() + else: + self.logger.error("Rollback issued during disabled transaction state ignored") def savepoint(self, save_point): """Savepoints work as a nested transaction. diff --git a/frappe/model/document.py b/frappe/model/document.py index e000923a10..c9ae34a354 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -1300,7 +1300,11 @@ class Document(BaseDocument): def runner(self, method, *args, **kwargs): add_to_return_value(self, fn(self, *args, **kwargs)) for f in hooks: - add_to_return_value(self, f(self, method, *args, **kwargs)) + try: + frappe.db.disable_transaction_control = True + add_to_return_value(self, f(self, method, *args, **kwargs)) + finally: + frappe.db.disable_transaction_control = False return self.__dict__.pop("_return_value", None) From e152fa579ddf930f660f4ea5f02ac76447967165 Mon Sep 17 00:00:00 2001 From: RitvikSardana Date: Thu, 14 Mar 2024 23:15:46 +0530 Subject: [PATCH 002/118] feat: add eval support for link field filters --- frappe/public/js/form_builder/components/Field.vue | 6 +----- frappe/public/js/frappe/form/form.js | 8 +++++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/frappe/public/js/form_builder/components/Field.vue b/frappe/public/js/form_builder/components/Field.vue index 7e5ab99fa3..a4e2f79468 100644 --- a/frappe/public/js/form_builder/components/Field.vue +++ b/frappe/public/js/form_builder/components/Field.vue @@ -97,6 +97,7 @@ function make_dialog(frm) { }); props.field.df.link_filters = JSON.stringify(filters); + store.form.selected_field = props.field.df; frm.dialog.hide(); }, primary_action_label: __("Apply"), @@ -133,11 +134,6 @@ function make_dialog(frm) { } }); } - - // Setting selected field in store because when we click on the dialog the selected field is set to null - frm.dialog.$wrapper.on("click", () => { - store.form.selected_field = props.field.df; - }); } function make_filter_area(frm, doctype) { diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 69a7c6e366..2d9afa7c7a 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -292,13 +292,19 @@ frappe.ui.form.Form = class FrappeForm { for (const d of data) { for (const condition of d) { let [doctype, field, operator, value] = condition; + if (value.includes("eval")) { + // if condition type of 'like' is used then remove % from value + value = value.replace(/%/g, ""); + // get the value to calculate + value = value.split("eval:")[1]; + value = frappe.utils.eval(value, { doc: this.doc, frappe }); + } doctype = doctype.fieldname; if (!parsed_data[doctype]) { parsed_data[doctype] = { filters: {}, }; } - if (!parsed_data[doctype].filters[field]) { parsed_data[doctype].filters[field] = [operator, value]; } From 5756713851b22393bd09f62a5c9481955bbb4549 Mon Sep 17 00:00:00 2001 From: RitvikSardana Date: Fri, 15 Mar 2024 16:26:00 +0530 Subject: [PATCH 003/118] fix: support for adding filters for child table --- frappe/public/js/frappe/form/form.js | 30 +++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 2d9afa7c7a..644364a846 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -284,6 +284,34 @@ frappe.ui.form.Form = class FrappeForm { const filters = fields_with_filters[link_field]; this.set_query(link_field, () => filters); } + + // for child tables + let table_fields = frappe + .get_meta(this.doctype) + .fields.filter((field) => field.fieldtype === "Table"); + // get meta of table fields + let table_field_map = {}; + + table_fields.forEach((field) => { + table_field_map[field.fieldname] = frappe.get_meta(field.options); + }); + // now in table_field_map we have the filter field where link_filters are present + let i = {}; + for (let table_field in table_field_map) { + let filters = table_field_map[table_field].fields + .filter((field) => field.link_filters) + .map((field) => JSON.parse(field.link_filters)); + // console.log(filters) + i[table_field] = this.parse_filters(filters); + } + + for (let parent_fieldname in i) { + let child_field = i[parent_fieldname]; + for (let child_fieldname in child_field) { + let filters = child_field[child_fieldname]; + this.set_query(child_fieldname, parent_fieldname, () => filters); + } + } } parse_filters(data) { @@ -292,7 +320,7 @@ frappe.ui.form.Form = class FrappeForm { for (const d of data) { for (const condition of d) { let [doctype, field, operator, value] = condition; - if (value.includes("eval")) { + if (String(value).startsWith("eval:")) { // if condition type of 'like' is used then remove % from value value = value.replace(/%/g, ""); // get the value to calculate From fbaa35ba1ca606e00ed99bc58de0ac6c441e8266 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 18 Mar 2024 17:31:23 +0100 Subject: [PATCH 004/118] perf: get rid of unnecessary jquery --- frappe/public/js/frappe/list/list_view.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index f20e2d351a..18e4ecf777 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -936,10 +936,10 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { let comment_count = null; if (this.list_view_settings && !this.list_view_settings.disable_comment_count) { - comment_count = $(``); - $(comment_count).append(` + comment_count = ` ${frappe.utils.icon("es-line-chat-alt")} - ${doc._comment_count > 99 ? "99+" : doc._comment_count || 0}`); + ${doc._comment_count > 99 ? "99+" : doc._comment_count || 0} + `; } html += ` @@ -948,7 +948,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { ${settings_button || assigned_to} ${modified} - ${comment_count ? $(comment_count).prop("outerHTML") : ""} + ${comment_count || ""} ${comment_count ? '·' : ""}