From b8fbed0f667af953c5ead931e444416d751bdaed Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sun, 11 Jul 2021 17:19:34 +0530 Subject: [PATCH 001/108] feat: New Print Format Builder - Print Format Builder Beta page - Add margin fields in Print Format - Using vuedraggable for drag and drop --- .../doctype/print_format/print_format.json | 39 +++- .../doctype/print_format/print_format.py | 4 + frappe/printing/page/print/print.js | 6 + .../print_format_builder.js | 18 +- .../print_format_builder.py | 9 +- .../print_format_builder_beta/__init__.py | 0 .../print_format_builder_beta.css | 3 + .../print_format_builder_beta.js | 31 +++ .../print_format_builder_beta.json | 22 ++ .../js/print_format_builder/PrintFormat.vue | 73 +++++++ .../PrintFormatBuilder.vue | 110 ++++++++++ .../PrintFormatControls.vue | 163 ++++++++++++++ .../PrintFormatSection.vue | 203 ++++++++++++++++++ .../print_format_builder.bundle.js | 31 +++ .../public/js/print_format_builder/utils.js | 100 +++++++++ package.json | 3 +- yarn.lock | 12 ++ 17 files changed, 815 insertions(+), 12 deletions(-) create mode 100644 frappe/printing/page/print_format_builder_beta/__init__.py create mode 100644 frappe/printing/page/print_format_builder_beta/print_format_builder_beta.css create mode 100644 frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js create mode 100644 frappe/printing/page/print_format_builder_beta/print_format_builder_beta.json create mode 100644 frappe/public/js/print_format_builder/PrintFormat.vue create mode 100644 frappe/public/js/print_format_builder/PrintFormatBuilder.vue create mode 100644 frappe/public/js/print_format_builder/PrintFormatControls.vue create mode 100644 frappe/public/js/print_format_builder/PrintFormatSection.vue create mode 100644 frappe/public/js/print_format_builder/print_format_builder.bundle.js create mode 100644 frappe/public/js/print_format_builder/utils.js diff --git a/frappe/printing/doctype/print_format/print_format.json b/frappe/printing/doctype/print_format/print_format.json index 4032cef209..52220ed67c 100644 --- a/frappe/printing/doctype/print_format/print_format.json +++ b/frappe/printing/doctype/print_format/print_format.json @@ -19,6 +19,10 @@ "html", "raw_commands", "section_break_9", + "margin_top", + "margin_bottom", + "margin_left", + "margin_right", "align_labels_right", "show_section_headings", "line_breaks", @@ -31,7 +35,8 @@ "section_break_13", "print_format_help", "format_data", - "print_format_builder" + "print_format_builder", + "print_format_builder_beta" ], "fields": [ { @@ -205,13 +210,43 @@ "fieldname": "absolute_value", "fieldtype": "Check", "label": "Show Absolute Values" + }, + { + "default": "0", + "fieldname": "print_format_builder_beta", + "fieldtype": "Check", + "label": "Print Format Builder Beta" + }, + { + "default": "15", + "fieldname": "margin_top", + "fieldtype": "Float", + "label": "Margin Top" + }, + { + "default": "15", + "fieldname": "margin_bottom", + "fieldtype": "Float", + "label": "Margin Bottom" + }, + { + "default": "15", + "fieldname": "margin_left", + "fieldtype": "Float", + "label": "Margin Left" + }, + { + "default": "15", + "fieldname": "margin_right", + "fieldtype": "Float", + "label": "Margin Right" } ], "icon": "fa fa-print", "idx": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2021-03-01 15:25:46.578863", + "modified": "2021-07-11 11:53:52.028982", "modified_by": "Administrator", "module": "Printing", "name": "Print Format", diff --git a/frappe/printing/doctype/print_format/print_format.py b/frappe/printing/doctype/print_format/print_format.py index 878a864b38..2049c4105c 100644 --- a/frappe/printing/doctype/print_format/print_format.py +++ b/frappe/printing/doctype/print_format/print_format.py @@ -38,6 +38,10 @@ class PrintFormat(Document): def extract_images(self): from frappe.core.doctype.file.file import extract_images_from_html + + if self.print_format_builder_beta: + return + if self.format_data: data = json.loads(self.format_data) for df in data: diff --git a/frappe/printing/page/print/print.js b/frappe/printing/page/print/print.js index ca2a340661..225c06980e 100644 --- a/frappe/printing/page/print/print.js +++ b/frappe/printing/page/print/print.js @@ -258,6 +258,11 @@ frappe.ui.form.PrintView = class { fieldtype: 'Read Only', default: print_format.name || 'Standard', }, + { + label: __('Use the new Print Format Builder Beta'), + fieldname: 'beta', + fieldtype: 'Check' + }, ], (data) => { frappe.route_options = { @@ -265,6 +270,7 @@ frappe.ui.form.PrintView = class { doctype: this.frm.doctype, name: data.print_format_name, based_on: data.based_on, + beta: data.beta }; frappe.set_route('print-format-builder'); this.print_sel.val(data.print_format_name); diff --git a/frappe/printing/page/print_format_builder/print_format_builder.js b/frappe/printing/page/print_format_builder/print_format_builder.js index ca2a8bc378..e2d00bd53d 100644 --- a/frappe/printing/page/print_format_builder/print_format_builder.js +++ b/frappe/printing/page/print_format_builder/print_format_builder.js @@ -12,9 +12,9 @@ frappe.pages['print-format-builder'].on_page_show = function(wrapper) { }); } else if(frappe.route_options) { if(frappe.route_options.make_new) { - let { doctype, name, based_on } = frappe.route_options; + let { doctype, name, based_on, beta } = frappe.route_options; frappe.route_options = null; - frappe.print_format_builder.setup_new_print_format(doctype, name, based_on); + frappe.print_format_builder.setup_new_print_format(doctype, name, based_on, beta); } else { frappe.print_format_builder.print_format = frappe.route_options.doc; frappe.route_options = null; @@ -126,18 +126,22 @@ frappe.PrintFormatBuilder = class PrintFormatBuilder { }); } - setup_new_print_format(doctype, name, based_on) { + setup_new_print_format(doctype, name, based_on, beta) { frappe.call({ method: 'frappe.printing.page.print_format_builder.print_format_builder.create_custom_format', args: { doctype: doctype, name: name, - based_on: based_on + based_on: based_on, + beta: Boolean(beta) }, callback: (r) => { - if(!r.exc) { - if(r.message) { - this.print_format = r.message; + if(r.message) { + let print_format = r.message; + if (print_format.print_format_builder_beta) { + frappe.set_route('print-format-builder-beta', print_format.name); + } else { + this.print_format = print_format; this.refresh(); } } diff --git a/frappe/printing/page/print_format_builder/print_format_builder.py b/frappe/printing/page/print_format_builder/print_format_builder.py index d9f57762b0..fae564d3c3 100644 --- a/frappe/printing/page/print_format_builder/print_format_builder.py +++ b/frappe/printing/page/print_format_builder/print_format_builder.py @@ -1,11 +1,16 @@ import frappe @frappe.whitelist() -def create_custom_format(doctype, name, based_on='Standard'): +def create_custom_format(doctype, name, based_on='Standard', beta=False): doc = frappe.new_doc('Print Format') doc.doc_type = doctype doc.name = name - doc.print_format_builder = 1 + beta = frappe.parse_json(beta) + + if beta: + doc.print_format_builder_beta = 1 + else: + doc.print_format_builder = 1 doc.format_data = frappe.db.get_value('Print Format', based_on, 'format_data') \ if based_on != 'Standard' else None doc.insert() diff --git a/frappe/printing/page/print_format_builder_beta/__init__.py b/frappe/printing/page/print_format_builder_beta/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.css b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.css new file mode 100644 index 0000000000..0bd8d9c0f3 --- /dev/null +++ b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.css @@ -0,0 +1,3 @@ +.layout-main-section-wrapper { + margin-bottom: 0; +} diff --git a/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js new file mode 100644 index 0000000000..9004dd8b98 --- /dev/null +++ b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js @@ -0,0 +1,31 @@ +frappe.pages["print-format-builder-beta"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: __("Print Format Builder"), + single_column: true + }); + + function load_print_format_builder_beta() { + let route = frappe.get_route(); + let $parent = $(wrapper).find(".layout-main-section"); + $parent.empty(); + + if (route.length > 1) { + frappe.require("print_format_builder.bundle.js").then(() => { + frappe.print_format_builder = new frappe.ui.PrintFormatBuilder({ + wrapper: $parent, + page, + print_format: route[1] + }); + }); + } + } + + load_print_format_builder_beta(); + + // hot reload in development + if (frappe.boot.developer_mode) { + frappe.hot_update = frappe.hot_update || []; + frappe.hot_update.push(load_print_format_builder_beta); + } +}; diff --git a/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.json b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.json new file mode 100644 index 0000000000..a5b1288bc0 --- /dev/null +++ b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.json @@ -0,0 +1,22 @@ +{ + "content": null, + "creation": "2021-07-10 12:22:16.138485", + "docstatus": 0, + "doctype": "Page", + "idx": 0, + "modified": "2021-07-10 12:22:16.138485", + "modified_by": "Administrator", + "module": "Printing", + "name": "print-format-builder-beta", + "owner": "Administrator", + "page_name": "Print Format Builder Beta", + "roles": [ + { + "role": "System Manager" + } + ], + "script": null, + "standard": "Yes", + "style": null, + "system_page": 0 +} \ No newline at end of file diff --git a/frappe/public/js/print_format_builder/PrintFormat.vue b/frappe/public/js/print_format_builder/PrintFormat.vue new file mode 100644 index 0000000000..9e8e2033a4 --- /dev/null +++ b/frappe/public/js/print_format_builder/PrintFormat.vue @@ -0,0 +1,73 @@ + + + + + \ No newline at end of file diff --git a/frappe/public/js/print_format_builder/PrintFormatBuilder.vue b/frappe/public/js/print_format_builder/PrintFormatBuilder.vue new file mode 100644 index 0000000000..88b70f8b1b --- /dev/null +++ b/frappe/public/js/print_format_builder/PrintFormatBuilder.vue @@ -0,0 +1,110 @@ + + + + + \ No newline at end of file diff --git a/frappe/public/js/print_format_builder/PrintFormatControls.vue b/frappe/public/js/print_format_builder/PrintFormatControls.vue new file mode 100644 index 0000000000..b4f452751a --- /dev/null +++ b/frappe/public/js/print_format_builder/PrintFormatControls.vue @@ -0,0 +1,163 @@ + + + + + \ No newline at end of file diff --git a/frappe/public/js/print_format_builder/PrintFormatSection.vue b/frappe/public/js/print_format_builder/PrintFormatSection.vue new file mode 100644 index 0000000000..e204c2053f --- /dev/null +++ b/frappe/public/js/print_format_builder/PrintFormatSection.vue @@ -0,0 +1,203 @@ + + + + + \ No newline at end of file diff --git a/frappe/public/js/print_format_builder/print_format_builder.bundle.js b/frappe/public/js/print_format_builder/print_format_builder.bundle.js new file mode 100644 index 0000000000..e364bfa29e --- /dev/null +++ b/frappe/public/js/print_format_builder/print_format_builder.bundle.js @@ -0,0 +1,31 @@ +import PrintFormatBuilderComponent from "./PrintFormatBuilder.vue"; + +class PrintFormatBuilder { + constructor({ wrapper, page, print_format }) { + this.$wrapper = $(wrapper); + this.page = page; + this.print_format = print_format; + this.page.set_title(__("Editing {0}", [this.print_format])); + this.page.set_primary_action(__("Save changes"), () => { + this.$component.save_changes(); + }); + this.page.set_secondary_action(__("Reset changes"), () => { + this.$component.reset_changes(); + }); + + let $vm = new Vue({ + el: this.$wrapper.get(0), + render: h => + h(PrintFormatBuilderComponent, { + props: { + print_format_name: print_format + } + }) + }); + this.$component = $vm.$children[0]; + } +} + +frappe.provide("frappe.ui"); +frappe.ui.PrintFormatBuilder = PrintFormatBuilder; +export default PrintFormatBuilder; diff --git a/frappe/public/js/print_format_builder/utils.js b/frappe/public/js/print_format_builder/utils.js new file mode 100644 index 0000000000..9428ca61f9 --- /dev/null +++ b/frappe/public/js/print_format_builder/utils.js @@ -0,0 +1,100 @@ +export function create_default_layout(meta) { + let layout = { + sections: [] + }; + + let section = null, + column = null; + + function set_column(df) { + if (!section) { + set_section(); + } + column = get_new_column(df); + section.columns.push(column); + } + + function set_section(df) { + section = get_new_section(df); + column = null; + layout.sections.push(section); + } + + function get_new_section(df) { + if (!df) { + df = { label: "" }; + } + return { + label: df.label || "", + columns: [] + }; + } + + function get_new_column(df) { + if (!df) { + df = { label: "" }; + } + return { + label: df.label || "", + fields: [] + }; + } + + for (let df of meta.fields) { + if (df.fieldname) { + // make a copy to avoid mutation bugs + df = JSON.parse(JSON.stringify(df)); + } else { + continue; + } + + if (df.fieldtype === "Section Break") { + set_section(df); + } else if (df.fieldtype === "Column Break") { + set_column(df); + } else if (df.label) { + if (!column) set_column(); + + if (!df.print_hide) { + let field = { + label: df.label, + fieldname: df.fieldname, + options: df.options + }; + + if (df.fieldtype === "Table") { + field.table_columns = get_table_columns(df); + } + + column.fields.push(field); + section.has_fields = true; + } + } + } + + // remove empty sections + layout.sections = layout.sections.filter(section => section.has_fields); + + return layout; +} + +export function get_table_columns(df) { + let table_columns = []; + let table_fields = frappe.get_meta(df.options).fields; + + for (let tf of table_fields) { + if ( + !in_list(["Section Break", "Column Break"], tf.fieldtype) && + !tf.print_hide && + df.label + ) { + table_columns.push({ + label: tf.label, + fieldname: tf.fieldname, + options: tf.options, + width: tf.width || 0 + }); + } + } + return table_columns; +} diff --git a/package.json b/package.json index 2283a44533..82a335c2ba 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,8 @@ "superagent": "^3.8.2", "touch": "^3.1.0", "vue": "2.6.12", - "vue-router": "^2.0.0" + "vue-router": "^2.0.0", + "vuedraggable": "^2.24.3" }, "devDependencies": { "chalk": "^2.3.2", diff --git a/yarn.lock b/yarn.lock index ee530d747b..cdabdb6565 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6911,6 +6911,11 @@ socket.io@^2.4.0: socket.io-client "2.4.0" socket.io-parser "~3.4.0" +sortablejs@1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.10.2.tgz#6e40364d913f98b85a14f6678f92b5c1221f5290" + integrity sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A== + sortablejs@^1.7.0: version "1.8.3" resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.8.3.tgz#5ae908ef96300966e95440a143340f5dd565a0df" @@ -7790,6 +7795,13 @@ vue@2.6.12: resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123" integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg== +vuedraggable@^2.24.3: + version "2.24.3" + resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19" + integrity sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g== + dependencies: + sortablejs "1.10.2" + wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" From f58254db7870d0d95f85636a3b81508c4ee37e09 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sun, 11 Jul 2021 17:21:06 +0530 Subject: [PATCH 002/108] fix: poor man's hot reload --- esbuild/esbuild.js | 41 ++++++++++--------- .../build_events/build_events.bundle.js | 28 +++++++++++++ frappe/sessions.py | 4 ++ 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/esbuild/esbuild.js b/esbuild/esbuild.js index 9074beae06..442846c73f 100644 --- a/esbuild/esbuild.js +++ b/esbuild/esbuild.js @@ -280,10 +280,24 @@ function get_watch_config() { assets_json, prev_assets_json } = await write_assets_json(result.metafile); + + let changed_files; if (prev_assets_json) { - log_rebuilt_assets(prev_assets_json, assets_json); + changed_files = get_rebuilt_assets( + prev_assets_json, + assets_json + ); + + let timestamp = new Date().toLocaleTimeString(); + let message = `${timestamp}: Compiled ${changed_files.length} files...`; + log(chalk.yellow(message)); + for (let filepath of changed_files) { + let filename = path.basename(filepath); + log(" " + filename); + } + log(); } - notify_redis({ success: true }); + notify_redis({ success: true, changed_files }); } } }; @@ -453,7 +467,7 @@ function run_build_command_for_apps(apps) { process.chdir(cwd); } -async function notify_redis({ error, success }) { +async function notify_redis({ error, success, changed_files }) { // notify redis which in turns tells socketio to publish this to browser let subscriber = get_redis_subscriber("redis_socketio"); subscriber.on("error", _ => { @@ -475,7 +489,8 @@ async function notify_redis({ error, success }) { } if (success) { payload = { - success: true + success: true, + changed_files }; } @@ -505,7 +520,7 @@ function open_in_editor() { subscriber.subscribe("open_in_editor"); } -function log_rebuilt_assets(prev_assets, new_assets) { +function get_rebuilt_assets(prev_assets, new_assets) { let added_files = []; let old_files = Object.values(prev_assets); let new_files = Object.values(new_assets); @@ -515,17 +530,5 @@ function log_rebuilt_assets(prev_assets, new_assets) { added_files.push(filepath); } } - - log( - chalk.yellow( - `${new Date().toLocaleTimeString()}: Compiled ${ - added_files.length - } files...` - ) - ); - for (let filepath of added_files) { - let filename = path.basename(filepath); - log(" " + filename); - } - log(); -} \ No newline at end of file + return added_files; +} diff --git a/frappe/public/js/frappe/build_events/build_events.bundle.js b/frappe/public/js/frappe/build_events/build_events.bundle.js index 6c8986af3f..6180ccbd66 100644 --- a/frappe/public/js/frappe/build_events/build_events.bundle.js +++ b/frappe/public/js/frappe/build_events/build_events.bundle.js @@ -7,6 +7,34 @@ let error = null; frappe.realtime.on("build_event", data => { if (data.success) { + // remove executed cache for rebuilt files + let changed_files = data.changed_files; + if (Array.isArray(changed_files)) { + for (let file of changed_files) { + if (file.includes(".bundle.")) { + let parts = file.split(".bundle."); + if (parts.length === 2) { + let filename = parts[0].split("/").slice(-1)[0]; + + frappe.assets.executed_ = frappe.assets.executed_.filter( + asset => !asset.includes(`${filename}.bundle`) + ); + } + } + } + } + // update assets json + frappe.call("frappe.sessions.get_boot_assets_json").then(r => { + if (r.message) { + frappe.boot.assets_json = r.message; + + if (frappe.hot_update) { + frappe.hot_update.forEach(callback => { + callback(); + }); + } + } + }); show_build_success(data); } else if (data.error) { show_build_error(data); diff --git a/frappe/sessions.py b/frappe/sessions.py index ce104968ad..8a8355ec75 100644 --- a/frappe/sessions.py +++ b/frappe/sessions.py @@ -159,6 +159,10 @@ def get(): return bootinfo +@frappe.whitelist() +def get_boot_assets_json(): + return get_assets_json() + def get_csrf_token(): if not frappe.local.session.data.csrf_token: generate_csrf_token() From f536a1ff91db91397ff09d2e996014c09ff80aba Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sun, 15 Aug 2021 16:10:04 +0530 Subject: [PATCH 003/108] fix: More features - Show selection dialog if Print Format not selected - Field component - Common store - Edit Field label inline - Configure table columns - Edit Custom HTML - Preview --- .../print_format_builder_beta.js | 20 + .../print_format_builder/ConfigureColumns.vue | 86 +++++ .../public/js/print_format_builder/Field.vue | 345 ++++++++++++++++++ .../js/print_format_builder/PrintFormat.vue | 21 +- .../PrintFormatBuilder.vue | 94 +---- .../PrintFormatControls.vue | 61 +++- .../PrintFormatSection.vue | 62 +--- .../print_format_builder.bundle.js | 55 ++- .../public/js/print_format_builder/store.js | 125 +++++++ .../public/js/print_format_builder/utils.js | 22 +- 10 files changed, 732 insertions(+), 159 deletions(-) create mode 100644 frappe/public/js/print_format_builder/ConfigureColumns.vue create mode 100644 frappe/public/js/print_format_builder/Field.vue create mode 100644 frappe/public/js/print_format_builder/store.js diff --git a/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js index 9004dd8b98..b40e8c6f97 100644 --- a/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js +++ b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js @@ -18,6 +18,26 @@ frappe.pages["print-format-builder-beta"].on_page_load = function(wrapper) { print_format: route[1] }); }); + } else { + let d = new frappe.ui.Dialog({ + title: __("Select Print Format to edit"), + fields: [ + { + label: __("Print Format"), + fieldname: "print_format", + fieldtype: "Link", + options: "Print Format", + filters: { + print_format_builder_beta: 1 + } + } + ], + primary_action({ print_format }) { + if (!print_format) return; + frappe.set_route("print-format-builder-beta", print_format); + } + }); + d.show(); } } diff --git a/frappe/public/js/print_format_builder/ConfigureColumns.vue b/frappe/public/js/print_format_builder/ConfigureColumns.vue new file mode 100644 index 0000000000..8966595216 --- /dev/null +++ b/frappe/public/js/print_format_builder/ConfigureColumns.vue @@ -0,0 +1,86 @@ + + + diff --git a/frappe/public/js/print_format_builder/Field.vue b/frappe/public/js/print_format_builder/Field.vue new file mode 100644 index 0000000000..d82015f51c --- /dev/null +++ b/frappe/public/js/print_format_builder/Field.vue @@ -0,0 +1,345 @@ + + + diff --git a/frappe/public/js/print_format_builder/PrintFormat.vue b/frappe/public/js/print_format_builder/PrintFormat.vue index 9e8e2033a4..d10eb88a6f 100644 --- a/frappe/public/js/print_format_builder/PrintFormat.vue +++ b/frappe/public/js/print_format_builder/PrintFormat.vue @@ -19,13 +19,14 @@ @@ -70,4 +71,4 @@ export default { box-shadow: var(--shadow-lg); border-radius: var(--border-radius); } - \ No newline at end of file + diff --git a/frappe/public/js/print_format_builder/PrintFormatBuilder.vue b/frappe/public/js/print_format_builder/PrintFormatBuilder.vue index 88b70f8b1b..78205406e3 100644 --- a/frappe/public/js/print_format_builder/PrintFormatBuilder.vue +++ b/frappe/public/js/print_format_builder/PrintFormatBuilder.vue @@ -1,14 +1,10 @@ @@ -16,87 +12,33 @@ @@ -107,4 +49,4 @@ export default { padding-top: 0.5rem; padding-bottom: 4rem; } - \ No newline at end of file + diff --git a/frappe/public/js/print_format_builder/PrintFormatControls.vue b/frappe/public/js/print_format_builder/PrintFormatControls.vue index b4f452751a..dd54f8f55e 100644 --- a/frappe/public/js/print_format_builder/PrintFormatControls.vue +++ b/frappe/public/js/print_format_builder/PrintFormatControls.vue @@ -14,7 +14,7 @@ type="number" class="form-control form-control-sm" :value="print_format[df.fieldname]" - @change="(e) => update_margin(df.fieldname, e.target.value)" + @change="e => update_margin(df.fieldname, e.target.value)" /> @@ -24,7 +24,7 @@ @@ -74,19 +62,23 @@ @@ -166,38 +158,8 @@ export default { padding-right: 8px; } -.field { - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; - background-color: var(--bg-light-gray); - border-radius: var(--border-radius); - border: 1px dashed var(--gray-400); - padding: 0.5rem 0.75rem; - font-size: var(--text-sm); -} - -.field:not(:first-child) { - margin-top: 0.5rem; -} - -.btn-remove-field { - opacity: 0; - padding: 2px; - box-shadow: none; -} - -.btn-remove-field:hover { - background-color: white; -} - -.field:hover .btn-remove-field { - opacity: 1; -} - .drag-container { height: 100%; min-height: 2rem; } - \ No newline at end of file + diff --git a/frappe/public/js/print_format_builder/print_format_builder.bundle.js b/frappe/public/js/print_format_builder/print_format_builder.bundle.js index e364bfa29e..63cc098380 100644 --- a/frappe/public/js/print_format_builder/print_format_builder.bundle.js +++ b/frappe/public/js/print_format_builder/print_format_builder.bundle.js @@ -5,13 +5,24 @@ class PrintFormatBuilder { this.$wrapper = $(wrapper); this.page = page; this.print_format = print_format; + + this.page.clear_actions() + this.page.clear_custom_actions() + this.page.set_title(__("Editing {0}", [this.print_format])); this.page.set_primary_action(__("Save changes"), () => { - this.$component.save_changes(); + this.$component.$store.save_changes(); }); this.page.set_secondary_action(__("Reset changes"), () => { - this.$component.reset_changes(); + this.$component.$store.reset_changes(); }); + this.page.add_button( + __("Preview"), + () => { + this.preview(); + }, + { icon: "small-file" } + ); let $vm = new Vue({ el: this.$wrapper.get(0), @@ -24,6 +35,46 @@ class PrintFormatBuilder { }); this.$component = $vm.$children[0]; } + + async preview() { + let doctype = this.$component.$store.print_format.doc_type; + let default_doc = await frappe.db.get_list(doctype, { + limit: 1 + }); + + let d = new frappe.ui.Dialog({ + title: __("Preview Print Format"), + fields: [ + { + label: __("Type"), + fieldname: "type", + fieldtype: "Select", + options: ["PDF", "HTML"], + default: "PDF" + }, + { + label: __("Select Document"), + fieldname: "docname", + fieldtype: "Link", + options: doctype, + reqd: 1, + default: default_doc.length > 0 ? default_doc[0].name : null + } + ], + primary_action: ({ docname, type }) => { + let params = new URLSearchParams(); + params.append("doctype", doctype); + params.append("name", docname); + params.append("print_format", this.print_format); + let url = + type == "PDF" + ? `/api/method/frappe.utils.weasyprint.download_pdf` + : "/printpreview"; + window.open(`${url}?${params.toString()}`, "_blank"); + } + }); + d.show(); + } } frappe.provide("frappe.ui"); diff --git a/frappe/public/js/print_format_builder/store.js b/frappe/public/js/print_format_builder/store.js new file mode 100644 index 0000000000..3af4a21dec --- /dev/null +++ b/frappe/public/js/print_format_builder/store.js @@ -0,0 +1,125 @@ +import { create_default_layout, pluck } from "./utils"; + +let stores = {}; + +export function getStore(print_format_name) { + if (stores[print_format_name]) { + return stores[print_format_name]; + } + + let options = { + data() { + return { + print_format_name, + print_format: null, + doctype: null, + meta: null, + layout: null + }; + }, + methods: { + fetch() { + frappe.model.clear_doc("Print Format", this.print_format_name); + frappe.model.with_doc( + "Print Format", + this.print_format_name, + () => { + this.print_format = frappe.get_doc( + "Print Format", + this.print_format_name + ); + frappe.model.with_doctype( + this.print_format.doc_type, + () => { + this.meta = frappe.get_meta( + this.print_format.doc_type + ); + this.layout = this.get_layout(); + } + ); + } + ); + }, + update({ fieldname, value }) { + this.$set(this.print_format, fieldname, value); + }, + save_changes() { + frappe.dom.freeze(__("Saving...")); + + this.layout.sections = this.layout.sections + .filter(section => !section.remove) + .map(section => { + section.columns = section.columns.map(column => { + column.fields = column.fields + .filter(df => !df.remove) + .map(df => { + if (df.table_columns) { + df.table_columns = df.table_columns.map( + tf => { + return pluck(tf, [ + "label", + "fieldname", + "fieldtype", + "options", + "width" + ]); + } + ); + } + return pluck(df, [ + "label", + "fieldname", + "fieldtype", + "options", + "table_columns" + ]); + }); + return column; + }); + return section; + }); + + this.print_format.format_data = JSON.stringify(this.layout); + + frappe + .call("frappe.client.save", { + doc: this.print_format + }) + .then(() => this.fetch()) + .always(() => frappe.dom.unfreeze()); + }, + reset_changes() { + this.fetch(); + }, + get_layout() { + if (this.print_format) { + if (!this.print_format.format_data) { + return create_default_layout(this.meta); + } + if (typeof this.print_format.format_data == "string") { + return JSON.parse(this.print_format.format_data); + } + return this.print_format.format_data; + } + return null; + } + } + }; + stores[print_format_name] = new Vue(options); + return stores[print_format_name]; +} + +export let storeMixin = { + inject: ["$store"], + computed: { + print_format() { + return this.$store.print_format; + }, + layout() { + return this.$store.layout; + }, + meta() { + return this.$store.meta; + } + } +}; diff --git a/frappe/public/js/print_format_builder/utils.js b/frappe/public/js/print_format_builder/utils.js index 9428ca61f9..7bdd78a04a 100644 --- a/frappe/public/js/print_format_builder/utils.js +++ b/frappe/public/js/print_format_builder/utils.js @@ -59,6 +59,7 @@ export function create_default_layout(meta) { let field = { label: df.label, fieldname: df.fieldname, + fieldtype: df.fieldtype, options: df.options }; @@ -81,20 +82,35 @@ export function create_default_layout(meta) { export function get_table_columns(df) { let table_columns = []; let table_fields = frappe.get_meta(df.options).fields; - + let total_columns = 0; for (let tf of table_fields) { if ( !in_list(["Section Break", "Column Break"], tf.fieldtype) && !tf.print_hide && - df.label + df.label && + total_columns < 12 ) { + let columns = + typeof tf.width == "number" && tf.width < 12 ? tf.width : 2; table_columns.push({ label: tf.label, fieldname: tf.fieldname, + fieldtype: tf.fieldtype, options: tf.options, - width: tf.width || 0 + width: columns }); + total_columns += columns; } } return table_columns; } + +export function pluck(object, keys) { + let out = {}; + for (let key of keys) { + if (key in object) { + out[key] = object[key]; + } + } + return out; +} From a25817b64ce9d3d2434f2057899ce68fffb26037 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 21 Aug 2021 18:03:36 +0530 Subject: [PATCH 004/108] fix: Set table column width in percentages --- .../print_format_builder/ConfigureColumns.vue | 45 ++++++++++++++----- .../public/js/print_format_builder/Field.vue | 20 +++++---- .../public/js/print_format_builder/utils.js | 16 ++++--- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/frappe/public/js/print_format_builder/ConfigureColumns.vue b/frappe/public/js/print_format_builder/ConfigureColumns.vue index 8966595216..da10f99e40 100644 --- a/frappe/public/js/print_format_builder/ConfigureColumns.vue +++ b/frappe/public/js/print_format_builder/ConfigureColumns.vue @@ -1,6 +1,6 @@ + diff --git a/frappe/public/js/print_format_builder/LetterHeadEditor.vue b/frappe/public/js/print_format_builder/LetterHeadEditor.vue new file mode 100644 index 0000000000..d958a6e67a --- /dev/null +++ b/frappe/public/js/print_format_builder/LetterHeadEditor.vue @@ -0,0 +1,108 @@ + + + diff --git a/frappe/public/js/print_format_builder/MarginText.vue b/frappe/public/js/print_format_builder/MarginText.vue new file mode 100644 index 0000000000..85229d2d42 --- /dev/null +++ b/frappe/public/js/print_format_builder/MarginText.vue @@ -0,0 +1,114 @@ + + + diff --git a/frappe/public/js/print_format_builder/Preview.vue b/frappe/public/js/print_format_builder/Preview.vue index 1ce89a87aa..1d795f27d7 100644 --- a/frappe/public/js/print_format_builder/Preview.vue +++ b/frappe/public/js/print_format_builder/Preview.vue @@ -97,6 +97,9 @@ export default { params.append("doctype", this.doctype); params.append("name", this.docname); params.append("print_format", this.print_format.name); + if (this.$store.letterhead) { + params.append("letterhead", this.$store.letterhead.name); + } let url = this.type == "PDF" ? `/api/method/frappe.utils.weasyprint.download_pdf` diff --git a/frappe/public/js/print_format_builder/PrintFormat.vue b/frappe/public/js/print_format_builder/PrintFormat.vue index f0f7f713ea..74cfb84133 100644 --- a/frappe/public/js/print_format_builder/PrintFormat.vue +++ b/frappe/public/js/print_format_builder/PrintFormat.vue @@ -1,6 +1,20 @@ - diff --git a/frappe/public/js/print_format_builder/PrintFormat.vue b/frappe/public/js/print_format_builder/PrintFormat.vue index 74cfb84133..7163282067 100644 --- a/frappe/public/js/print_format_builder/PrintFormat.vue +++ b/frappe/public/js/print_format_builder/PrintFormat.vue @@ -32,7 +32,12 @@ @change="$set(layout, 'footer', $event)" :button-label="__('Edit Footer')" /> - + @@ -85,6 +90,10 @@ export default { sections.push(_section); } this.$set(this.layout, "sections", sections); + }, + update_letterhead_footer(val) { + this.letterhead.footer = val; + this.letterhead._dirty = true; } } }; diff --git a/frappe/public/js/print_format_builder/store.js b/frappe/public/js/print_format_builder/store.js index f72cf0c450..57c48632c8 100644 --- a/frappe/public/js/print_format_builder/store.js +++ b/frappe/public/js/print_format_builder/store.js @@ -115,9 +115,11 @@ export function getStore(print_format_name) { }) .then(() => { if (this.letterhead && this.letterhead._dirty) { - return frappe.call("frappe.client.save", { - doc: this.letterhead - }); + return frappe + .call("frappe.client.save", { + doc: this.letterhead + }) + .then(r => (this.letterhead = r.message)); } }) .then(() => this.fetch()) @@ -125,7 +127,6 @@ export function getStore(print_format_name) { }, reset_changes() { this.fetch(); - }, get_layout() { if (this.print_format) { @@ -143,7 +144,7 @@ export function getStore(print_format_name) { return create_default_layout(this.meta); }, change_letterhead(letterhead) { - frappe.db.get_doc("Letter Head", letterhead).then(doc => { + return frappe.db.get_doc("Letter Head", letterhead).then(doc => { this.letterhead = doc; }); } diff --git a/frappe/public/js/print_format_builder/utils.js b/frappe/public/js/print_format_builder/utils.js index 77d4e2a36d..6c52b2e4a4 100644 --- a/frappe/public/js/print_format_builder/utils.js +++ b/frappe/public/js/print_format_builder/utils.js @@ -94,8 +94,8 @@ export function get_table_columns(df) { typeof tf.width == "number" && tf.width < 100 ? tf.width : tf.width - ? 20 - : 10; + ? 20 + : 10; table_columns.push({ label: tf.label, fieldname: tf.fieldname, @@ -118,3 +118,13 @@ export function pluck(object, keys) { } return out; } + +export function get_image_dimensions(src) { + return new Promise(resolve => { + let img = new Image(); + img.onload = function() { + resolve({ width: this.width, height: this.height }); + }; + img.src = src; + }); +} diff --git a/frappe/templates/print_format/print_format.html b/frappe/templates/print_format/print_format.html index 7e710e8c3f..69fb50d959 100644 --- a/frappe/templates/print_format/print_format.html +++ b/frappe/templates/print_format/print_format.html @@ -13,7 +13,7 @@ - {{ header }} + {{ header or '' }} {% for section in layout.sections %}
{% if section.label %} @@ -31,6 +31,6 @@
{% endfor %} - {{ footer }} + {{ footer or '' }} diff --git a/frappe/templates/print_format/print_header.html b/frappe/templates/print_format/print_header.html index 69a5360d6f..9b1357e08c 100644 --- a/frappe/templates/print_format/print_header.html +++ b/frappe/templates/print_format/print_header.html @@ -6,7 +6,7 @@ position: fixed; top: 0; left: 0; - width: 100%; + width: {{ body_width | int }}mm; padding-top: {{ print_format.margin_top | int }}mm; padding-left: {{ print_format.margin_left | int }}mm; padding-right: {{ print_format.margin_right | int }}mm; From a8347c0b27c7ad254cbd82f5a427eb62dfd10af8 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Mon, 4 Oct 2021 14:15:54 -0400 Subject: [PATCH 021/108] feat: allow bulk rename with merge --- frappe/model/rename_doc.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py index 9b8ac2574d..465358e557 100644 --- a/frappe/model/rename_doc.py +++ b/frappe/model/rename_doc.py @@ -458,7 +458,7 @@ def bulk_rename(doctype, rows=None, via_console = False): """Bulk rename documents :param doctype: DocType to be renamed - :param rows: list of documents as `((oldname, newname), ..)`""" + :param rows: list of documents as `((oldname, newname, merge(optional)), ..)`""" if not rows: frappe.throw(_("Please select a valid csv file with data")) @@ -471,8 +471,9 @@ def bulk_rename(doctype, rows=None, via_console = False): for row in rows: # if row has some content if len(row) > 1 and row[0] and row[1]: + merge = True if len(row) > 2 and (row[2] == "1" or row[2].lower() == "true") else False try: - if rename_doc(doctype, row[0], row[1]): + if rename_doc(doctype, row[0], row[1], merge=merge): msg = _("Successful: {0} to {1}").format(row[0], row[1]) frappe.db.commit() else: From 67acd5d22e5865b40e76fd8b57d458301707dbeb Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 5 Oct 2021 14:21:12 +0530 Subject: [PATCH 022/108] fix: Set route_options from links --- frappe/public/js/frappe/router.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js index 484f1ac911..7b26832522 100644 --- a/frappe/public/js/frappe/router.js +++ b/frappe/public/js/frappe/router.js @@ -58,6 +58,12 @@ $('body').on('click', 'a', function(e) { if (frappe.router.is_app_route(e.currentTarget.pathname)) { // target has "/app, this is a v2 style route. + + frappe.route_options = {}; + let params = new URLSearchParams(e.currentTarget.search); + for (const [key, value] of params) { + frappe.route_options[key] = value; + } return override(e.currentTarget.pathname + e.currentTarget.hash); } }); From d8457a3c71bdc2f0e73ba648f83537427faa4222 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 5 Oct 2021 14:21:57 +0530 Subject: [PATCH 023/108] fix: Show print preview on print page --- frappe/printing/page/print/print.js | 41 ++++++++- .../print_format_builder_beta.js | 83 +++++++++++++++++-- frappe/public/scss/desk/print_preview.scss | 5 ++ .../templates/print_format/print_format.css | 2 +- 4 files changed, 120 insertions(+), 11 deletions(-) diff --git a/frappe/printing/page/print/print.js b/frappe/printing/page/print/print.js index 27fc4be802..30d9fedeae 100644 --- a/frappe/printing/page/print/print.js +++ b/frappe/printing/page/print/print.js @@ -41,7 +41,11 @@ frappe.ui.form.PrintView = class {
- ` + +
+ +
+ ` ); this.print_settings = frappe.model.get_doc( @@ -134,7 +138,7 @@ frappe.ui.form.PrintView = class { add_sidebar_item(df, is_dynamic) { if (df.fieldtype == 'Select') { - df.input_class = 'btn btn-default btn-sm'; + df.input_class = 'btn btn-default btn-sm text-left'; } let field = frappe.ui.form.make_control({ @@ -187,6 +191,13 @@ frappe.ui.form.PrintView = class { this.set_breadcrumbs(); this.setup_customize_dialog(); + // print format builder beta + this.page.add_inner_message(` + + ${__('Try the new Print Format Builder')} + + `); + let tasks = [ this.refresh_print_options, this.set_default_print_language, @@ -383,6 +394,17 @@ frappe.ui.form.PrintView = class { } preview() { + let print_format = this.get_print_format(); + if (print_format.print_format_builder_beta) { + this.print_wrapper.find('.print-preview-wrapper').hide(); + this.print_wrapper.find('.preview-beta-wrapper').show(); + this.preview_beta(); + return; + } + + this.print_wrapper.find('.preview-beta-wrapper').hide(); + this.print_wrapper.find('.print-preview-wrapper').show(); + const $print_format = this.print_wrapper.find('iframe'); this.$print_format_body = $print_format.contents(); this.get_print_html((out) => { @@ -406,6 +428,21 @@ frappe.ui.form.PrintView = class { }); } + preview_beta() { + let print_format = this.get_print_format(); + const iframe = this.print_wrapper.find('.preview-beta-wrapper iframe'); + let params = new URLSearchParams({ + doctype: this.frm.doc.doctype, + name: this.frm.doc.name, + print_format: print_format.name + }); + let letterhead = this.get_letterhead(); + if (letterhead) { + params.append("letterhead", letterhead); + } + iframe.prop('src', `/printpreview?${params.toString()}`); + } + setup_print_format_dom(out, $print_format) { this.print_wrapper.find('.print-format-skeleton').remove(); let base_url = frappe.urllib.get_base_url(); diff --git a/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js index d53266d0d5..7185d17832 100644 --- a/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js +++ b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.js @@ -31,23 +31,90 @@ function load_print_format_builder_beta(wrapper) { }); } else { let d = new frappe.ui.Dialog({ - title: __("Select Print Format to edit"), + title: __("Create or Edit Print Format"), fields: [ { - label: __("Print Format"), + label: __("Action"), + fieldname: "action", + fieldtype: "Select", + options: [ + { label: __("Create New"), value: "Create" }, + { label: __("Edit Existing"), value: "Edit" } + ], + change() { + let action = d.get_value("action"); + d.get_primary_btn().text( + action === "Create" ? __("Create") : __("Edit") + ); + } + }, + { + label: __("Select Document Type"), + fieldname: "doctype", + fieldtype: "Link", + options: "DocType", + filters: { + istable: 0 + }, + reqd: 1, + default: frappe.route_options + ? frappe.route_options.doctype + : null + }, + { + label: __("Print Format Name"), + fieldname: "print_format_name", + fieldtype: "Data", + depends_on: doc => doc.action === "Create", + mandatory_depends_on: doc => doc.action === "Create" + }, + { + label: __("Select Print Format"), fieldname: "print_format", fieldtype: "Link", options: "Print Format", - filters: { - print_format_builder_beta: 1 - } + only_select: 1, + depends_on: doc => doc.action === "Edit", + get_query() { + return { + filters: { + doc_type: d.get_value("doctype"), + print_format_builder_beta: 1 + } + }; + }, + mandatory_depends_on: doc => doc.action === "Edit" } ], - primary_action({ print_format }) { - if (!print_format) return; - frappe.set_route("print-format-builder-beta", print_format); + primary_action_label: __("Edit"), + primary_action({ + action, + doctype, + print_format, + print_format_name + }) { + if (action === "Edit") { + frappe.set_route("print-format-builder-beta", print_format); + } else if (action === "Create") { + d.get_primary_btn().prop("disabled", true); + frappe.db + .insert({ + doctype: "Print Format", + name: print_format_name, + doc_type: doctype, + print_format_builder_beta: 1 + }) + .then(doc => { + d.get_primary_btn().prop("disabled", false); + frappe.set_route( + "print-format-builder-beta", + doc.name + ); + }); + } } }); + d.set_value("action", "Create"); d.show(); } } diff --git a/frappe/public/scss/desk/print_preview.scss b/frappe/public/scss/desk/print_preview.scss index 3c0acc68b8..468b37fe5a 100644 --- a/frappe/public/scss/desk/print_preview.scss +++ b/frappe/public/scss/desk/print_preview.scss @@ -14,6 +14,11 @@ } } +.preview-beta-wrapper { + border-radius: var(--border-radius); + overflow: hidden; +} + .print-toolbar { margin: 0px; padding: var(--padding-md) 0; diff --git a/frappe/templates/print_format/print_format.css b/frappe/templates/print_format/print_format.css index a52dcf49aa..fd0c0be1b6 100644 --- a/frappe/templates/print_format/print_format.css +++ b/frappe/templates/print_format/print_format.css @@ -34,7 +34,7 @@ body { @media screen { html { - background-color: var(--gray-300); + background-color: var(--gray-200); } body { background-color: white; From 75a9b9c8367d45250913efc6f6a5b9f37d0a617d Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 7 Oct 2021 14:22:14 +0530 Subject: [PATCH 024/108] fix: Redirect to private home if it exist --- frappe/public/js/frappe/desk.js | 2 +- frappe/public/js/frappe/router.js | 3 ++- frappe/public/js/frappe/views/workspace/workspace.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index a4dc1a6709..4a4c757cc3 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -283,7 +283,7 @@ frappe.Application = class Application { frappe.workspaces = {}; for (let page of frappe.boot.allowed_workspaces || []) { frappe.modules[page.module]=page; - frappe.workspaces[frappe.router.slug(page.title)] = page; + frappe.workspaces[frappe.router.slug(page.label)] = page; } } diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js index 484f1ac911..8ca9e6b0ad 100644 --- a/frappe/public/js/frappe/router.js +++ b/frappe/public/js/frappe/router.js @@ -354,7 +354,8 @@ frappe.router = { return a; } }).join('/'); - let default_page = frappe.workspaces['home'] ? 'home' : Object.keys(frappe.workspaces)[0]; + let private_home = frappe.workspaces[`home-${frappe.user.name.toLowerCase()}`]; + let default_page = private_home ? 'private/home' : frappe.workspaces['home'] ? 'home' : Object.keys(frappe.workspaces)[0]; return '/app/' + (path_string || default_page); }, diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js index 41f73c8639..052f4cf159 100644 --- a/frappe/public/js/frappe/views/workspace/workspace.js +++ b/frappe/public/js/frappe/views/workspace/workspace.js @@ -66,7 +66,7 @@ frappe.views.Workspace = class Workspace { if (this.all_pages) { frappe.workspaces = {}; for (let page of this.all_pages) { - frappe.workspaces[frappe.router.slug(page.title)] = {title: page.title}; + frappe.workspaces[frappe.router.slug(page.label)] = {title: page.title}; } if (this.new_page && this.new_page.name) { if (!frappe.workspaces[frappe.router.slug(this.new_page.name)]) { From 1133f625863adb46d9fa155bec90abed03a7f2a6 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 7 Oct 2021 15:55:29 +0530 Subject: [PATCH 025/108] fix: Added translation to blocks and sidebar items --- frappe/public/js/frappe/desk.js | 2 +- frappe/public/js/frappe/views/workspace/blocks/card.js | 2 +- frappe/public/js/frappe/views/workspace/blocks/chart.js | 2 +- frappe/public/js/frappe/views/workspace/blocks/header.js | 2 +- frappe/public/js/frappe/views/workspace/blocks/paragraph.js | 2 +- frappe/public/js/frappe/views/workspace/blocks/shortcut.js | 2 +- frappe/public/js/frappe/views/workspace/workspace.js | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index 4a4c757cc3..a53368d67a 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -283,7 +283,7 @@ frappe.Application = class Application { frappe.workspaces = {}; for (let page of frappe.boot.allowed_workspaces || []) { frappe.modules[page.module]=page; - frappe.workspaces[frappe.router.slug(page.label)] = page; + frappe.workspaces[frappe.router.slug(page.name)] = page; } } diff --git a/frappe/public/js/frappe/views/workspace/blocks/card.js b/frappe/public/js/frappe/views/workspace/blocks/card.js index 15e27fed40..9b4a2ed14f 100644 --- a/frappe/public/js/frappe/views/workspace/blocks/card.js +++ b/frappe/public/js/frappe/views/workspace/blocks/card.js @@ -30,7 +30,7 @@ export default class Card extends Block { this.new('card', 'links'); if (this.data && this.data.card_name) { - let has_data = this.make('card', this.data.card_name, 'links'); + let has_data = this.make('card', __(this.data.card_name), 'links'); if (!has_data) return; } diff --git a/frappe/public/js/frappe/views/workspace/blocks/chart.js b/frappe/public/js/frappe/views/workspace/blocks/chart.js index e41063e6fc..02e6a66e6f 100644 --- a/frappe/public/js/frappe/views/workspace/blocks/chart.js +++ b/frappe/public/js/frappe/views/workspace/blocks/chart.js @@ -30,7 +30,7 @@ export default class Chart extends Block { this.new('chart'); if (this.data && this.data.chart_name) { - let has_data = this.make('chart', this.data.chart_name); + let has_data = this.make('chart', __(this.data.chart_name)); if (!has_data) return; } diff --git a/frappe/public/js/frappe/views/workspace/blocks/header.js b/frappe/public/js/frappe/views/workspace/blocks/header.js index 356f9c3244..a87d52fc95 100644 --- a/frappe/public/js/frappe/views/workspace/blocks/header.js +++ b/frappe/public/js/frappe/views/workspace/blocks/header.js @@ -27,7 +27,7 @@ export default class Header extends Block { data = {}; } - newData.text = data.text || ''; + newData.text = __(data.text.replace(/(\n|\t)/gm,"")) || ''; newData.level = parseInt(data.level) || this.defaultLevel.number; newData.col = parseInt(data.col) || 12; diff --git a/frappe/public/js/frappe/views/workspace/blocks/paragraph.js b/frappe/public/js/frappe/views/workspace/blocks/paragraph.js index 26afa65d51..9e5dfb68ff 100644 --- a/frappe/public/js/frappe/views/workspace/blocks/paragraph.js +++ b/frappe/public/js/frappe/views/workspace/blocks/paragraph.js @@ -177,7 +177,7 @@ export default class Paragraph extends Block { set data(data) { this._data = data || {}; - this._element.innerHTML = this._data.text || ''; + this._element.innerHTML = __(this._data.text) || ''; } static get pasteConfig() { diff --git a/frappe/public/js/frappe/views/workspace/blocks/shortcut.js b/frappe/public/js/frappe/views/workspace/blocks/shortcut.js index f7482a06f3..96b8f47484 100644 --- a/frappe/public/js/frappe/views/workspace/blocks/shortcut.js +++ b/frappe/public/js/frappe/views/workspace/blocks/shortcut.js @@ -29,7 +29,7 @@ export default class Shortcut extends Block { this.new('shortcut'); if (this.data && this.data.shortcut_name) { - let has_data = this.make('shortcut', this.data.shortcut_name); + let has_data = this.make('shortcut', __(this.data.shortcut_name)); if (!has_data) return; } diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js index 052f4cf159..a97d6d293f 100644 --- a/frappe/public/js/frappe/views/workspace/workspace.js +++ b/frappe/public/js/frappe/views/workspace/workspace.js @@ -66,7 +66,7 @@ frappe.views.Workspace = class Workspace { if (this.all_pages) { frappe.workspaces = {}; for (let page of this.all_pages) { - frappe.workspaces[frappe.router.slug(page.label)] = {title: page.title}; + frappe.workspaces[frappe.router.slug(page.name)] = {title: page.title}; } if (this.new_page && this.new_page.name) { if (!frappe.workspaces[frappe.router.slug(this.new_page.name)]) { @@ -94,10 +94,10 @@ frappe.views.Workspace = class Workspace { From 7230b7e8e4065e9b4114d9d4c4c9219e93d90542 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 7 Oct 2021 16:06:27 +0530 Subject: [PATCH 026/108] fix: sider fix --- frappe/public/js/frappe/views/workspace/blocks/header.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/workspace/blocks/header.js b/frappe/public/js/frappe/views/workspace/blocks/header.js index a87d52fc95..219ee3ebd3 100644 --- a/frappe/public/js/frappe/views/workspace/blocks/header.js +++ b/frappe/public/js/frappe/views/workspace/blocks/header.js @@ -27,7 +27,7 @@ export default class Header extends Block { data = {}; } - newData.text = __(data.text.replace(/(\n|\t)/gm,"")) || ''; + newData.text = __(data.text.replace(/(\n|\t)/gm, "")) || ''; newData.level = parseInt(data.level) || this.defaultLevel.number; newData.col = parseInt(data.col) || 12; From f08584c06dbb7750a6ddf9542b51140a2dc544c6 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Fri, 8 Oct 2021 11:04:43 +0530 Subject: [PATCH 027/108] fix: Fixed redirect to newly created workspace --- frappe/public/js/frappe/router.js | 6 ++++-- frappe/public/js/frappe/views/workspace/blocks/header.js | 2 +- frappe/public/js/frappe/views/workspace/workspace.js | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js index 8ca9e6b0ad..7ecc3f5010 100644 --- a/frappe/public/js/frappe/router.js +++ b/frappe/public/js/frappe/router.js @@ -126,12 +126,14 @@ frappe.router = { // /app/user/user-001 = ["Form", "User", "user-001"] // /app/event/view/calendar/default = ["List", "Event", "Calendar", "Default"] + let private_wspace = route[1] && `${route[1]}-${frappe.user.name.toLowerCase()}`; + if (frappe.workspaces[route[0]]) { // public workspace route = ['Workspaces', frappe.workspaces[route[0]].title]; - } else if (route[0] == 'private' && frappe.workspaces[route[1]]) { + } else if (route[0] == 'private' && frappe.workspaces[private_wspace]) { // private workspace - route = ['Workspaces', 'private', frappe.workspaces[route[1]].title]; + route = ['Workspaces', 'private', frappe.workspaces[private_wspace].title]; } else if (this.routes[route[0]]) { // route route = this.set_doctype_route(route); diff --git a/frappe/public/js/frappe/views/workspace/blocks/header.js b/frappe/public/js/frappe/views/workspace/blocks/header.js index 219ee3ebd3..d88bc42af9 100644 --- a/frappe/public/js/frappe/views/workspace/blocks/header.js +++ b/frappe/public/js/frappe/views/workspace/blocks/header.js @@ -27,7 +27,7 @@ export default class Header extends Block { data = {}; } - newData.text = __(data.text.replace(/(\n|\t)/gm, "")) || ''; + newData.text = (data.text && __(data.text.replace(/(\n|\t)/gm, ""))) || ''; newData.level = parseInt(data.level) || this.defaultLevel.number; newData.col = parseInt(data.col) || 12; diff --git a/frappe/public/js/frappe/views/workspace/workspace.js b/frappe/public/js/frappe/views/workspace/workspace.js index a97d6d293f..e6248f66cf 100644 --- a/frappe/public/js/frappe/views/workspace/workspace.js +++ b/frappe/public/js/frappe/views/workspace/workspace.js @@ -69,7 +69,7 @@ frappe.views.Workspace = class Workspace { frappe.workspaces[frappe.router.slug(page.name)] = {title: page.title}; } if (this.new_page && this.new_page.name) { - if (!frappe.workspaces[frappe.router.slug(this.new_page.name)]) { + if (!frappe.workspaces[frappe.router.slug(this.new_page.label)]) { this.new_page = { name: this.all_pages[0].title, public: this.all_pages[0].public }; } if (this.new_page.public) { From 9ac748dc300e44298cb083e185adb6f6c9c38c6c Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 11 Oct 2021 19:45:06 +0200 Subject: [PATCH 028/108] feat: allow tuple of doctypes as key --- .../doctype/custom_field/custom_field.py | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/frappe/custom/doctype/custom_field/custom_field.py b/frappe/custom/doctype/custom_field/custom_field.py index bf606701da..8c22d3c45c 100644 --- a/frappe/custom/doctype/custom_field/custom_field.py +++ b/frappe/custom/doctype/custom_field/custom_field.py @@ -131,7 +131,7 @@ def create_custom_field(doctype, df, ignore_validate=False): "permlevel": 0, "fieldtype": 'Data', "hidden": 0, - # Looks like we always use this programatically? + # Looks like we always use this programatically? # "is_standard": 1 }) custom_field.update(df) @@ -146,24 +146,29 @@ def create_custom_fields(custom_fields, ignore_validate = False, update=True): if not ignore_validate and frappe.flags.in_setup_wizard: ignore_validate = True - for doctype, fields in custom_fields.items(): + for doctypes, fields in custom_fields.items(): if isinstance(fields, dict): # only one field fields = [fields] - for df in fields: - field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": df["fieldname"]}) - if not field: - try: - df["owner"] = "Administrator" - create_custom_field(doctype, df, ignore_validate=ignore_validate) - except frappe.exceptions.DuplicateEntryError: - pass - elif update: - custom_field = frappe.get_doc("Custom Field", field) - custom_field.flags.ignore_validate = ignore_validate - custom_field.update(df) - custom_field.save() + if isinstance(doctypes, str): + # only one doctype + doctypes = (doctypes,) + + for doctype in doctypes: + for df in fields: + field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": df["fieldname"]}) + if not field: + try: + df["owner"] = "Administrator" + create_custom_field(doctype, df, ignore_validate=ignore_validate) + except frappe.exceptions.DuplicateEntryError: + pass + elif update: + custom_field = frappe.get_doc("Custom Field", field) + custom_field.flags.ignore_validate = ignore_validate + custom_field.update(df) + custom_field.save() frappe.clear_cache(doctype=doctype) frappe.db.updatedb(doctype) From 7315076038fea37f8368ee691b56835ff3b64ab7 Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Wed, 13 Oct 2021 14:06:34 +0530 Subject: [PATCH 029/108] refactor: converted queries --- frappe/defaults.py | 18 ++++++++---------- frappe/permissions.py | 17 +++++++++-------- frappe/sessions.py | 18 +++++++++--------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/frappe/defaults.py b/frappe/defaults.py index 75feabc332..796965e597 100644 --- a/frappe/defaults.py +++ b/frappe/defaults.py @@ -116,14 +116,11 @@ def set_default(key, value, parent, parenttype="__default"): :param value: Default value. :param parent: Usually, **User** to whom the default belongs. :param parenttype: [optional] default is `__default`.""" - if frappe.db.sql(''' - select - defkey - from - `tabDefaultValue` - where - defkey=%s and parent=%s - for update''', (key, parent)): + table = frappe.qb.DocType("DefaultValue") + result = frappe.qb.from_(table).where(table.defkey == key) \ + .where(table.parent == parent) \ + .select(table.defkey).for_update().run() + if result: frappe.db.delete("DefaultValue", { "defkey": key, "parent": parent @@ -191,8 +188,9 @@ def get_defaults_for(parent="__default"): if defaults==None: # sort descending because first default must get precedence - res = frappe.db.sql("""select defkey, defvalue from `tabDefaultValue` - where parent = %s order by creation""", (parent,), as_dict=1) + table = frappe.qb.DocType("DefaultValue") + res = frappe.qb.from_(table).where(table.parent == parent) \ + .select(table.defkey, table.defvalue).orderby("creation").run(as_dict=True) defaults = frappe._dict({}) for d in res: diff --git a/frappe/permissions.py b/frappe/permissions.py index 7ee1119ebb..34fcbee1a8 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -333,8 +333,8 @@ def get_all_perms(role): '''Returns valid permissions for a given role''' perms = frappe.get_all('DocPerm', fields='*', filters=dict(role=role)) custom_perms = frappe.get_all('Custom DocPerm', fields='*', filters=dict(role=role)) - doctypes_with_custom_perms = frappe.db.sql_list("""select distinct parent - from `tabCustom DocPerm`""") + query = frappe.qb.from_("Custom DocPerm").select("parent").distinct() + doctypes_with_custom_perms = frappe.db.sql_list(query) for p in perms: if p.parent not in doctypes_with_custom_perms: @@ -351,10 +351,12 @@ def get_roles(user=None, with_standard=True): def get(): if user == 'Administrator': - return [r[0] for r in frappe.db.sql("select name from `tabRole`")] # return all available roles + return [r[0] for r in frappe.qb.from_("Role").select("name").run()] # return all available roles else: - return [r[0] for r in frappe.db.sql("""select role from `tabHas Role` - where parent=%s and role not in ('All', 'Guest')""", (user,))] + ['All', 'Guest'] + table = frappe.qb.DocType("Has Role") + result = frappe.qb.form_(table).where(table.parent == user) \ + .where(table.role.notin(["All", "Guest"])).select(table.role).run() + return [r[0] for r in result] + ['All', 'Guest'] roles = frappe.cache().hget("roles", user, get) @@ -463,10 +465,9 @@ def update_permission_property(doctype, role, permlevel, ptype, value=None, vali name = frappe.get_value('Custom DocPerm', dict(parent=doctype, role=role, permlevel=permlevel)) + table = frappe.qb.DocType("Custom DocPerm") + frappe.qb.update(table).set(ptype, value).where(table.name == name).run() - frappe.db.sql(""" - update `tabCustom DocPerm` - set `{0}`=%s where name=%s""".format(ptype), (value, name)) if validate: validate_permissions_for_doctype(doctype) diff --git a/frappe/sessions.py b/frappe/sessions.py index ce104968ad..efa2779a23 100644 --- a/frappe/sessions.py +++ b/frappe/sessions.py @@ -16,6 +16,7 @@ import frappe.translate import redis from urllib.parse import unquote from frappe.cache_manager import clear_user_cache +from frappe.query_builder import Order @frappe.whitelist(allow_guest=True) def clear(user=None): @@ -61,18 +62,17 @@ def get_sessions_to_clear(user=None, keep_current=False, device=None): simultaneous_sessions = frappe.db.get_value('User', user, 'simultaneous_sessions') or 1 offset = simultaneous_sessions - 1 + table = frappe.qb.DocType("Sessions") + criterion = frappe.qb.from_(table).where(table.user == user) \ + .where(table.device.isin(device)) condition = '' if keep_current: - condition = ' AND sid != {0}'.format(frappe.db.escape(frappe.session.sid)) + criterion = criterion.where(table.sid != frappe.db.escape(frappe.session.sid)) - return frappe.db.sql_list(""" - SELECT `sid` FROM `tabSessions` - WHERE `tabSessions`.user=%(user)s - AND device in %(device)s - {condition} - ORDER BY `lastupdate` DESC - LIMIT 100 OFFSET {offset}""".format(condition=condition, offset=offset), - {"user": user, "device": device}) + query = criterion.select(table.sid).offset(offset).limit(100) \ + .orderby(table.lastupdate, order=Order.desc) + + return frappe.db.sql_list(query) def delete_session(sid=None, user=None, reason="Session Expired"): from frappe.core.doctype.activity_log.feed import logout_feed From a621c4178cb20ffc19296226c6851ec5b8cbf6e7 Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Wed, 13 Oct 2021 14:28:13 +0530 Subject: [PATCH 030/108] fix: fixing erroneous query conversions --- frappe/defaults.py | 2 +- frappe/permissions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/defaults.py b/frappe/defaults.py index 796965e597..3672bed511 100644 --- a/frappe/defaults.py +++ b/frappe/defaults.py @@ -190,7 +190,7 @@ def get_defaults_for(parent="__default"): # sort descending because first default must get precedence table = frappe.qb.DocType("DefaultValue") res = frappe.qb.from_(table).where(table.parent == parent) \ - .select(table.defkey, table.defvalue).orderby("creation").run(as_dict=True) + .select(table.defkey, table.defvalue).orderby("creation").run(as_dict=True) defaults = frappe._dict({}) for d in res: diff --git a/frappe/permissions.py b/frappe/permissions.py index 34fcbee1a8..494a0f1d14 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -354,7 +354,7 @@ def get_roles(user=None, with_standard=True): return [r[0] for r in frappe.qb.from_("Role").select("name").run()] # return all available roles else: table = frappe.qb.DocType("Has Role") - result = frappe.qb.form_(table).where(table.parent == user) \ + result = frappe.qb.from_(table).where(table.parent == user) \ .where(table.role.notin(["All", "Guest"])).select(table.role).run() return [r[0] for r in result] + ['All', 'Guest'] From e0a3e4efe3283ae08e88979262723b9e460a1aeb Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Wed, 13 Oct 2021 15:13:13 +0530 Subject: [PATCH 031/108] refactor: converted queries in share & translate --- frappe/share.py | 6 ++++-- frappe/translate.py | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/frappe/share.py b/frappe/share.py index 030feea8fa..cee1120066 100644 --- a/frappe/share.py +++ b/frappe/share.py @@ -128,8 +128,10 @@ def get_shared_doctypes(user=None): """Return list of doctypes in which documents are shared for the given user.""" if not user: user = frappe.session.user - - return frappe.db.sql_list("select distinct share_doctype from tabDocShare where (user=%s or everyone=1)", user) + table = frappe.qb.DocType("DocShare") + query = frappe.qb.from_(table).where(table.user == user | table.everyone == 1) \ + .select(table.share_doctype).distinct() + return frappe.db.sql_list(query) def get_share_name(doctype, name, user, everyone): if cint(everyone): diff --git a/frappe/translate.py b/frappe/translate.py index 6f3ed81dc2..3fc9fa826e 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -119,7 +119,8 @@ def set_default_language(lang): def get_lang_dict(): """Returns all languages in dict format, full name is the key e.g. `{"english":"en"}`""" - return dict(frappe.db.sql('select language_name, name from tabLanguage')) + result = dict(frappe.qb.from_("Language").select("language_name", "name").run()) + return result def get_dict(fortype, name=None): """Returns translation dict for a type of object. @@ -151,12 +152,12 @@ def get_dict(fortype, name=None): messages += get_messages_from_navbar() messages += get_messages_from_include_files() - messages += frappe.db.sql("select 'Print Format:', name from `tabPrint Format`") - messages += frappe.db.sql("select 'DocType:', name from tabDocType") - messages += frappe.db.sql("select 'Role:', name from tabRole") - messages += frappe.db.sql("select 'Module:', name from `tabModule Def`") - messages += frappe.db.sql("select '', format from `tabWorkspace Shortcut` where format is not null") - messages += frappe.db.sql("select '', title from `tabOnboarding Step`") + messages += frappe.qb.from_("Print Format").select("Print Format:", "name").run() + messages += frappe.qb.from_("DocType").select("DocType:", "name").run() + messages += frappe.qb.from_("Role").select("Role:", "name").run() + messages += frappe.qb.from_("Module Def").select("Module:", "name").run() + messages += frappe.qb.from_("Workspace Shortcut").where(frappe.qb.Field("format" != None)).select("").run() + messages += frappe.qb.from_("Onboarding Step").select("", "title").run() messages = deduplicate_messages(messages) message_dict = make_dict_from_messages(messages, load_user_translation=False) @@ -898,7 +899,8 @@ def get_translator_url(): def get_all_languages(with_language_name=False): """Returns all language codes ar, ch etc""" def get_language_codes(): - return frappe.db.sql_list('select name from tabLanguage') + query = frappe.qb.from_("Language").select("name") + return frappe.db.sql_list(query) def get_all_language_with_name(): return frappe.db.get_all('Language', ['language_code', 'language_name']) From 12e4b33a1f8a9e66091f0531d19f50fff7dc649c Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Wed, 13 Oct 2021 11:26:24 -0400 Subject: [PATCH 032/108] fix: simplify merge condition statement Co-authored-by: gavin --- frappe/model/rename_doc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py index 9377ad74f8..de83b24cd8 100644 --- a/frappe/model/rename_doc.py +++ b/frappe/model/rename_doc.py @@ -471,7 +471,7 @@ def bulk_rename(doctype, rows=None, via_console = False): for row in rows: # if row has some content if len(row) > 1 and row[0] and row[1]: - merge = True if len(row) > 2 and (row[2] == "1" or row[2].lower() == "true") else False + merge = len(row) > 2 and (row[2] == "1" or row[2].lower() == "true") try: if rename_doc(doctype, row[0], row[1], merge=merge): msg = _("Successful: {0} to {1}").format(row[0], row[1]) From e01d97b8df979e59a318cd3e1b03c5838f3b8e83 Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Thu, 14 Oct 2021 01:16:46 +0530 Subject: [PATCH 033/108] refactor: replacing queries with frappe ORM --- frappe/defaults.py | 20 ++++++++++++-------- frappe/permissions.py | 16 ++++++++-------- frappe/translate.py | 15 ++++++++++----- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/frappe/defaults.py b/frappe/defaults.py index 3672bed511..eb98db449f 100644 --- a/frappe/defaults.py +++ b/frappe/defaults.py @@ -4,6 +4,7 @@ import frappe from frappe.desk.notifications import clear_notifications from frappe.cache_manager import clear_defaults_cache, common_default_keys +from frappe.query_builder import DocType # Note: DefaultValue records are identified by parenttype # __default, __global or 'User Permission' @@ -116,11 +117,11 @@ def set_default(key, value, parent, parenttype="__default"): :param value: Default value. :param parent: Usually, **User** to whom the default belongs. :param parenttype: [optional] default is `__default`.""" - table = frappe.qb.DocType("DefaultValue") - result = frappe.qb.from_(table).where(table.defkey == key) \ - .where(table.parent == parent) \ - .select(table.defkey).for_update().run() - if result: + table = DocType("DefaultValue") + key_exists = frappe.qb.from_(table).where( + (table.defkey == key) & (table.parent == parent) + ).select(table.defkey).for_update().run() + if key_exists: frappe.db.delete("DefaultValue", { "defkey": key, "parent": parent @@ -188,9 +189,12 @@ def get_defaults_for(parent="__default"): if defaults==None: # sort descending because first default must get precedence - table = frappe.qb.DocType("DefaultValue") - res = frappe.qb.from_(table).where(table.parent == parent) \ - .select(table.defkey, table.defvalue).orderby("creation").run(as_dict=True) + table = DocType("DefaultValue") + res = frappe.qb.from_(table).where( + table.parent == parent + ).select( + table.defkey, table.defvalue + ).orderby("creation").run(as_dict=True) defaults = frappe._dict({}) for d in res: diff --git a/frappe/permissions.py b/frappe/permissions.py index 494a0f1d14..0585b1e220 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -6,7 +6,7 @@ import frappe import frappe.share from frappe import _, msgprint from frappe.utils import cint - +from frappe.query_builder import DocType rights = ("select", "read", "write", "create", "delete", "submit", "cancel", "amend", "print", "email", "report", "import", "export", "set_user_permissions", "share") @@ -333,8 +333,7 @@ def get_all_perms(role): '''Returns valid permissions for a given role''' perms = frappe.get_all('DocPerm', fields='*', filters=dict(role=role)) custom_perms = frappe.get_all('Custom DocPerm', fields='*', filters=dict(role=role)) - query = frappe.qb.from_("Custom DocPerm").select("parent").distinct() - doctypes_with_custom_perms = frappe.db.sql_list(query) + doctypes_with_custom_perms = frappe.get_all("Custom DocPerm", pluck="parent", distinct=True) for p in perms: if p.parent not in doctypes_with_custom_perms: @@ -351,11 +350,12 @@ def get_roles(user=None, with_standard=True): def get(): if user == 'Administrator': - return [r[0] for r in frappe.qb.from_("Role").select("name").run()] # return all available roles + return frappe.get_all("Role", pluck="name") # return all available roles else: - table = frappe.qb.DocType("Has Role") - result = frappe.qb.from_(table).where(table.parent == user) \ - .where(table.role.notin(["All", "Guest"])).select(table.role).run() + table = DocType("Has Role") + result = frappe.qb.from_(table).where( + (table.parent == user) & (table.role.notin(["All", "Guest"])) + ).select(table.role).run() return [r[0] for r in result] + ['All', 'Guest'] roles = frappe.cache().hget("roles", user, get) @@ -465,7 +465,7 @@ def update_permission_property(doctype, role, permlevel, ptype, value=None, vali name = frappe.get_value('Custom DocPerm', dict(parent=doctype, role=role, permlevel=permlevel)) - table = frappe.qb.DocType("Custom DocPerm") + table = DocType("Custom DocPerm") frappe.qb.update(table).set(ptype, value).where(table.name == name).run() if validate: diff --git a/frappe/translate.py b/frappe/translate.py index 3fc9fa826e..3abffd3215 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -20,6 +20,7 @@ from typing import List, Union, Tuple import frappe from frappe.model.utils import InvalidIncludePath, render_include from frappe.utils import get_bench_path, is_html, strip, strip_html_tags +from frappe.query_builder import Field def get_language(lang_list: List = None) -> str: @@ -156,7 +157,7 @@ def get_dict(fortype, name=None): messages += frappe.qb.from_("DocType").select("DocType:", "name").run() messages += frappe.qb.from_("Role").select("Role:", "name").run() messages += frappe.qb.from_("Module Def").select("Module:", "name").run() - messages += frappe.qb.from_("Workspace Shortcut").where(frappe.qb.Field("format" != None)).select("").run() + messages += frappe.qb.from_("Workspace Shortcut").where(Field("format").isnotnull()).select("").run() messages += frappe.qb.from_("Onboarding Step").select("", "title").run() messages = deduplicate_messages(messages) @@ -324,13 +325,17 @@ def get_messages_for_app(app, deduplicate=True): # doctypes if modules: - for name in frappe.db.sql_list("""select name from tabDocType - where module in ({})""".format(modules)): + names = frappe.qb.from_("DocType").where( + Field("module").isin(modules) + ).select("name").run() + for name in names: messages.extend(get_messages_from_doctype(name)) # pages - for name, title in frappe.db.sql("""select name, title from tabPage - where module in ({})""".format(modules)): + result = frappe.qb.from_("Page").where( + Field("module").isin(modules) + ).select("name", "title").run() + for name, title in result: messages.append((None, title or name)) messages.extend(get_messages_from_page(name)) From d75aab4b3edf219471169b12487b3c3dcfd92be5 Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Thu, 14 Oct 2021 03:28:53 +0530 Subject: [PATCH 034/108] fix: fixed erroneous query conversion --- frappe/share.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/share.py b/frappe/share.py index cee1120066..4d43990c54 100644 --- a/frappe/share.py +++ b/frappe/share.py @@ -129,8 +129,9 @@ def get_shared_doctypes(user=None): if not user: user = frappe.session.user table = frappe.qb.DocType("DocShare") - query = frappe.qb.from_(table).where(table.user == user | table.everyone == 1) \ - .select(table.share_doctype).distinct() + query = frappe.qb.from_(table).where( + (table.user == user) | (table.everyone == 1) + ).select(table.share_doctype).distinct() return frappe.db.sql_list(query) def get_share_name(doctype, name, user, everyone): From 5186347219759bc51ffe34df394c6506aefcd916 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 14 Oct 2021 11:08:21 +0530 Subject: [PATCH 035/108] revert: Reverting single vertical scrollbar fix --- .../js/frappe/views/reports/query_report.js | 4 ---- .../js/frappe/views/reports/report_view.js | 2 -- frappe/public/scss/desk/report.scss | 22 ------------------- 3 files changed, 28 deletions(-) diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 7d68919821..a4b3564e37 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -518,9 +518,6 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { } else { this.page.show_form(); } - - this.page.body[0].style.setProperty('--report-filter-height', this.page.page_form.css('height')); - this.page.body.parent().css('margin-bottom', 'unset'); } set_filters(filters) { @@ -832,7 +829,6 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { if (this.raw_data.add_total_row) { data = data.slice(); data.splice(-1, 1); - this.$page.find('.layout-main-section')[0].style.setProperty('--report-total-height', '310px'); } this.$report.show(); diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index 2a92d93e30..8866a4b2af 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -50,8 +50,6 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { this.setup_columns(); super.setup_new_doc_event(); this.page.main.addClass('report-view'); - this.page.body[0].style.setProperty('--report-filter-height', this.page.page_form.css('height')); - this.page.body.parent().css('margin-bottom', 'unset'); } toggle_side_bar() { diff --git a/frappe/public/scss/desk/report.scss b/frappe/public/scss/desk/report.scss index 2389a4f8f6..f8666602ff 100644 --- a/frappe/public/scss/desk/report.scss +++ b/frappe/public/scss/desk/report.scss @@ -84,39 +84,17 @@ margin-bottom: 10px; } -.layout-main-section { - --report-filter-height: 0px; - --report-total-height: 275px; -} - .report-wrapper { overflow: auto; - - .datatable { - height: calc(100vh - var(--report-filter-height) - 205px); - - .dt-scrollable { - height: calc(100vh - var(--report-filter-height) - var(--report-total-height)); - } - } } .report-view { .result { - min-height: 50vh !important; .dt-row:last-child:not(.dt-row-filter) { .dt-cell { border-bottom: 1px solid var(--border-color); } } - - .datatable { - height: calc(100vh - var(--report-filter-height) - 225px); - - .dt-scrollable { - height: calc(100vh - var(--report-filter-height) - 295px); - } - } } } From f5a5f975936390039672012b0225b79a1d714db9 Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Thu, 14 Oct 2021 03:29:20 +0530 Subject: [PATCH 036/108] refactor: converted quries in sessions.py --- frappe/sessions.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frappe/sessions.py b/frappe/sessions.py index efa2779a23..508badbd8f 100644 --- a/frappe/sessions.py +++ b/frappe/sessions.py @@ -17,6 +17,7 @@ import redis from urllib.parse import unquote from frappe.cache_manager import clear_user_cache from frappe.query_builder import Order +from frappe.query_builder import DocType @frappe.whitelist(allow_guest=True) def clear(user=None): @@ -65,12 +66,10 @@ def get_sessions_to_clear(user=None, keep_current=False, device=None): table = frappe.qb.DocType("Sessions") criterion = frappe.qb.from_(table).where(table.user == user) \ .where(table.device.isin(device)) - condition = '' if keep_current: criterion = criterion.where(table.sid != frappe.db.escape(frappe.session.sid)) - query = criterion.select(table.sid).offset(offset).limit(100) \ - .orderby(table.lastupdate, order=Order.desc) + query = criterion.select(table.sid).offset(offset).limit(100).orderby(table.lastupdate, order=Order.desc) return frappe.db.sql_list(query) @@ -80,7 +79,10 @@ def delete_session(sid=None, user=None, reason="Session Expired"): frappe.cache().hdel("session", sid) frappe.cache().hdel("last_db_session_update", sid) if sid and not user: - user_details = frappe.db.sql("""select user from tabSessions where sid=%s""", sid, as_dict=True) + table = DocType("Sessions") + user_details = frappe.qb.from_(table).where( + table.sid == sid + ).select(table.user).run(as_dict=True) if user_details: user = user_details[0].get("user") logout_feed(user, reason) @@ -91,7 +93,7 @@ def clear_all_sessions(reason=None): """This effectively logs out all users""" frappe.only_for("Administrator") if not reason: reason = "Deleted All Active Session" - for sid in frappe.db.sql_list("select sid from `tabSessions`"): + for sid in [r[0] for r in frappe.qb.from_("Sessions").select("sid").run()]: delete_session(sid, reason=reason) def get_expired_sessions(): From b05cd732f53dc3e4197b0819958bc86d9ea2965d Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Thu, 14 Oct 2021 14:45:15 +0530 Subject: [PATCH 037/108] ci: trigger build From 58de6515e7bd7a54f03cfd35267f85860343350f Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 14 Oct 2021 11:23:56 +0200 Subject: [PATCH 038/108] test: test_create_custom_fields --- .../doctype/custom_field/test_custom_field.py | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/frappe/custom/doctype/custom_field/test_custom_field.py b/frappe/custom/doctype/custom_field/test_custom_field.py index 9633f0eb8a..ad3cf27eea 100644 --- a/frappe/custom/doctype/custom_field/test_custom_field.py +++ b/frappe/custom/doctype/custom_field/test_custom_field.py @@ -6,7 +6,42 @@ import frappe import unittest -test_records = frappe.get_test_records('Custom Field') +test_records = frappe.get_test_records("Custom Field") + class TestCustomField(unittest.TestCase): - pass + def test_create_custom_fields(self): + from .custom_field import create_custom_fields + + create_custom_fields( + { + "Address": [ + { + "fieldname": "_test_custom_field_1", + "label": "_Test Custom Field 1", + "fieldtype": "Data", + "insert_after": "phone", + }, + ], + ("Address", "Contact"): [ + { + "fieldname": "_test_custom_field_2", + "label": "_Test Custom Field 2", + "fieldtype": "Data", + "insert_after": "phone", + }, + ], + } + ) + + frappe.db.commit() + + self.assertTrue( + frappe.db.exists("Custom Field", "Address-_test_custom_field_1") + ) + self.assertTrue( + frappe.db.exists("Custom Field", "Address-_test_custom_field_2") + ) + self.assertTrue( + frappe.db.exists("Custom Field", "Contact-_test_custom_field_2") + ) From 668051cfe9a7b3a6a30485a81b2c7fca380cb646 Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Thu, 14 Oct 2021 22:54:53 +0530 Subject: [PATCH 039/108] refactor: refactored query using frappe.get_all --- frappe/translate.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frappe/translate.py b/frappe/translate.py index 3abffd3215..f6a3880774 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -120,7 +120,7 @@ def set_default_language(lang): def get_lang_dict(): """Returns all languages in dict format, full name is the key e.g. `{"english":"en"}`""" - result = dict(frappe.qb.from_("Language").select("language_name", "name").run()) + result = frappe.get_all("Language", fields=["language_name", "name"], order_by="modified", as_list=True) return result def get_dict(fortype, name=None): @@ -904,8 +904,7 @@ def get_translator_url(): def get_all_languages(with_language_name=False): """Returns all language codes ar, ch etc""" def get_language_codes(): - query = frappe.qb.from_("Language").select("name") - return frappe.db.sql_list(query) + return frappe.get_all("Language", pluck="name", order_by="modified") def get_all_language_with_name(): return frappe.db.get_all('Language', ['language_code', 'language_name']) From 4ed10de918bfa05d9e38675868e42e92cede805f Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Thu, 14 Oct 2021 23:25:43 +0530 Subject: [PATCH 040/108] fix: fixed sider issues --- frappe/core/doctype/activity_log/activity_log.py | 9 ++++++--- frappe/sessions.py | 3 +-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/frappe/core/doctype/activity_log/activity_log.py b/frappe/core/doctype/activity_log/activity_log.py index 183a1c264c..9c27e84740 100644 --- a/frappe/core/doctype/activity_log/activity_log.py +++ b/frappe/core/doctype/activity_log/activity_log.py @@ -7,6 +7,8 @@ from frappe.utils import get_fullname, now from frappe.model.document import Document from frappe.core.utils import set_timeline_doc import frappe +from frappe.query_builder import DocType, Interval +from frappe.query_builder.functions import Now class ActivityLog(Document): def before_insert(self): @@ -44,6 +46,7 @@ def clear_activity_logs(days=None): if not days: days = 90 - - frappe.db.sql("""delete from `tabActivity Log` where \ - creation< (NOW() - INTERVAL '{0}' DAY)""".format(days)) \ No newline at end of file + doctype = DocType("Activity Log") + frappe.qb.from_(doctype).where( + doctype.creation < (Now() - Interval(days=days)) + ).delete().run() \ No newline at end of file diff --git a/frappe/sessions.py b/frappe/sessions.py index 508badbd8f..05f3bba3cf 100644 --- a/frappe/sessions.py +++ b/frappe/sessions.py @@ -64,8 +64,7 @@ def get_sessions_to_clear(user=None, keep_current=False, device=None): offset = simultaneous_sessions - 1 table = frappe.qb.DocType("Sessions") - criterion = frappe.qb.from_(table).where(table.user == user) \ - .where(table.device.isin(device)) + criterion = frappe.qb.from_(table).where((table.user == user) & (table.device.isin(device))) if keep_current: criterion = criterion.where(table.sid != frappe.db.escape(frappe.session.sid)) From 2c088c81ba3f05cd9a9500cf3ef197e028f89c14 Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Fri, 15 Oct 2021 05:00:46 +0530 Subject: [PATCH 041/108] refactor: Converted more queries --- .../core/doctype/log_settings/log_settings.py | 10 +++++-- frappe/core/doctype/user/user.py | 30 ++++++++++++------- .../patches/v11_0/remove_skip_for_doctype.py | 17 +++++------ 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/frappe/core/doctype/log_settings/log_settings.py b/frappe/core/doctype/log_settings/log_settings.py index 8a471b9173..5b361c9a13 100644 --- a/frappe/core/doctype/log_settings/log_settings.py +++ b/frappe/core/doctype/log_settings/log_settings.py @@ -5,6 +5,9 @@ import frappe from frappe import _ from frappe.model.document import Document +from frappe.query_builder import DocType, Interval +from frappe.query_builder.functions import Now + class LogSettings(Document): def clear_logs(self): @@ -13,9 +16,10 @@ class LogSettings(Document): self.clear_email_queue() def clear_error_logs(self): - frappe.db.sql(""" DELETE FROM `tabError Log` - WHERE `creation` < (NOW() - INTERVAL '{0}' DAY) - """.format(self.clear_error_log_after)) + table = DocType("Error Log") + frappe.db.delete(table, filters=( + table.creation < Now() - Interval(days=self.clear_error_log_after) + )) def clear_activity_logs(self): from frappe.core.doctype.activity_log.activity_log import clear_activity_logs diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index e4b94cdbb6..45f7d47a27 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -16,6 +16,7 @@ from frappe.utils.user import get_system_managers from frappe.website.utils import is_signup_disabled from frappe.rate_limiter import rate_limit from frappe.core.doctype.user_type.user_type import user_linked_with_permission_on_doctype +from frappe.query_builder import DocType STANDARD_USERS = ("Guest", "Administrator") @@ -366,15 +367,21 @@ class User(Document): # delete shares frappe.db.delete("DocShare", {"user": self.name}) # delete messages - frappe.db.sql("""delete from `tabCommunication` - where communication_type in ('Chat', 'Notification') - and reference_doctype='User' - and (reference_name=%s or owner=%s)""", (self.name, self.name)) - + table = DocType("Communication") + frappe.db.delete( + table, + filters=( + (table.communication_type.isin(["Chat", "Notification"])) + & (table.reference_doctype == "User") + & ((table.reference_name == self.name) | table.owner == self.name) + ), + run=False, + ) # unlink contact - frappe.db.sql("""update `tabContact` - set `user`=null - where `user`=%s""", (self.name)) + table = DocType("Contact") + frappe.qb.update(table).where( + table.user == self.name + ).set(table.user, None).run() # delete notification settings frappe.delete_doc("Notification Settings", self.name, ignore_permissions=True) @@ -421,9 +428,10 @@ class User(Document): frappe.rename_doc("Notification Settings", old_name, new_name, force=True, show_alert=False) # set email - frappe.db.sql("""UPDATE `tabUser` - SET email = %s - WHERE name = %s""", (new_name, new_name)) + table = DocType("User") + frappe.qb.update(table).where( + table.name == new_name + ).set("email", new_name).run() def append_roles(self, *roles): """Add roles to user""" diff --git a/frappe/patches/v11_0/remove_skip_for_doctype.py b/frappe/patches/v11_0/remove_skip_for_doctype.py index 638a5a0fd7..1063dca3ff 100644 --- a/frappe/patches/v11_0/remove_skip_for_doctype.py +++ b/frappe/patches/v11_0/remove_skip_for_doctype.py @@ -2,6 +2,7 @@ import frappe from frappe.desk.form.linked_with import get_linked_doctypes from frappe.patches.v11_0.replicate_old_user_permissions import get_doctypes_to_skip +from frappe.query_builder import Field # `skip_for_doctype` was a un-normalized way of storing for which # doctypes the user permission was applicable. @@ -72,16 +73,12 @@ def execute(): frappe.db.set_value('User Permission', user_permission.name, 'apply_to_all_doctypes', 1) if new_user_permissions_list: - frappe.db.sql(''' - INSERT INTO `tabUser Permission` - (`name`, `user`, `allow`, `for_value`, `applicable_for`, `apply_to_all_doctypes`, `creation`, `modified`) - VALUES {} - '''.format( # nosec - ', '.join(['%s'] * len(new_user_permissions_list)) - ), tuple(new_user_permissions_list)) + frappe.qb.into("User Permission").columns( + "name", "user", "allow", "for_value", "applicable_for", "apply_to_all_doctypes", "creation", "modified" + ).insert(tuple(new_user_permissions_list)).run() if user_permissions_to_delete: - frappe.db.sql('DELETE FROM `tabUser Permission` WHERE `name` in ({})' # nosec - .format(','.join(['%s'] * len(user_permissions_to_delete))), - tuple(user_permissions_to_delete) + frappe.db.delete( + "User Permission", + filters=(Field("name").isin(tuple(user_permissions_to_delete))) ) From 0cce6e2af87d26f9844e4ace38418f190cf10f2f Mon Sep 17 00:00:00 2001 From: Aradhya-Tripathi Date: Sat, 16 Oct 2021 09:21:38 +0530 Subject: [PATCH 042/108] fix: fixed erroneous queries in translate --- .../core/doctype/activity_log/activity_log.py | 7 ++-- .../core/doctype/log_settings/log_settings.py | 3 +- frappe/translate.py | 36 +++++++++++++++---- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/frappe/core/doctype/activity_log/activity_log.py b/frappe/core/doctype/activity_log/activity_log.py index 9c27e84740..69565a2c2a 100644 --- a/frappe/core/doctype/activity_log/activity_log.py +++ b/frappe/core/doctype/activity_log/activity_log.py @@ -9,6 +9,7 @@ from frappe.core.utils import set_timeline_doc import frappe from frappe.query_builder import DocType, Interval from frappe.query_builder.functions import Now +from pypika.terms import PseudoColumn class ActivityLog(Document): def before_insert(self): @@ -47,6 +48,6 @@ def clear_activity_logs(days=None): if not days: days = 90 doctype = DocType("Activity Log") - frappe.qb.from_(doctype).where( - doctype.creation < (Now() - Interval(days=days)) - ).delete().run() \ No newline at end of file + frappe.db.delete(doctype, filters=( + doctype.creation < PseudoColumn(f"({Now() - Interval(days=days)})") + )) \ No newline at end of file diff --git a/frappe/core/doctype/log_settings/log_settings.py b/frappe/core/doctype/log_settings/log_settings.py index 5b361c9a13..008656f0f6 100644 --- a/frappe/core/doctype/log_settings/log_settings.py +++ b/frappe/core/doctype/log_settings/log_settings.py @@ -7,6 +7,7 @@ from frappe import _ from frappe.model.document import Document from frappe.query_builder import DocType, Interval from frappe.query_builder.functions import Now +from pypika.terms import PseudoColumn class LogSettings(Document): @@ -18,7 +19,7 @@ class LogSettings(Document): def clear_error_logs(self): table = DocType("Error Log") frappe.db.delete(table, filters=( - table.creation < Now() - Interval(days=self.clear_error_log_after) + table.creation < PseudoColumn(f"({Now() - Interval(days=self.clear_error_log_after)})") )) def clear_activity_logs(self): diff --git a/frappe/translate.py b/frappe/translate.py index f6a3880774..d0208bd379 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -21,6 +21,7 @@ import frappe from frappe.model.utils import InvalidIncludePath, render_include from frappe.utils import get_bench_path, is_html, strip, strip_html_tags from frappe.query_builder import Field +from pypika.terms import PseudoColumn def get_language(lang_list: List = None) -> str: @@ -153,12 +154,35 @@ def get_dict(fortype, name=None): messages += get_messages_from_navbar() messages += get_messages_from_include_files() - messages += frappe.qb.from_("Print Format").select("Print Format:", "name").run() - messages += frappe.qb.from_("DocType").select("DocType:", "name").run() - messages += frappe.qb.from_("Role").select("Role:", "name").run() - messages += frappe.qb.from_("Module Def").select("Module:", "name").run() - messages += frappe.qb.from_("Workspace Shortcut").where(Field("format").isnotnull()).select("").run() - messages += frappe.qb.from_("Onboarding Step").select("", "title").run() + messages += ( + frappe.qb.from_("Print Format") + .select(PseudoColumn("'Print Format:'"), "name") + .run() + ) + messages += ( + frappe.qb.from_("DocType") + .select(PseudoColumn("'DocType:'"), "name") + .run() + ) + messages += ( + frappe.qb.from_("Role").select(PseudoColumn("'Role:'"), "name").run() + ) + messages += ( + frappe.qb.from_("Module Def") + .select(PseudoColumn("'Module:'"), "name") + .run() + ) + messages += ( + frappe.qb.from_("Workspace Shortcut") + .where(Field("format").isnotnull()) + .select(PseudoColumn("''"), "format") + .run() + ) + messages += ( + frappe.qb.from_("Onboarding Step") + .select(PseudoColumn("''"), "title") + .run() + ) messages = deduplicate_messages(messages) message_dict = make_dict_from_messages(messages, load_user_translation=False) From a39e4290050e18544a53b88d65d33d0fec2193cf Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 19 Oct 2021 15:38:28 +0530 Subject: [PATCH 043/108] refactor: move max_writes constant to a class var --- frappe/database/database.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index e98cc22f41..d26a7dfc04 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -37,6 +37,7 @@ class Database(object): STANDARD_VARCHAR_COLUMNS = ('name', 'owner', 'modified_by', 'parent', 'parentfield', 'parenttype') DEFAULT_COLUMNS = ['name', 'creation', 'modified', 'modified_by', 'owner', 'docstatus', 'parent', 'parentfield', 'parenttype', 'idx'] + MAX_WRITES_PER_TRANSACTION = 200_000 class InvalidColumnName(frappe.ValidationError): pass @@ -262,7 +263,7 @@ class Database(object): if query[:6].lower() in ('update', 'insert', 'delete'): self.transaction_writes += 1 - if self.transaction_writes > 200000: + if self.transaction_writes > self.MAX_WRITES_PER_TRANSACTION: if self.auto_commit_on_many_writes: self.commit() else: From c31bf0aadc1fd1f3cb020cac292971a25552f58f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 19 Oct 2021 15:45:40 +0530 Subject: [PATCH 044/108] fix: Page number - simpler configuration - remove arbitrary margin text configuration --- .../doctype/print_format/print_format.json | 10 +- .../js/print_format_builder/MarginText.vue | 114 ------------------ .../js/print_format_builder/PrintFormat.vue | 43 +++++-- .../PrintFormatControls.vue | 30 +++++ .../templates/print_format/print_format.css | 19 ++- 5 files changed, 81 insertions(+), 135 deletions(-) delete mode 100644 frappe/public/js/print_format_builder/MarginText.vue diff --git a/frappe/printing/doctype/print_format/print_format.json b/frappe/printing/doctype/print_format/print_format.json index ab13c28f3b..75ec0fa7fd 100644 --- a/frappe/printing/doctype/print_format/print_format.json +++ b/frappe/printing/doctype/print_format/print_format.json @@ -30,6 +30,7 @@ "column_break_11", "font_size", "font", + "page_number", "css_section", "css", "custom_html_help", @@ -245,13 +246,20 @@ "fieldname": "font_size", "fieldtype": "Int", "label": "Font Size" + }, + { + "default": "Hide", + "fieldname": "page_number", + "fieldtype": "Select", + "label": "Page Number", + "options": "Hide\nTop Left\nTop Center\nTop Right\nBottom Left\nBottom Center\nBottom Right" } ], "icon": "fa fa-print", "idx": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2021-09-07 09:47:57.119820", + "modified": "2021-10-12 17:52:41.167107", "modified_by": "Administrator", "module": "Printing", "name": "Print Format", diff --git a/frappe/public/js/print_format_builder/MarginText.vue b/frappe/public/js/print_format_builder/MarginText.vue deleted file mode 100644 index 85229d2d42..0000000000 --- a/frappe/public/js/print_format_builder/MarginText.vue +++ /dev/null @@ -1,114 +0,0 @@ - - - diff --git a/frappe/public/js/print_format_builder/PrintFormat.vue b/frappe/public/js/print_format_builder/PrintFormat.vue index 7163282067..5138a54a38 100644 --- a/frappe/public/js/print_format_builder/PrintFormat.vue +++ b/frappe/public/js/print_format_builder/PrintFormat.vue @@ -1,11 +1,6 @@