From 064ef5a15a5a7c3d85cfe7a794d38d5308474b7f Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Wed, 22 Mar 2023 19:41:41 +0530 Subject: [PATCH 01/14] fix: Avoid list update if user is doing some bulk operation --- frappe/public/js/frappe/list/list_view.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 59784b853e..6b20282099 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -1339,6 +1339,11 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { return; } + // if some bulk operation is happening by selecting list items, don't refresh + if (this.$checks && this.$checks.length) { + return; + } + if (!frappe.get_doc(data?.doctype, data?.name)?.__unsaved) { frappe.model.remove_from_locals(data.doctype, data.name); } From 2036dd19b23dad7859235877e5f0ebbf5b81e95f Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 23 Mar 2023 12:30:50 +0530 Subject: [PATCH 02/14] fix: Get translated value for child tables in print format --- frappe/templates/print_formats/standard_macros.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/templates/print_formats/standard_macros.html b/frappe/templates/print_formats/standard_macros.html index 5dcbaff7c5..2bfcf074ab 100644 --- a/frappe/templates/print_formats/standard_macros.html +++ b/frappe/templates/print_formats/standard_macros.html @@ -56,9 +56,9 @@ {% if doc.child_print_templates %} {%- set child_templates = doc.child_print_templates.get(df.fieldname) -%} -
{{ print_value(tdf, d, doc, visible_columns, child_templates) }}
+
{{ _(print_value(tdf, d, doc, visible_columns, child_templates)) }}
{% else %} -
{{ print_value(tdf, d, doc, visible_columns) }}
+
{{ _(print_value(tdf, d, doc, visible_columns)) }}
{% endif %} {% endfor %} From b39b2e7923c668105673e56467eb0087fe506b40 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 23 Mar 2023 15:54:23 +0530 Subject: [PATCH 03/14] fix: consider JSON as Data for filters closes https://github.com/frappe/frappe/issues/20433 --- frappe/public/js/frappe/list/base_list.js | 1 + frappe/public/js/frappe/ui/filters/filter.js | 1 + 2 files changed, 2 insertions(+) diff --git a/frappe/public/js/frappe/list/base_list.js b/frappe/public/js/frappe/list/base_list.js index 600db57dd1..8852a0df5d 100644 --- a/frappe/public/js/frappe/list/base_list.js +++ b/frappe/public/js/frappe/list/base_list.js @@ -774,6 +774,7 @@ class FilterArea { "Data", "Code", "Phone", + "JSON", "Read Only", ].includes(fieldtype) ) { diff --git a/frappe/public/js/frappe/ui/filters/filter.js b/frappe/public/js/frappe/ui/filters/filter.js index c2f795833c..5902c136bd 100644 --- a/frappe/public/js/frappe/ui/filters/filter.js +++ b/frappe/public/js/frappe/ui/filters/filter.js @@ -508,6 +508,7 @@ frappe.ui.filter_utils = { "HTML Editor", "Tag", "Phone", + "JSON", "Comments", "Barcode", "Dynamic Link", From 5a91ac945cb5afcccd005b706254105db6a4294d Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 23 Mar 2023 16:16:14 +0530 Subject: [PATCH 04/14] fix: doctype form - hide irrelevant fields --- frappe/core/doctype/doctype/doctype.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json index 671a6e86e6..b3196158f5 100644 --- a/frappe/core/doctype/doctype/doctype.json +++ b/frappe/core/doctype/doctype/doctype.json @@ -189,6 +189,7 @@ }, { "default": "0", + "depends_on": "eval:!doc.istable", "fieldname": "beta", "fieldtype": "Check", "label": "Beta" @@ -463,6 +464,7 @@ }, { "default": "0", + "depends_on": "eval:!doc.istable", "description": "Tree structures are implemented using Nested Set", "fieldname": "is_tree", "fieldtype": "Check", @@ -539,6 +541,7 @@ }, { "default": "0", + "depends_on": "eval:!doc.istable", "fieldname": "is_virtual", "fieldtype": "Check", "label": "Is Virtual" @@ -622,6 +625,7 @@ }, { "default": "0", + "depends_on": "eval:!doc.istable", "description": "Enables Calendar and Gantt views.", "fieldname": "is_calendar_and_gantt", "fieldtype": "Check", @@ -708,7 +712,7 @@ "link_fieldname": "reference_doctype" } ], - "modified": "2023-01-04 17:23:09.206018", + "modified": "2023-03-23 16:15:51.067267", "modified_by": "Administrator", "module": "Core", "name": "DocType", From 3f717f2fbdc13571d409a99f94df25c78aa5886b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 23 Mar 2023 16:55:09 +0530 Subject: [PATCH 05/14] perf: Don't re-initate sessions in realtime.py Session is already created for all requests in app.py -> init_request -> HTTPRequest() --- frappe/realtime.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/frappe/realtime.py b/frappe/realtime.py index 6283b8eb80..4a7cce0f45 100644 --- a/frappe/realtime.py +++ b/frappe/realtime.py @@ -105,10 +105,8 @@ def get_redis_server(): @frappe.whitelist(allow_guest=True) def can_subscribe_doc(doctype: str, docname: str) -> bool: from frappe.exceptions import PermissionError - from frappe.sessions import Session - session = Session(None, resume=True).get_session_data() - if not frappe.has_permission(user=session.user, doctype=doctype, doc=docname, ptype="read"): + if not frappe.has_permission(doctype=doctype, doc=docname, ptype="read"): raise PermissionError() return True @@ -118,7 +116,7 @@ def can_subscribe_doc(doctype: str, docname: str) -> bool: def can_subscribe_doctype(doctype: str) -> bool: from frappe.exceptions import PermissionError - if not frappe.has_permission(user=frappe.session.user, doctype=doctype, ptype="read"): + if not frappe.has_permission(doctype=doctype, ptype="read"): raise PermissionError() return True @@ -126,13 +124,9 @@ def can_subscribe_doctype(doctype: str) -> bool: @frappe.whitelist(allow_guest=True) def get_user_info(): - from frappe.sessions import Session - - session = Session(None, resume=True).get_session_data() - return { - "user": session.user, - "user_type": session.user_type, + "user": frappe.session.user, + "user_type": frappe.session.user_type, } From 6e3ef3dc3d0c166e1a02fcba6556e4aae1327b8c Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 23 Mar 2023 17:53:18 +0530 Subject: [PATCH 06/14] test: fixed failing UI test --- cypress/integration/list_view.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cypress/integration/list_view.js b/cypress/integration/list_view.js index 1fed62d678..3fa0758f0c 100644 --- a/cypress/integration/list_view.js +++ b/cypress/integration/list_view.js @@ -54,12 +54,8 @@ context("List View", () => { method: "POST", url: "api/method/frappe.model.workflow.bulk_workflow_approval", }).as("bulk-approval"); - cy.intercept({ - method: "POST", - url: "api/method/frappe.desk.reportview.get", - }).as("real-time-update"); cy.wrap(elements).contains("Approve").click(); - cy.wait(["@bulk-approval", "@real-time-update"]); + cy.wait("@bulk-approval"); cy.wait(300); cy.get_open_dialog().find(".btn-modal-close").click(); cy.reload(); From bd049a42a317b22d0c961ff0a12d26e123e41148 Mon Sep 17 00:00:00 2001 From: Leonard Goertz <49870752+uepselon@users.noreply.github.com> Date: Fri, 24 Mar 2023 04:14:34 +0100 Subject: [PATCH 07/14] fix: fields are rendered empty after save (#20270) Co-authored-by: Ankush Menat --- frappe/public/js/frappe/list/list_view.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 6b20282099..38dc76ec80 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -1344,10 +1344,6 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { return; } - if (!frappe.get_doc(data?.doctype, data?.name)?.__unsaved) { - frappe.model.remove_from_locals(data.doctype, data.name); - } - if (this.avoid_realtime_update()) { return; } From f7f575acbdfb48e086f1fcd39118ddd58c751fd3 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Fri, 24 Mar 2023 04:23:34 +0100 Subject: [PATCH 08/14] ci: copy docs checker from erpnext (#20441) [skip ci] --- .github/helper/documentation.py | 97 ++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 37 deletions(-) diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py index 8156137e3f..b541583fd6 100644 --- a/.github/helper/documentation.py +++ b/.github/helper/documentation.py @@ -1,50 +1,73 @@ import sys +import requests from urllib.parse import urlparse -import requests -docs_repos = [ - "frappe_docs", - "erpnext_documentation", +WEBSITE_REPOS = [ "erpnext_com", "frappe_io", ] +DOCUMENTATION_DOMAINS = [ + "docs.erpnext.com", + "frappeframework.com", +] -def uri_validator(x): - result = urlparse(x) - return all([result.scheme, result.netloc, result.path]) -def docs_link_exists(body): - for line in body.splitlines(): - for word in line.split(): - if word.startswith('http') and uri_validator(word): - parsed_url = urlparse(word) - if parsed_url.netloc == "github.com": - parts = parsed_url.path.split('/') - if len(parts) == 5 and parts[1] == "frappe" and parts[2] in docs_repos: - return True - if parsed_url.netloc in ["docs.erpnext.com", "frappeframework.com"]: - return True +def is_valid_url(url: str) -> bool: + parts = urlparse(url) + return all((parts.scheme, parts.netloc, parts.path)) + + +def is_documentation_link(word: str) -> bool: + if not word.startswith("http") or not is_valid_url(word): + return False + + parsed_url = urlparse(word) + if parsed_url.netloc in DOCUMENTATION_DOMAINS: + return True + + if parsed_url.netloc == "github.com": + parts = parsed_url.path.split("/") + if len(parts) == 5 and parts[1] == "frappe" and parts[2] in WEBSITE_REPOS: + return True + + return False + + +def contains_documentation_link(body: str) -> bool: + return any( + is_documentation_link(word) + for line in body.splitlines() + for word in line.split() + ) + + +def check_pull_request(number: str) -> "tuple[int, str]": + response = requests.get(f"https://api.github.com/repos/frappe/frappe/pulls/{number}") + if not response.ok: + return 1, "Pull Request Not Found! ⚠️" + + payload = response.json() + title = (payload.get("title") or "").lower().strip() + head_sha = (payload.get("head") or {}).get("sha") + body = (payload.get("body") or "").lower() + + if ( + not title.startswith("feat") + or not head_sha + or "no-docs" in body + or "backport" in body + ): + return 0, "Skipping documentation checks... 🏃" + + if contains_documentation_link(body): + return 0, "Documentation Link Found. You're Awesome! 🎉" + + return 1, "Documentation Link Not Found! ⚠️" if __name__ == "__main__": - pr = sys.argv[1] - response = requests.get(f"https://api.github.com/repos/frappe/frappe/pulls/{pr}") - - if response.ok: - payload = response.json() - title = (payload.get("title") or "").lower() - head_sha = (payload.get("head") or {}).get("sha") - body = (payload.get("body") or "").lower() - - if title.startswith("feat") and head_sha and "no-docs" not in body: - if docs_link_exists(body): - print("Documentation Link Found. You're Awesome! 🎉") - - else: - print("Documentation Link Not Found! ⚠️") - sys.exit(1) - - else: - print("Skipping documentation checks... 🏃") + exit_code, message = check_pull_request(sys.argv[1]) + print(message) + sys.exit(exit_code) From 6b3d283cf7ac7ce26907c67fe229fecf356388ef Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 24 Mar 2023 09:58:19 +0530 Subject: [PATCH 09/14] fix: unsubscribe from list_update before resubbing (#20450) resubbing can result in multiple events being fired, so unsubscribe all of them before re-subscribing. missed in https://github.com/frappe/frappe/pull/20423 --- frappe/public/js/frappe/list/list_view.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 38dc76ec80..a7cd09d76d 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -1334,6 +1334,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { return; } frappe.socketio.doctype_subscribe(this.doctype); + frappe.realtime.off("list_update"); frappe.realtime.on("list_update", (data) => { if (data?.doctype !== this.doctype) { return; From 0374d37c624c0d4d406092f361641c9316d850f0 Mon Sep 17 00:00:00 2001 From: HarryPaulo Date: Fri, 24 Mar 2023 04:13:09 -0300 Subject: [PATCH 10/14] feat: show if address is "Disabled" (#20446) --- frappe/public/js/frappe/form/templates/address_list.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/public/js/frappe/form/templates/address_list.html b/frappe/public/js/frappe/form/templates/address_list.html index a6b8bf1377..0e533ed2ea 100644 --- a/frappe/public/js/frappe/form/templates/address_list.html +++ b/frappe/public/js/frappe/form/templates/address_list.html @@ -8,6 +8,8 @@ ({%= __("Primary") %}){% } %} {% if(addr_list[i].is_shipping_address) { %} ({%= __("Shipping") %}){% } %} + {% if(addr_list[i].disabled) { %} + ({%= __("Disabled") %}){% } %} From 0ec7ea45e9b3b291c84fb86026f31105b7df68b5 Mon Sep 17 00:00:00 2001 From: Himanshu Shivhare Date: Fri, 24 Mar 2023 12:49:42 +0530 Subject: [PATCH 11/14] fix: Update social media links (#20400) * YouTube channel addded in about section. I have added ERPNext YouTube channel reference in the about section. #Create an official Handle for YouTube Channel (Like @erpnext or erpnextofficial) * chore: handle [skip ci] * Update about.js YouTube channel name changed. --------- [skip ci] --- frappe/public/js/frappe/ui/toolbar/about.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/ui/toolbar/about.js b/frappe/public/js/frappe/ui/toolbar/about.js index 69cbbfaba0..699db266da 100644 --- a/frappe/public/js/frappe/ui/toolbar/about.js +++ b/frappe/public/js/frappe/ui/toolbar/about.js @@ -20,7 +20,7 @@ frappe.ui.misc.about = function () {

Twitter: https://twitter.com/erpnext

- YouTube: https://www.youtube.com/@erpnextofficial

+ YouTube: https://www.youtube.com/@frappetech


${__("Installed Apps")}

${__("Loading versions...")}
From 543a4c467bdcb91cd5d2e236208c673e7908d5fd Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 24 Mar 2023 12:50:22 +0530 Subject: [PATCH 12/14] fix: social media links [skip ci] --- frappe/public/js/frappe/ui/toolbar/about.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/ui/toolbar/about.js b/frappe/public/js/frappe/ui/toolbar/about.js index 699db266da..b75f950d72 100644 --- a/frappe/public/js/frappe/ui/toolbar/about.js +++ b/frappe/public/js/frappe/ui/toolbar/about.js @@ -18,7 +18,7 @@ frappe.ui.misc.about = function () {

Facebook: https://facebook.com/erpnext

- Twitter: https://twitter.com/erpnext

+ Twitter: https://twitter.com/frappetech

YouTube: https://www.youtube.com/@frappetech


From d9383afae692bfaa83c333b12eef17868888e7e9 Mon Sep 17 00:00:00 2001 From: Ritwik Puri Date: Fri, 24 Mar 2023 13:45:46 +0530 Subject: [PATCH 13/14] fix: exception handling for bulk email sending (#20451) --- frappe/email/doctype/email_queue/email_queue.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py index b474f37e8e..c10494b0d9 100644 --- a/frappe/email/doctype/email_queue/email_queue.py +++ b/frappe/email/doctype/email_queue/email_queue.py @@ -5,6 +5,7 @@ import json import quopri import smtplib import traceback +from contextlib import suppress from email.parser import Parser from email.policy import SMTPUTF8 @@ -706,7 +707,10 @@ class QueueBuilder: if not smtp_server_instance: email_account = q.get_email_account() smtp_server_instance = email_account.get_smtp_server() - q.send(smtp_server_instance=smtp_server_instance) + + with suppress(Exception): + q.send(smtp_server_instance=smtp_server_instance) + smtp_server_instance.quit() def as_dict(self, include_recipients=True): From 86f72195251c5abfcacf5f9db0351fb0b54f8e1c Mon Sep 17 00:00:00 2001 From: gavin Date: Fri, 24 Mar 2023 21:02:30 +0530 Subject: [PATCH 14/14] fix: Auto-Reload after changing time zone (#20456) --- frappe/core/doctype/user/user.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/user/user.js b/frappe/core/doctype/user/user.js index 18e8651819..413dd07dc4 100644 --- a/frappe/core/doctype/user/user.js +++ b/frappe/core/doctype/user/user.js @@ -114,12 +114,16 @@ frappe.ui.form.on("User", { return; } + function hasChanged(doc_attr, boot_attr) { + return (doc_attr || boot_attr) && doc_attr !== boot_attr; + } + if ( doc.name === frappe.session.user && !doc.__unsaved && frappe.all_timezones && - (doc.language || frappe.boot.user.language) && - doc.language !== frappe.boot.user.language + (hasChanged(doc.language, frappe.boot.user.language) || + hasChanged(doc.time_zone, frappe.boot.time_zone.user)) ) { frappe.msgprint(__("Refreshing...")); window.location.reload();