From 53712ed556c8fbf010a9bfb9e23ceeebbb3f1975 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 10 Oct 2023 13:02:05 +0530 Subject: [PATCH 001/136] fix: only show amended docs in dropdown --- frappe/core/doctype/audit_trail/audit_trail.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frappe/core/doctype/audit_trail/audit_trail.js b/frappe/core/doctype/audit_trail/audit_trail.js index ffd289257e..6db096085d 100644 --- a/frappe/core/doctype/audit_trail/audit_trail.js +++ b/frappe/core/doctype/audit_trail/audit_trail.js @@ -16,6 +16,14 @@ frappe.ui.form.on("Audit Trail", { }; }); + frm.set_query("document", () => { + return { + filters: { + amended_from: ["!=", ""], + }, + }; + }); + frm.page.set_primary_action("Compare", () => { frm.call({ doc: frm.doc, From 6758be3e24da10c1ff52612d9abb35c399501c44 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 10 Oct 2023 13:05:18 +0530 Subject: [PATCH 002/136] feat: start and end date filters --- frappe/core/doctype/audit_trail/audit_trail.json | 14 +++++++++++++- frappe/core/doctype/audit_trail/audit_trail.py | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/audit_trail/audit_trail.json b/frappe/core/doctype/audit_trail/audit_trail.json index 8ad5a88c37..454948bdd8 100644 --- a/frappe/core/doctype/audit_trail/audit_trail.json +++ b/frappe/core/doctype/audit_trail/audit_trail.json @@ -6,8 +6,10 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ + "start_date", "doctype_name", "column_break_peck", + "end_date", "document", "section_break_gppi", "version_table", @@ -68,13 +70,23 @@ "fieldtype": "Section Break", "hidden": 1, "label": "Rows Removed" + }, + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "Start Date" + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "End Date" } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-08-22 12:12:59.780845", + "modified": "2023-10-10 12:55:56.556403", "modified_by": "Administrator", "module": "Core", "name": "Audit Trail", diff --git a/frappe/core/doctype/audit_trail/audit_trail.py b/frappe/core/doctype/audit_trail/audit_trail.py index b8e4e48b43..526a28c401 100644 --- a/frappe/core/doctype/audit_trail/audit_trail.py +++ b/frappe/core/doctype/audit_trail/audit_trail.py @@ -20,6 +20,8 @@ class AuditTrail(Document): doctype_name: DF.Link document: DF.DynamicLink + end_date: DF.Date | None + start_date: DF.Date | None # end: auto-generated types pass From 8707fbf248503ba45c403b496faa6fed9df7fa3c Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 10 Oct 2023 15:21:04 +0530 Subject: [PATCH 003/136] fix: make date filters mandatory --- frappe/core/doctype/audit_trail/audit_trail.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/audit_trail/audit_trail.json b/frappe/core/doctype/audit_trail/audit_trail.json index 454948bdd8..c0e9e38e95 100644 --- a/frappe/core/doctype/audit_trail/audit_trail.json +++ b/frappe/core/doctype/audit_trail/audit_trail.json @@ -74,19 +74,21 @@ { "fieldname": "start_date", "fieldtype": "Date", - "label": "Start Date" + "label": "Start Date", + "reqd": 1 }, { "fieldname": "end_date", "fieldtype": "Date", - "label": "End Date" + "label": "End Date", + "reqd": 1 } ], "hide_toolbar": 1, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-10-10 12:55:56.556403", + "modified": "2023-10-10 15:20:00.558979", "modified_by": "Administrator", "module": "Core", "name": "Audit Trail", From 56d1bf2732446624efaba3fecc6c111c030fa1d6 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 10 Oct 2023 15:21:43 +0530 Subject: [PATCH 004/136] fix: filter document field using date --- frappe/core/doctype/audit_trail/audit_trail.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/core/doctype/audit_trail/audit_trail.js b/frappe/core/doctype/audit_trail/audit_trail.js index 6db096085d..3ed129b8ed 100644 --- a/frappe/core/doctype/audit_trail/audit_trail.js +++ b/frappe/core/doctype/audit_trail/audit_trail.js @@ -20,6 +20,7 @@ frappe.ui.form.on("Audit Trail", { return { filters: { amended_from: ["!=", ""], + creation: ["between", [frm.doc.start_date, frm.doc.end_date]], }, }; }); From 796c2608b36dc7ea688e7e89d9d82454e44ec690 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 10 Oct 2023 15:25:02 +0530 Subject: [PATCH 005/136] fix: validate date fields explicitly --- .../core/doctype/audit_trail/audit_trail.py | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/frappe/core/doctype/audit_trail/audit_trail.py b/frappe/core/doctype/audit_trail/audit_trail.py index 526a28c401..668efa8765 100644 --- a/frappe/core/doctype/audit_trail/audit_trail.py +++ b/frappe/core/doctype/audit_trail/audit_trail.py @@ -20,22 +20,24 @@ class AuditTrail(Document): doctype_name: DF.Link document: DF.DynamicLink - end_date: DF.Date | None - start_date: DF.Date | None + end_date: DF.Date + start_date: DF.Date # end: auto-generated types pass def validate(self): - self.validate_doctype_name() - self.validate_document() + self.validate_fields() - def validate_doctype_name(self): - if not self.doctype_name: - frappe.throw(_("{} field cannot be empty.").format(frappe.bold("Doctype"))) - - def validate_document(self): - if not self.document: - frappe.throw(_("{} field cannot be empty.").format(frappe.bold("Document"))) + def validate_fields(self): + fields_dict = { + "DocType": self.doctype_name, + "Document": self.document, + "Start Date": self.start_date, + "End Date": self.end_date, + } + for field in fields_dict: + if not fields_dict[field]: + frappe.throw(_("{} field cannot be empty.").format(frappe.bold(field))) @frappe.whitelist() def compare_document(self): From 22e138de9e37d8835657b52042bea7a5a7441372 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 10 Oct 2023 15:32:03 +0530 Subject: [PATCH 006/136] fix: filter docs in controller --- frappe/core/doctype/audit_trail/audit_trail.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/audit_trail/audit_trail.py b/frappe/core/doctype/audit_trail/audit_trail.py index 668efa8765..29d8ee8eae 100644 --- a/frappe/core/doctype/audit_trail/audit_trail.py +++ b/frappe/core/doctype/audit_trail/audit_trail.py @@ -7,6 +7,7 @@ import frappe from frappe import _ from frappe.core.doctype.version.version import get_diff from frappe.model.document import Document +from frappe.utils import compare class AuditTrail(Document): @@ -64,9 +65,15 @@ class AuditTrail(Document): def get_amended_documents(self): amended_document_names = [] curr_doc = self.document - while curr_doc and len(amended_document_names) < 5: + creation = frappe.db.get_value(self.doctype_name, self.document, "creation") + while ( + curr_doc + and len(amended_document_names) < 5 + and compare(creation, ">=", self.start_date, "Date") + ): amended_document_names.append(curr_doc) curr_doc = frappe.db.get_value(self.doctype_name, curr_doc, "amended_from") + creation = frappe.db.get_value(self.doctype_name, curr_doc, "creation") amended_document_names = amended_document_names[::-1] return amended_document_names From 3c4fa8415e19309eec9fc3513d7c1aaf07881fc9 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 10 Oct 2023 15:33:13 +0530 Subject: [PATCH 007/136] fix: set date fields in test --- frappe/core/doctype/audit_trail/test_audit_trail.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/audit_trail/test_audit_trail.py b/frappe/core/doctype/audit_trail/test_audit_trail.py index 45093de033..c5f195a9f6 100644 --- a/frappe/core/doctype/audit_trail/test_audit_trail.py +++ b/frappe/core/doctype/audit_trail/test_audit_trail.py @@ -3,6 +3,7 @@ import frappe from frappe.tests.utils import FrappeTestCase +from frappe.utils import today class TestAuditTrail(FrappeTestCase): @@ -129,6 +130,11 @@ def amend_document(amend_from, changed_fields, rows_updated, submit=False): def create_comparator_doc(doctype_name, document): comparator = frappe.new_doc("Audit Trail") - comparator.doctype_name = doctype_name - comparator.document = document + args_dict = { + "doctype_name": doctype_name, + "document": document, + "start_date": today(), + "end_date": today(), + } + comparator.update(args_dict) return comparator From c0eab528772d96ade6a1014dd6dc1612e33ab5e8 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Tue, 17 Oct 2023 12:23:16 +0530 Subject: [PATCH 008/136] chore: fix translation --- frappe/translations/fr.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/translations/fr.csv b/frappe/translations/fr.csv index 5a2302acb3..273d2de5c6 100644 --- a/frappe/translations/fr.csv +++ b/frappe/translations/fr.csv @@ -4852,4 +4852,4 @@ Published on,Publié le, Bottom,Bas, Top,Haut, List View,Vue en liste, -Edit,Détail,Edit grid row, +Edit,Détail,Edit grid row From 6aa795b855cbff1b09cb669e61a42eff97f04f47 Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Mon, 23 Oct 2023 00:25:42 +0500 Subject: [PATCH 009/136] perf(remove_script_and_style): caching for performance --- frappe/public/js/frappe/dom.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/frappe/public/js/frappe/dom.js b/frappe/public/js/frappe/dom.js index 203e5bde7a..0b6dbf0eb8 100644 --- a/frappe/public/js/frappe/dom.js +++ b/frappe/public/js/frappe/dom.js @@ -32,7 +32,26 @@ frappe.dom = { // execute the script globally document.getElementsByTagName("head")[0].appendChild(el); }, + + _remove_script_and_style_cache: {}, + remove_script_and_style: function (txt) { + // do not parse if html tag not found (for performance and cache memory reduction) + if (!txt || !txt.includes("<")) { + return txt; + } + + // cache already processed strings since DOMParser.parseFromString is relatively slow + let cached = this._remove_script_and_style_cache[txt]; + if (cached) { + // true means no evil tags, return string as is undisturbed + if (cached === true) { + return txt; + } else { + return cached; + } + } + const evil_tags = ["script", "style", "noscript", "title", "meta", "base", "head"]; const parser = new DOMParser(); const doc = parser.parseFromString(txt, "text/html"); @@ -55,9 +74,11 @@ frappe.dom = { } if (found) { + this._remove_script_and_style_cache[txt] = body.innerHTML; return body.innerHTML; } else { // don't disturb + this._remove_script_and_style_cache[txt] = true; return txt; } }, From 9ff71de4828b34747db4c60c72853c391c2efe7d Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Mon, 23 Oct 2023 00:52:35 +0500 Subject: [PATCH 010/136] perf(Grid): debounced_refresh_remove_rows_button --- frappe/public/js/frappe/form/grid.js | 2 ++ frappe/public/js/frappe/form/grid_row.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js index ed5efd7063..5c66ceda50 100644 --- a/frappe/public/js/frappe/form/grid.js +++ b/frappe/public/js/frappe/form/grid.js @@ -310,6 +310,8 @@ export default class Grid { this.remove_all_rows_button.toggleClass("hidden", !show_delete_all_btn); } + debounced_refresh_remove_rows_button = frappe.utils.debounce(this.refresh_remove_rows_button, 100) + get_selected() { return (this.grid_rows || []) .map((row) => { diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index 15dd8f4fd1..1117d92869 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -90,7 +90,7 @@ export default class GridRow { this.wrapper .find(".grid-row-check") .prop("checked", this.doc ? !!this.doc.__checked : false); - this.grid.refresh_remove_rows_button(); + this.grid.debounced_refresh_remove_rows_button(); } remove() { var me = this; From 5bc73e2ab879f2a58881e256b650ff544d58fd9c Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Mon, 23 Oct 2023 13:50:47 +0500 Subject: [PATCH 011/136] chore: linting --- frappe/public/js/frappe/form/grid.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js index 5c66ceda50..905773bc3b 100644 --- a/frappe/public/js/frappe/form/grid.js +++ b/frappe/public/js/frappe/form/grid.js @@ -310,7 +310,10 @@ export default class Grid { this.remove_all_rows_button.toggleClass("hidden", !show_delete_all_btn); } - debounced_refresh_remove_rows_button = frappe.utils.debounce(this.refresh_remove_rows_button, 100) + debounced_refresh_remove_rows_button = frappe.utils.debounce( + this.refresh_remove_rows_button, + 100 + ); get_selected() { return (this.grid_rows || []) From b000169718896b7dcf53504ecc7020c085ce8b6c Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Mon, 23 Oct 2023 16:22:28 +0500 Subject: [PATCH 012/136] perf(remove_script_and_style): regex check instead of caching --- frappe/public/js/frappe/dom.js | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/frappe/public/js/frappe/dom.js b/frappe/public/js/frappe/dom.js index 0b6dbf0eb8..02f359214b 100644 --- a/frappe/public/js/frappe/dom.js +++ b/frappe/public/js/frappe/dom.js @@ -33,26 +33,21 @@ frappe.dom = { document.getElementsByTagName("head")[0].appendChild(el); }, - _remove_script_and_style_cache: {}, - remove_script_and_style: function (txt) { - // do not parse if html tag not found (for performance and cache memory reduction) - if (!txt || !txt.includes("<")) { + const evil_tags = ["script", "style", "noscript", "title", "meta", "base", "head"]; + const unsafe_tags = ["link"]; + + if (!this.unsafe_tags_regex) { + const evil_and_unsafe_tags = evil_tags.concat(unsafe_tags); + const regex_str = evil_and_unsafe_tags.map(t => `<([\\s]*)${t}`).join("|"); + this.unsafe_tags_regex = new RegExp(regex_str, "im"); + } + + // if no unsafe tags are present return as is to prevent unncessary expensive parsing + if (!txt || !this.unsafe_tags_regex.test(txt)) { return txt; } - // cache already processed strings since DOMParser.parseFromString is relatively slow - let cached = this._remove_script_and_style_cache[txt]; - if (cached) { - // true means no evil tags, return string as is undisturbed - if (cached === true) { - return txt; - } else { - return cached; - } - } - - const evil_tags = ["script", "style", "noscript", "title", "meta", "base", "head"]; const parser = new DOMParser(); const doc = parser.parseFromString(txt, "text/html"); const body = doc.body; @@ -74,11 +69,9 @@ frappe.dom = { } if (found) { - this._remove_script_and_style_cache[txt] = body.innerHTML; return body.innerHTML; } else { // don't disturb - this._remove_script_and_style_cache[txt] = true; return txt; } }, From 12e74d2af5dc4e90117bc83889d23f112834ca8c Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Mon, 23 Oct 2023 16:34:50 +0500 Subject: [PATCH 013/136] chore: linting --- frappe/public/js/frappe/dom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/dom.js b/frappe/public/js/frappe/dom.js index 02f359214b..33b9e3e403 100644 --- a/frappe/public/js/frappe/dom.js +++ b/frappe/public/js/frappe/dom.js @@ -39,7 +39,7 @@ frappe.dom = { if (!this.unsafe_tags_regex) { const evil_and_unsafe_tags = evil_tags.concat(unsafe_tags); - const regex_str = evil_and_unsafe_tags.map(t => `<([\\s]*)${t}`).join("|"); + const regex_str = evil_and_unsafe_tags.map((t) => `<([\\s]*)${t}`).join("|"); this.unsafe_tags_regex = new RegExp(regex_str, "im"); } From 65f62bb52f38ebe2d154b18bed4a668418d03e35 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Mon, 30 Oct 2023 12:23:28 +0530 Subject: [PATCH 014/136] fix: Create doctype through a dialog --- frappe/core/doctype/doctype/doctype_list.js | 107 ++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 frappe/core/doctype/doctype/doctype_list.js diff --git a/frappe/core/doctype/doctype/doctype_list.js b/frappe/core/doctype/doctype/doctype_list.js new file mode 100644 index 0000000000..5f6ce6c098 --- /dev/null +++ b/frappe/core/doctype/doctype/doctype_list.js @@ -0,0 +1,107 @@ +frappe.listview_settings["DocType"] = { + primary_action: function () { + let non_developer = frappe.session.user !== "Administrator" || !frappe.boot.developer_mode; + let new_d = new frappe.ui.Dialog({ + title: __("Create New DocType"), + fields: [ + { + label: __("DocType Name"), + fieldname: "doctype_name", + fieldtype: "Data", + reqd: 1, + }, + { fieldtype: "Column Break" }, + { + label: __("Module"), + fieldname: "module", + fieldtype: "Link", + options: "Module Def", + reqd: 1, + }, + { fieldtype: "Section Break" }, + { + label: __("Is Submittable"), + fieldname: "is_submittable", + fieldtype: "Check", + description: __( + "Once submitted, submittable documents cannot be changed. They can only be Cancelled and Amended." + ), + depends_on: "eval:!doc.istable && !doc.issingle", + }, + { + label: __("Is Child Table"), + fieldname: "istable", + fieldtype: "Check", + description: __("Child Tables are shown as a Grid in other DocTypes"), + depends_on: "eval:!doc.is_submittable && !doc.issingle", + }, + { + label: __("Editable Grid"), + fieldname: "editable_grid", + fieldtype: "Check", + depends_on: "istable", + default: 1, + }, + { + label: __("Is Single"), + fieldname: "issingle", + fieldtype: "Check", + description: __( + "Single Types have only one record no tables associated. Values are stored in tabSingles" + ), + depends_on: "eval:!doc.istable && !doc.is_submittable", + }, + { + label: __("Custom?"), + fieldname: "custom", + fieldtype: "Check", + default: non_developer, + read_only: non_developer, + }, + ], + primary_action_label: __("Create & Continue"), + primary_action(values) { + if (!values.istable) values.editable_grid = 0; + frappe.db + .insert({ + doctype: "DocType", + name: values.doctype_name, + module: values.module, + istable: values.istable, + editable_grid: values.editable_grid, + issingle: values.issingle, + custom: values.custom, + is_submittable: values.is_submittable, + permissions: [ + { + create: 1, + delete: 1, + email: 1, + export: 1, + print: 1, + read: 1, + report: 1, + role: "System Manager", + share: 1, + write: 1, + }, + ], + fields: [ + { + label: "Title", + fieldtype: "Data", + }, + ], + }) + .then((doc) => { + frappe.set_route("Form", "DocType", doc.name); + }); + }, + secondary_action_label: __("Cancel"), + secondary_action() { + new_d.hide(); + }, + }); + new_d.show(); + }, +}; From 8b5dffff98522d40d561f6e1906a90be0e11bf36 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Mon, 30 Oct 2023 12:24:08 +0530 Subject: [PATCH 015/136] chore: made form tab as a first tab in doctype form --- frappe/core/doctype/doctype/doctype.json | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json index 21d5fbfac8..3610d88651 100644 --- a/frappe/core/doctype/doctype/doctype.json +++ b/frappe/core/doctype/doctype/doctype.json @@ -8,6 +8,11 @@ "document_type": "Document", "engine": "InnoDB", "field_order": [ + "form_builder_tab", + "form_builder", + "fields_section", + "fields", + "details_tab", "sb0", "module", "is_submittable", @@ -53,10 +58,6 @@ "advanced", "engine", "migration_hash", - "form_builder_tab", - "form_builder", - "fields_section", - "fields", "settings_tab", "form_settings_section", "image_field", @@ -660,6 +661,11 @@ "fieldtype": "Tab Break", "label": "Connections", "show_dashboard": 1 + }, + { + "fieldname": "details_tab", + "fieldtype": "Tab Break", + "label": "Details" } ], "icon": "fa fa-bolt", @@ -742,7 +748,7 @@ "link_fieldname": "reference_doctype" } ], - "modified": "2023-08-29 12:27:06.587523", + "modified": "2023-10-30 12:19:49.757126", "modified_by": "Administrator", "module": "Core", "name": "DocType", From 3407a9963eb8b1eadb9a99ac71ae82a936440b36 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Mon, 30 Oct 2023 12:29:06 +0530 Subject: [PATCH 016/136] chore: hide fields table --- frappe/core/doctype/doctype/doctype.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json index 3610d88651..233fcc30cc 100644 --- a/frappe/core/doctype/doctype/doctype.json +++ b/frappe/core/doctype/doctype/doctype.json @@ -654,6 +654,7 @@ "collapsible": 1, "fieldname": "fields_section", "fieldtype": "Section Break", + "hidden": 1, "label": "Fields" }, { @@ -748,7 +749,7 @@ "link_fieldname": "reference_doctype" } ], - "modified": "2023-10-30 12:19:49.757126", + "modified": "2023-10-30 12:27:18.098074", "modified_by": "Administrator", "module": "Core", "name": "DocType", From cd8c2dd21c4617f9975313c6a3d0875e7824aeaa Mon Sep 17 00:00:00 2001 From: Maharshi Patel Date: Mon, 30 Oct 2023 12:44:35 +0530 Subject: [PATCH 017/136] fix: font loading on custom website theme - added inter.scss as css import is failing in custom website theme - changed css to inter.scss for website/index.scss - inter.css is deprecated and should be removed in future - update --font-stack if custom fonts are used in website theme. - removed espresso variables from css_variables.scss as they are already imported in variables.scss --- frappe/public/css/fonts/inter/inter.css | 2 + frappe/public/css/fonts/inter/inter.scss | 164 ++++++++++++++++++ frappe/public/scss/website/css_variables.scss | 5 - frappe/public/scss/website/index.scss | 2 +- .../website_theme/website_theme_template.scss | 10 +- 5 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 frappe/public/css/fonts/inter/inter.scss diff --git a/frappe/public/css/fonts/inter/inter.css b/frappe/public/css/fonts/inter/inter.css index 88057a55b6..3be525aba0 100644 --- a/frappe/public/css/fonts/inter/inter.css +++ b/frappe/public/css/fonts/inter/inter.css @@ -1,3 +1,5 @@ +/* This file is depricated use Inter.scss instead. */ +/* Backward compatibility */ @font-face { font-family: 'Inter V'; font-weight: 100 900; diff --git a/frappe/public/css/fonts/inter/inter.scss b/frappe/public/css/fonts/inter/inter.scss new file mode 100644 index 0000000000..d3565415a3 --- /dev/null +++ b/frappe/public/css/fonts/inter/inter.scss @@ -0,0 +1,164 @@ +// TODO instead of making copy of inter.css find a way to import it. +// workaround for css import as it fails for custom website_theme_template +@font-face { + font-family: 'Inter V'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + src: url('/assets/frappe/css/fonts/inter/Inter.var.woff2?v=3.19') format('woff2-variations'), + url('/assets/frappe/css/fonts/inter/Inter.var.woff2?v=3.19') format('woff2'); + src: url('/assets/frappe/css/fonts/inter/Inter.var.woff2?v=3.19') format('woff2') tech('variations'); + } + @font-face { + font-family: 'Inter V'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + src: url('/assets/frappe/css/fonts/inter/Inter-Italic.var.woff2?v=3.19') format('woff2-variations'), + url('/assets/frappe/css/fonts/inter/Inter-Italic.var.woff2?v=3.19') format('woff2'); + src: url('/assets/frappe/css/fonts/inter/Inter-Italic.var.woff2?v=3.19') format('woff2') tech('variations'); + } +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: italic; + font-weight: 100; + src: url("/assets/frappe/css/fonts/inter/inter_thinitalic.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_thinitalic.woff") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: normal; + font-weight: 200; + src: url("/assets/frappe/css/fonts/inter/inter_extralight.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_extralight.woff") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: italic; + font-weight: 200; + src: url("/assets/frappe/css/fonts/inter/inter_extralightitalic.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_extralightitalic.woff") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: normal; + font-weight: 300; + src: url("/assets/frappe/css/fonts/inter/inter_light.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_light.woff") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: italic; + font-weight: 300; + src: url("/assets/frappe/css/fonts/inter/inter_lightitalic.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_lightitalic.woff") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: normal; + font-weight: 400; + src: url("/assets/frappe/css/fonts/inter/inter_regular.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_regular.woff") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: italic; + font-weight: 400; + src: url("/assets/frappe/css/fonts/inter/inter_italic.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_italic.woff") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: normal; + font-weight: 500; + src: url("/assets/frappe/css/fonts/inter/inter_medium.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_medium.woff") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: italic; + font-weight: 500; + src: url("/assets/frappe/css/fonts/inter/inter_mediumitalic.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_mediumitalic.woff") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: normal; + font-weight: 600; + src: url("/assets/frappe/css/fonts/inter/inter_semibold.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_semibold.woff") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: italic; + font-weight: 600; + src: url("/assets/frappe/css/fonts/inter/inter_semibolditalic.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_semibolditalic.woff") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: normal; + font-weight: 700; + src: url("/assets/frappe/css/fonts/inter/inter_bold.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_bold.woff") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: italic; + font-weight: 700; + src: url("/assets/frappe/css/fonts/inter/inter_bolditalic.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_bolditalic.woff") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: normal; + font-weight: 800; + src: url("/assets/frappe/css/fonts/inter/inter_extrabold.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_extrabold.woff") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: italic; + font-weight: 800; + src: url("/assets/frappe/css/fonts/inter/inter_extrabolditalic.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_extrabolditalic.woff") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: normal; + font-weight: 900; + src: url("/assets/frappe/css/fonts/inter/inter_black.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_black.woff") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-display: swap; + font-style: italic; + font-weight: 900; + src: url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff2") format("woff2"), + url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff") format("woff"); +} diff --git a/frappe/public/scss/website/css_variables.scss b/frappe/public/scss/website/css_variables.scss index 4618805f39..2b9be4eb8b 100644 --- a/frappe/public/scss/website/css_variables.scss +++ b/frappe/public/scss/website/css_variables.scss @@ -1,9 +1,4 @@ @import '../common/css_variables.scss'; -@import "../espresso/colors"; -@import "../espresso/spacing"; -@import "../espresso/typography"; -@import "../espresso/shadows"; -@import "../espresso/borders"; // Deprecated but remove after all use is removed as well. :root { diff --git a/frappe/public/scss/website/index.scss b/frappe/public/scss/website/index.scss index 654464c6aa..306aeed02e 100644 --- a/frappe/public/scss/website/index.scss +++ b/frappe/public/scss/website/index.scss @@ -1,5 +1,5 @@ @import 'variables'; -@import "frappe/public/css/fonts/inter/inter.css"; +@import "../../css/fonts/inter/inter.scss"; @import '../common/quill'; @import '~bootstrap/scss/bootstrap'; @import '~cropperjs/dist/cropper.min'; diff --git a/frappe/website/doctype/website_theme/website_theme_template.scss b/frappe/website/doctype/website_theme/website_theme_template.scss index bedbc2255c..1d5f8d1025 100644 --- a/frappe/website/doctype/website_theme/website_theme_template.scss +++ b/frappe/website/doctype/website_theme/website_theme_template.scss @@ -1,8 +1,16 @@ {% if google_font %} @import url("https://fonts.googleapis.com/css2?family={{ google_font.replace(' ', '+') }}:{{ font_properties }}&display=swap"); -$font-family-sans-serif: "{{ google_font }}", -apple-system, BlinkMacSystemFont, +// backward compatibility. deprecated in v15 +$font-family-sans-serif: "{{ google_font }}", "Inter V", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + +// override font stack if custom font is set in website theme +:root { + --font-stack: "{{ google_font }}", "Inter V", "Inter", -apple-system, BlinkMacSystemFont, + "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", + "Droid Sans", "Helvetica Neue", sans-serif !important; +} {% endif -%} {% if primary_color %}$primary: {{ frappe.db.get_value('Color', primary_color, 'color') }};{% endif -%} From 0e0f38b60dc325febbf72d59a202bfa4e8b9a844 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Mon, 30 Oct 2023 13:07:25 +0530 Subject: [PATCH 018/136] feat: added on_tab_change event on form to run logic on tab change --- frappe/public/js/frappe/form/form.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 32a6ec0d5e..a4f40a97c2 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -2039,6 +2039,8 @@ frappe.ui.form.Form = class FrappeForm { this.active_tab_map = {}; } this.active_tab_map[this.docname] = tab; + + this.script_manager.trigger("on_tab_change"); } get_active_tab() { return this.active_tab_map && this.active_tab_map[this.docname]; From 8ca4501f7e835fa7d646b7fea4e5ed07fed54254 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Mon, 30 Oct 2023 13:27:16 +0530 Subject: [PATCH 019/136] fix: if Form tab is active hide comments & form message --- frappe/core/doctype/doctype/doctype.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/frappe/core/doctype/doctype/doctype.js b/frappe/core/doctype/doctype/doctype.js index 929244c977..1dde8e03bd 100644 --- a/frappe/core/doctype/doctype/doctype.js +++ b/frappe/core/doctype/doctype/doctype.js @@ -119,6 +119,20 @@ frappe.ui.form.on("DocType", { setup_default_views: (frm) => { frappe.model.set_default_views_for_doctype(frm.doc.name, frm); }, + + on_tab_change: (frm) => { + let current_tab = frm.get_active_tab().label; + + if (current_tab === "Form") { + frm.footer.wrapper.hide(); + frm.form_wrapper.find(".form-message").hide(); + frm.form_wrapper.addClass("mb-1"); + } else { + frm.footer.wrapper.show(); + frm.form_wrapper.find(".form-message").show(); + frm.form_wrapper.removeClass("mb-1"); + } + }, }); frappe.ui.form.on("DocField", { From 2a04a89be1789466dc60c890e82815fae9578332 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Mon, 30 Oct 2023 13:28:58 +0530 Subject: [PATCH 020/136] fix: changed form builder layout - sidebar is on right Also remove double scrollbar --- frappe/public/js/form_builder/FormBuilder.vue | 16 ++++++++-------- .../form_builder/components/FieldProperties.vue | 2 +- .../js/form_builder/components/FieldTypes.vue | 2 +- .../public/js/form_builder/components/Tabs.vue | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/frappe/public/js/form_builder/FormBuilder.vue b/frappe/public/js/form_builder/FormBuilder.vue index 427b93584b..e5db31dda1 100644 --- a/frappe/public/js/form_builder/FormBuilder.vue +++ b/frappe/public/js/form_builder/FormBuilder.vue @@ -30,16 +30,16 @@ onMounted(() => store.fetch()); class="form-builder-container" @click="store.form.selected_field = null" > -
-
- -
-
+
+
+ +
+
@@ -62,7 +62,7 @@ onMounted(() => store.fetch()); } .form-sidebar { - border-right: 1px solid var(--border-color); + border-left: 1px solid var(--border-color); border-bottom-left-radius: var(--border-radius); } @@ -70,7 +70,7 @@ onMounted(() => store.fetch()); border-radius: var(--border-radius); border: 1px solid var(--border-color); background-color: var(--card-bg); - margin: 10px; + margin: 5px; } .form-sidebar, @@ -270,7 +270,7 @@ onMounted(() => store.fetch()); } .form-main > :deep(div:first-child:not(.tab-header)) { - max-height: calc(100vh - 160px); + max-height: calc(100vh - 178px); } } diff --git a/frappe/public/js/form_builder/components/FieldProperties.vue b/frappe/public/js/form_builder/components/FieldProperties.vue index 12a8ce79ef..cc4c9609d9 100644 --- a/frappe/public/js/form_builder/components/FieldProperties.vue +++ b/frappe/public/js/form_builder/components/FieldProperties.vue @@ -89,7 +89,7 @@ let docfield_df = computed(() => { diff --git a/frappe/public/js/form_builder/components/SearchBox.vue b/frappe/public/js/form_builder/components/SearchBox.vue index 46a2c86f67..c8a5d161f5 100644 --- a/frappe/public/js/form_builder/components/SearchBox.vue +++ b/frappe/public/js/form_builder/components/SearchBox.vue @@ -18,7 +18,7 @@ .search-box { display: flex; position: relative; - padding: 0px 9px 9px; + padding: 5px; background-color: var(--fg-color); border-bottom: 1px solid var(--border-color); @@ -28,8 +28,8 @@ .search-icon { position: absolute; - left: 16px; - top: 2px; + left: 12px; + top: 7px; } } diff --git a/frappe/public/js/form_builder/components/Sidebar.vue b/frappe/public/js/form_builder/components/Sidebar.vue index 540fbbbb34..55f178e32d 100644 --- a/frappe/public/js/form_builder/components/Sidebar.vue +++ b/frappe/public/js/form_builder/components/Sidebar.vue @@ -6,8 +6,6 @@ import { useStore } from "../store"; let store = useStore(); -let tab_titles = [__("Field Types"), __("Field Properties")]; -let active_tab = ref(tab_titles[0]); let sidebar_width = ref(272); let sidebar_resizing = ref(false); @@ -33,14 +31,6 @@ function resize(e) { sidebar_width.value = 24 * 16; } } - -watch( - () => store.form.selected_field, - value => { - active_tab.value = value ? tab_titles[1] : tab_titles[0]; - }, - { deep: true } -); @@ -81,7 +56,8 @@ watch( z-index: 4; cursor: col-resize; - &:hover, &.resizing { + &:hover, + &.resizing { opacity: 1; } } From d23483d9aa43eb56a714b46bc282f72680243689 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Mon, 30 Oct 2023 15:45:17 +0530 Subject: [PATCH 027/136] fix: revert to setting `frappe.dynamic_link` instead of using `cur_frm` --- .../js/frappe/utils/address_and_contact.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/frappe/public/js/frappe/utils/address_and_contact.js b/frappe/public/js/frappe/utils/address_and_contact.js index e81d565218..1cea4d1514 100644 --- a/frappe/public/js/frappe/utils/address_and_contact.js +++ b/frappe/public/js/frappe/utils/address_and_contact.js @@ -12,7 +12,7 @@ $.extend(frappe.contacts, { $(frm.fields_dict["address_html"].wrapper) .html(frappe.render_template("address_list", frm.doc.__onload)) .find(".btn-address") - .on("click", () => new_record("Address", frm.doctype, frm.doc.name)); + .on("click", () => new_record("Address", frm.doc)); } // render contact @@ -20,7 +20,7 @@ $.extend(frappe.contacts, { $(frm.fields_dict["contact_html"].wrapper) .html(frappe.render_template("contact_list", frm.doc.__onload)) .find(".btn-contact") - .on("click", () => new_record("Contact", frm.doctype, frm.doc.name)); + .on("click", () => new_record("Contact", frm.doc)); } }, get_last_doc: function (frm) { @@ -59,14 +59,12 @@ $.extend(frappe.contacts, { }, }); -function new_record(doctype, link_doctype, link_name) { - return frappe.new_doc(doctype).then(() => { - if (cur_frm.doc.links) { - // avoid adding the same link twice - return; - } +function new_record(doctype, source_doc) { + frappe.dynamic_link = { + doctype: source_doc.doctype, + doc: source_doc, + fieldname: "name", + }; - cur_frm.add_child("links", { link_doctype: link_doctype, link_name: link_name }); - cur_frm.refresh_field("links"); - }); + return frappe.new_doc(doctype); } From 8e7cd47d3d66d983f7d24408c855aa4187b70b5b Mon Sep 17 00:00:00 2001 From: gavin Date: Mon, 30 Oct 2023 11:40:20 +0100 Subject: [PATCH 028/136] feat: Document.remove_tag (#22970) Added remove_tag API for consistency --- frappe/model/document.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frappe/model/document.py b/frappe/model/document.py index 1b7a97cc97..4d5eec64fc 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -1584,6 +1584,12 @@ class Document(BaseDocument): DocTags(self.doctype).add(self.name, tag) + def remove_tag(self, tag): + """Remove a Tag to this document""" + from frappe.desk.doctype.tag.tag import DocTags + + DocTags(self.doctype).remove(self.name, tag) + def get_tags(self): """Return a list of Tags attached to this document""" from frappe.desk.doctype.tag.tag import DocTags From c4544e89893ec21672ab24d778e51ee75979ddfc Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Mon, 30 Oct 2023 17:20:32 +0530 Subject: [PATCH 029/136] perf: query fields only once (#22982) Signed-off-by: Akhil Narang [skip ci] --- frappe/core/doctype/doctype/doctype.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index cf5f608b4b..7d85ba17c1 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -350,8 +350,10 @@ class DocType(Document): self.flags.update_fields_to_fetch_queries = [] - if set(old_fields_to_fetch) != {df.fieldname for df in new_meta.get_fields_to_fetch()}: - for df in new_meta.get_fields_to_fetch(): + new_fields_to_fetch = [df for df in new_meta.get_fields_to_fetch()] + + if set(old_fields_to_fetch) != {df.fieldname for df in new_fields_to_fetch}: + for df in new_fields_to_fetch: if df.fieldname not in old_fields_to_fetch: link_fieldname, source_fieldname = df.fetch_from.split(".", 1) link_df = new_meta.get_field(link_fieldname) From 13537ad0f6a8c50aaafb14284e8250f6ddc3f917 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Mon, 30 Oct 2023 17:21:43 +0530 Subject: [PATCH 030/136] chore(blog_post): drop usage of `ifnull` (#22983) `published` is a `Check` (int, non-nullable) field which has a default value in the database Signed-off-by: Akhil Narang [skip ci] --- frappe/website/doctype/blog_post/blog_post.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frappe/website/doctype/blog_post/blog_post.py b/frappe/website/doctype/blog_post/blog_post.py index 75c0ebe5ae..f6a2c2f495 100644 --- a/frappe/website/doctype/blog_post/blog_post.py +++ b/frappe/website/doctype/blog_post/blog_post.py @@ -300,9 +300,8 @@ def get_blog_categories(): def clear_blog_cache(): - for blog in frappe.db.sql_list( - """select route from - `tabBlog Post` where ifnull(published,0)=1""" + for blog in frappe.db.get_list( + "Blog Post", fields=["route"], pluck="route", filters={"published": True} ): clear_cache(blog) @@ -353,7 +352,7 @@ def get_blog_list( and reference_doctype='Blog Post' and reference_name=t1.name) as comments from `tabBlog Post` t1, `tabBlogger` t2 - where ifnull(t1.published,0)=1 + where t1.published = 1 and t1.blogger = t2.name {condition} order by featured desc, published_on desc, name asc From d3225a6df9d87264288cc11009b3bd9aafc4ea1e Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 30 Oct 2023 17:26:01 +0530 Subject: [PATCH 031/136] refactor: Writing multi-pdf (#22981) - rename variables, output -> pdf_writer - write to in memory stream instead of disk [skip ci] --- frappe/utils/print_format.py | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index 4faaf97780..bd6e6d9464 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -1,4 +1,5 @@ import os +from io import BytesIO from pypdf import PdfWriter @@ -61,7 +62,7 @@ def download_multi_pdf( import json - output = PdfWriter() + pdf_writer = PdfWriter() if isinstance(options, str): options = json.loads(options) @@ -71,12 +72,12 @@ def download_multi_pdf( # Concatenating pdf files for i, ss in enumerate(result): - output = frappe.get_print( + pdf_writer = frappe.get_print( doctype, ss, format, as_pdf=True, - output=output, + output=pdf_writer, no_letterhead=no_letterhead, letterhead=letterhead, pdf_options=options, @@ -88,12 +89,12 @@ def download_multi_pdf( for doctype_name in doctype: for doc_name in doctype[doctype_name]: try: - output = frappe.get_print( + pdf_writer = frappe.get_print( doctype_name, doc_name, format, as_pdf=True, - output=output, + output=pdf_writer, no_letterhead=no_letterhead, letterhead=letterhead, pdf_options=options, @@ -107,21 +108,13 @@ def download_multi_pdf( ) frappe.local.response.filename = f"{name}.pdf" - frappe.local.response.filecontent = read_multi_pdf(output) + with BytesIO() as merged_pdf: + pdf_writer.write(merged_pdf) + frappe.local.response.filecontent = merged_pdf.getvalue() + frappe.local.response.type = "pdf" -def read_multi_pdf(output): - # Get the content of the merged pdf files - fname = os.path.join("/tmp", f"frappe-pdf-{frappe.generate_hash()}.pdf") - output.write(open(fname, "wb")) - - with open(fname, "rb") as fileobj: - filedata = fileobj.read() - - return filedata - - @frappe.whitelist(allow_guest=True) def download_pdf( doctype, name, format=None, doc=None, no_letterhead=0, language=None, letterhead=None From daca4dd31c42ac203cca666d1d4239d6d1de4db3 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 30 Oct 2023 17:31:25 +0530 Subject: [PATCH 032/136] chore: keep deprecated function slated for removal in future This is used in ERPNext. --- frappe/utils/print_format.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index bd6e6d9464..7ab0c24a7c 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -7,6 +7,7 @@ import frappe from frappe import _ from frappe.core.doctype.access_log.access_log import make_access_log from frappe.translate import print_language +from frappe.utils.deprecations import deprecated from frappe.utils.pdf import get_pdf no_cache = 1 @@ -115,6 +116,13 @@ def download_multi_pdf( frappe.local.response.type = "pdf" +@deprecated +def read_multi_pdf(output: PdfWriter) -> bytes: + with BytesIO() as merged_pdf: + output.write(merged_pdf) + return merged_pdf.getvalue() + + @frappe.whitelist(allow_guest=True) def download_pdf( doctype, name, format=None, doc=None, no_letterhead=0, language=None, letterhead=None From afc3babbf92c51b5d15a86ce6567209d2b6cceab Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Mon, 30 Oct 2023 17:43:06 +0530 Subject: [PATCH 033/136] refactor: remove/add tab --- .../components/FieldProperties.vue | 29 +++--- .../js/form_builder/components/SearchBox.vue | 9 +- .../js/form_builder/components/Sidebar.vue | 36 ++++++- .../js/form_builder/components/Tabs.vue | 97 ++++++++++--------- frappe/public/js/form_builder/store.js | 34 ++++++- 5 files changed, 138 insertions(+), 67 deletions(-) diff --git a/frappe/public/js/form_builder/components/FieldProperties.vue b/frappe/public/js/form_builder/components/FieldProperties.vue index 3bd20ff192..af32a53193 100644 --- a/frappe/public/js/form_builder/components/FieldProperties.vue +++ b/frappe/public/js/form_builder/components/FieldProperties.vue @@ -68,7 +68,16 @@ let docfield_df = computed(() => { diff --git a/frappe/public/js/form_builder/components/SearchBox.vue b/frappe/public/js/form_builder/components/SearchBox.vue index c8a5d161f5..bae326058d 100644 --- a/frappe/public/js/form_builder/components/SearchBox.vue +++ b/frappe/public/js/form_builder/components/SearchBox.vue @@ -5,7 +5,7 @@ @@ -18,9 +18,8 @@ .search-box { display: flex; position: relative; - padding: 5px; background-color: var(--fg-color); - border-bottom: 1px solid var(--border-color); + width: 100%; .search-input { padding-left: 30px; @@ -28,8 +27,8 @@ .search-icon { position: absolute; - left: 12px; - top: 7px; + left: 7px; + top: 2px; } } diff --git a/frappe/public/js/form_builder/components/Sidebar.vue b/frappe/public/js/form_builder/components/Sidebar.vue index 55f178e32d..67fd084950 100644 --- a/frappe/public/js/form_builder/components/Sidebar.vue +++ b/frappe/public/js/form_builder/components/Sidebar.vue @@ -39,7 +39,21 @@ function resize(e) { @mousedown="start_resize" /> @@ -61,6 +75,7 @@ function resize(e) { opacity: 1; } } + .tab-header { display: flex; justify-content: space-between; @@ -104,4 +119,23 @@ function resize(e) { display: block; } } + +.default-state { + height: calc(100vh - 196px); + + .actions { + padding: 5px; + display: flex; + justify-content: flex-end; + border-bottom: 1px solid var(--border-color); + } + .empty-state { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + text-align: center; + color: var(--disabled-text-color); + } +} diff --git a/frappe/public/js/form_builder/components/Tabs.vue b/frappe/public/js/form_builder/components/Tabs.vue index 88a159d8e6..ca0b8b9bb6 100644 --- a/frappe/public/js/form_builder/components/Tabs.vue +++ b/frappe/public/js/form_builder/components/Tabs.vue @@ -13,17 +13,7 @@ let has_tabs = computed(() => store.form.layout.tabs.length > 1); store.form.active_tab = store.form.layout.tabs[0].df.name; function activate_tab(tab) { - store.form.active_tab = tab.df.name; - store.form.selected_field = tab.df; - - // scroll to active tab - nextTick(() => { - $(".tabs .tab.active")[0].scrollIntoView({ - behavior: "smooth", - inline: "center", - block: "nearest", - }); - }); + store.activate_tab(tab); } function drag_over(tab) { @@ -34,13 +24,7 @@ function drag_over(tab) { } function add_new_tab() { - let tab = { - df: store.get_df("Tab Break", "", "Tab " + (store.form.layout.tabs.length + 1)), - sections: [section_boilerplate()], - }; - - store.form.layout.tabs.push(tab); - activate_tab(tab); + store.add_new_tab(); } function add_new_section() { @@ -51,8 +35,8 @@ function add_new_section() { function is_current_tab_empty() { // check if sections have columns and it contains fields - return !store.current_tab.sections.some( - section => section.columns.some(column => column.fields.length) + return !store.current_tab.sections.some((section) => + section.columns.some((column) => column.fields.length) ); } @@ -67,7 +51,11 @@ function remove_tab() { } else { confirm_dialog( __("Delete Tab", null, "Title of confirmation dialog"), - __("Are you sure you want to delete the tab? All the sections along with fields in the tab will be moved to the previous tab.", null, "Confirmation dialog message"), + __( + "Are you sure you want to delete the tab? All the sections along with fields in the tab will be moved to the previous tab.", + null, + "Confirmation dialog message" + ), () => delete_tab(), __("Delete tab", null, "Button text"), () => delete_tab(true), @@ -109,7 +97,7 @@ function delete_tab(with_children) {