From 3fd60b70eeec03b29d426407a3202d111bef7658 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 18 Aug 2021 11:42:44 +0530 Subject: [PATCH 1/9] fix: Length change for docfield not updated in Database --- frappe/custom/doctype/customize_form/customize_form.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index 8de194fb00..94f25a41aa 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -193,6 +193,16 @@ class CustomizeForm(Document): if prop == "fieldtype": self.validate_fieldtype_change(df, meta_df[0].get(prop), df.get(prop)) + elif prop == "length": + old_value_length = cint(meta_df[0].get(prop)) + new_value_length = cint(df.get(prop)) + + if new_value_length and (old_value_length > new_value_length): + self.check_length_for_fieldtypes.append({'df': df, 'old_value': meta_df[0].get(prop)}) + self.validate_fieldtype_length() + else: + self.flags.update_db = True + elif prop == "allow_on_submit" and df.get(prop): if not frappe.db.get_value("DocField", {"parent": self.doc_type, "fieldname": df.fieldname}, "allow_on_submit"): From cd9b07b3bbdb80c27370301f9f786c537a9ff646 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 21 Aug 2021 19:07:44 +0530 Subject: [PATCH 2/9] test: Add test case for docfield length property update --- .../doctype/customize_form/test_customize_form.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/frappe/custom/doctype/customize_form/test_customize_form.py b/frappe/custom/doctype/customize_form/test_customize_form.py index aef95cd676..6783e52d68 100644 --- a/frappe/custom/doctype/customize_form/test_customize_form.py +++ b/frappe/custom/doctype/customize_form/test_customize_form.py @@ -188,6 +188,19 @@ class TestCustomizeForm(unittest.TestCase): def test_core_doctype_customization(self): self.assertRaises(frappe.ValidationError, self.get_customize_form, 'User') + def test_save_customization_length_field_property(self): + # Using Notification Log doctype as it doesn't have any other custom fields + d = self.get_customize_form("Notification Log") + + document_name = d.get("fields", {"fieldname": "document_name"})[0] + document_name.length = 255 + d.run_method("save_customization") + + self.assertEqual(frappe.db.get_value("Property Setter", + {"doc_type": "Notification Log", "property": "length", "field_name": "document_name"}, "value"), '255') + + self.assertTrue(d.flags.update_db) + def test_custom_link(self): try: # create a dummy doctype linked to Event From 863b462bbd4c0d9afb037610d7a5537bf51939b6 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 26 Aug 2021 10:58:59 +0530 Subject: [PATCH 3/9] fix: Pass get_query to link selector to get filtered list --- frappe/public/js/frappe/form/grid.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js index 05c70b214d..dd1d622bab 100644 --- a/frappe/public/js/frappe/form/grid.js +++ b/frappe/public/js/frappe/form/grid.js @@ -786,6 +786,7 @@ export default class Grid { doctype: link_field.options, fieldname: link, qty_fieldname: qty, + get_query: link_field.get_query, target: this, txt: "" }); From 8eb7f0f71915a071fbf560dee183ce06a94e0f4a Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 26 Aug 2021 10:59:47 +0530 Subject: [PATCH 4/9] fix: Call search after value is set to get latest filtered results --- frappe/public/js/frappe/form/link_selector.js | 97 ++++++++++--------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/frappe/public/js/frappe/form/link_selector.js b/frappe/public/js/frappe/form/link_selector.js index b8f1b3a842..3ae03dbe91 100644 --- a/frappe/public/js/frappe/form/link_selector.js +++ b/frappe/public/js/frappe/form/link_selector.js @@ -96,10 +96,10 @@ frappe.ui.form.LinkSelector = class LinkSelector { .attr('data-value', v[0]) .click(function () { var value = $(this).attr("data-value"); - var $link = this; if (me.target.is_grid) { // set in grid - me.set_in_grid(value); + // call search after value is set to get latest filtered results + me.set_in_grid(value).then(() => me.search()); } else { if (me.target.doctype) me.target.parse_validate_and_set_in_model(value); @@ -110,8 +110,8 @@ frappe.ui.form.LinkSelector = class LinkSelector { me.dialog.hide(); } return false; - }) - }) + }); + }); } else { $('


' + __("No Results") + '' + (frappe.model.can_create(me.doctype) ? @@ -130,49 +130,56 @@ frappe.ui.form.LinkSelector = class LinkSelector { }, this.dialog.get_primary_btn()); } - set_in_grid (value) { - var me = this, updated = false; - var d = null; - if (this.qty_fieldname) { - frappe.prompt({ - fieldname: "qty", fieldtype: "Float", label: "Qty", - "default": 1, reqd: 1 - }, function (data) { - $.each(me.target.frm.doc[me.target.df.fieldname] || [], function (i, d) { - if (d[me.fieldname] === value) { - frappe.model.set_value(d.doctype, d.name, me.qty_fieldname, data.qty); - frappe.show_alert(__("Added {0} ({1})", [value, d[me.qty_fieldname]])); - updated = true; - return false; + set_in_grid(value) { + return new Promise((resolve) => { + if (this.qty_fieldname) { + frappe.prompt({ + fieldname: "qty", + fieldtype: "Float", + label: "Qty", + default: 1, + reqd: 1 + }, (data) => { + let updated = (this.target.frm.doc[this.target.df.fieldname] || []).some(d => { + if (d[this.fieldname] === value) { + frappe.model.set_value(d.doctype, d.name, this.qty_fieldname, data.qty).then(() => { + frappe.show_alert(__("Added {0} ({1})", [value, d[this.qty_fieldname]])); + resolve(); + }); + return true; + } + }); + if (!updated) { + let d = null; + frappe.run_serially([ + () => d = this.target.add_new_row(), + () => frappe.timeout(0.1), + () => { + let args = {}; + args[this.fieldname] = value; + args[this.qty_fieldname] = data.qty; + return frappe.model.set_value(d.doctype, d.name, args); + }, + () => frappe.show_alert(__("Added {0} ({1})", [value, data.qty])), + () => resolve() + ]); } + }, __("Set Quantity"), __("Set")); + } else if (this.dynamic_link_field) { + let d = this.target.add_new_row(); + frappe.model.set_value(d.doctype, d.name, this.dynamic_link_field, this.dynamic_link_reference); + frappe.model.set_value(d.doctype, d.name, this.fieldname, value).then(() => { + frappe.show_alert(__("{0} {1} added", [this.dynamic_link_reference, value])); + resolve(); }); - if (!updated) { - frappe.run_serially([ - () => { - d = me.target.add_new_row(); - }, - () => frappe.timeout(0.1), - () => { - let args = {}; - args[me.fieldname] = value; - args[me.qty_fieldname] = data.qty; - - return frappe.model.set_value(d.doctype, d.name, args); - }, - () => frappe.show_alert(__("Added {0} ({1})", [value, data.qty])) - ]); - } - }, __("Set Quantity"), __("Set")); - } else if (me.dynamic_link_field) { - var d = me.target.add_new_row(); - frappe.model.set_value(d.doctype, d.name, me.dynamic_link_field, me.dynamic_link_reference); - frappe.model.set_value(d.doctype, d.name, me.fieldname, value); - frappe.show_alert(__("{0} {1} added", [me.dynamic_link_reference, value])); - } else { - var d = me.target.add_new_row(); - frappe.model.set_value(d.doctype, d.name, me.fieldname, value); - frappe.show_alert(__("{0} added", [value])); - } + } else { + let d = this.target.add_new_row(); + frappe.model.set_value(d.doctype, d.name, this.fieldname, value).then(() => { + frappe.show_alert(__("{0} added", [value])); + resolve(); + }); + } + }); } }; From 783165c01e4bd0433814bd145a4960b92130100b Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 30 Aug 2021 12:00:31 +0530 Subject: [PATCH 5/9] fix: Retry get_redis_conn until "sure" If ConnectionError or BusyLoadingError occurs, try every second for up-to 10 times. Why: `bench start` exits just as i run it at times. This happens when the worker's processes each try to fetch a redis conn but redis isnt up yet. The 3 workeer processes exit with 1 and our procman gives up too. --- frappe/utils/background_jobs.py | 9 ++++++++- requirements.txt | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index 567268f760..b8f3372540 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -3,12 +3,14 @@ import socket import time from uuid import uuid4 from collections import defaultdict +from typing import List import redis -from typing import List +from redis.exceptions import BusyLoadingError, ConnectionError from rq import Connection, Queue, Worker from rq.logutils import setup_loghandlers +from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed import frappe from frappe import _ @@ -233,6 +235,11 @@ def validate_queue(queue, default_queue_list=None): if queue not in default_queue_list: frappe.throw(_("Queue should be one of {0}").format(', '.join(default_queue_list))) +@retry( + retry=retry_if_exception_type(BusyLoadingError) | retry_if_exception_type(ConnectionError), + stop=stop_after_attempt(10), + wait=wait_fixed(1) +) def get_redis_conn(username=None, password=None): if not hasattr(frappe.local, 'conf'): raise Exception('You need to call frappe.init') diff --git a/requirements.txt b/requirements.txt index 51327953d5..be96520a02 100644 --- a/requirements.txt +++ b/requirements.txt @@ -77,3 +77,4 @@ Whoosh~=2.7.4 wrapt~=1.12.1 xlrd~=2.0.1 zxcvbn-python~=4.4.24 +tenacity~=8.0.1 From a5ded007a53390e2fdf8ca0cd9010b4106c5c68f Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 30 Aug 2021 12:54:37 +0530 Subject: [PATCH 6/9] fix(ci): Run all builds on github push events Issue: No PR number is detected on Push events and all builds are skipped. We want the opposite to be true, so we're running all builds on merges in hopes of testing better. --- .github/helper/roulette.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/helper/roulette.py b/.github/helper/roulette.py index dd3081822e..9831df7f30 100644 --- a/.github/helper/roulette.py +++ b/.github/helper/roulette.py @@ -38,8 +38,12 @@ if __name__ == "__main__": pr_number = os.environ.get("PR_NUMBER") repo = os.environ.get("REPO_NAME") - if not files_list and pr_number: - files_list = get_files_list(pr_number=pr_number, repo=repo) + # this is a push build, run all builds + if not pr_number: + os.system('echo "::set-output name=build::strawberry"') + sys.exit(0) + + files_list = files_list or get_files_list(pr_number=pr_number, repo=repo) if not files_list: print("No files' changes detected. Build is shutting") From 0c7c1dcb890410ba6c5b18f2e6fec01609a31ca3 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 30 Aug 2021 20:02:29 +0530 Subject: [PATCH 7/9] feat: Bulk export from list view (#13906) Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- .../js/frappe/data_import/data_exporter.js | 16 ++++++++-------- frappe/public/js/frappe/list/bulk_operations.js | 10 ++++++++++ frappe/public/js/frappe/list/list_view.js | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/data_import/data_exporter.js b/frappe/public/js/frappe/data_import/data_exporter.js index 03e6288856..8fa5a08945 100644 --- a/frappe/public/js/frappe/data_import/data_exporter.js +++ b/frappe/public/js/frappe/data_import/data_exporter.js @@ -13,6 +13,13 @@ frappe.data_import.DataExporter = class DataExporter { this.dialog = new frappe.ui.Dialog({ title: __('Export Data'), fields: [ + { + fieldtype: 'Select', + fieldname: 'file_type', + label: __('File Type'), + options: ['Excel', 'CSV'], + default: 'CSV' + }, { fieldtype: 'Select', fieldname: 'export_records', @@ -45,13 +52,6 @@ frappe.data_import.DataExporter = class DataExporter { fieldname: 'filter_area', depends_on: doc => doc.export_records === 'by_filter' }, - { - fieldtype: 'Select', - fieldname: 'file_type', - label: __('File Type'), - options: ['Excel', 'CSV'], - default: 'CSV' - }, { fieldtype: 'Section Break' }, @@ -141,7 +141,7 @@ frappe.data_import.DataExporter = class DataExporter { let for_insert = this.exporting_for === 'Insert New Records'; let section_title = for_insert ? __('Select Fields To Insert') : __('Select Fields To Update'); let $select_all_buttons = $(` -

+
${section_title}