diff --git a/frappe/core/doctype/data_export/exporter.py b/frappe/core/doctype/data_export/exporter.py index 366245b5e8..bc67087151 100644 --- a/frappe/core/doctype/data_export/exporter.py +++ b/frappe/core/doctype/data_export/exporter.py @@ -9,6 +9,7 @@ import frappe import frappe.permissions from frappe import _ from frappe.core.doctype.access_log.access_log import make_access_log +from frappe.model.utils import is_virtual_doctype from frappe.utils import cint, cstr, format_datetime, format_duration, formatdate, parse_json from frappe.utils.csvutils import UnicodeWriter @@ -390,6 +391,8 @@ class DataExporter: if self.all_doctypes: # add child tables for c in self.child_doctypes: + if is_virtual_doctype(c["doctype"]): + continue child_doctype_table = DocType(c["doctype"]) data_row = ( frappe.qb.from_(child_doctype_table) diff --git a/frappe/database/database.py b/frappe/database/database.py index c51a8f10a7..5eb4e17ac4 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -1222,7 +1222,7 @@ class Database: # multi_word_regex is designed to match following patterns # `tabXxx Xxx` and "tabXxx Xxx" - # ([`"]?) Captures " or ` at the begining of the table name (if provided) + # ([`"]?) Captures " or ` at the beginning of the table name (if provided) # \1 matches the first captured group (quote character) at the end of the table name # multi word table name must have surrounding quotes. diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js index b0a36aa2e8..cd9bdcdaa6 100644 --- a/frappe/public/js/frappe/form/controls/link.js +++ b/frappe/public/js/frappe/form/controls/link.js @@ -475,7 +475,7 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat let value = filter[3] == null || filter[3] === "" ? __("empty") : String(filter[3]); - return [__(label).bold(), filter[2], value.bold()].join(" "); + return [__(label).bold(), __(frappe.model.unscrub(filter[2])), value.bold()].join(" "); } let filter_string = filter_array.map(get_filter_description).join(", "); diff --git a/frappe/public/js/frappe/form/footer/form_timeline.js b/frappe/public/js/frappe/form/footer/form_timeline.js index d70da5f030..5514693c05 100644 --- a/frappe/public/js/frappe/form/footer/form_timeline.js +++ b/frappe/public/js/frappe/form/footer/form_timeline.js @@ -608,30 +608,26 @@ class FormTimeline extends BaseTimeline { } get_last_email(from_recipient) { - let last_email = null; - let communications = this.frm.get_docinfo().communications || []; - let email = this.get_recipient(); - // REDESIGN TODO: What is this? Check again - communications - .sort((a, b) => (a.creation > b.creation ? -1 : 1)) - .forEach((c) => { - if ( - c.communication_type === "Communication" && - c.communication_medium === "Email" - ) { - if (from_recipient) { - if (c.sender.indexOf(email) !== -1) { - last_email = c; - return false; - } - } else { - last_email = c; - return false; - } - } - }); + /** + * Return the latest email communication. + * + * @param {boolean} from_recipient If true, only considers emails where current form's recipient is the sender. + * @returns {object|null} The latest email communication, or null if no communication is found. + */ - return last_email; + const communications = this.frm.get_docinfo().communications || []; + const recipient = this.get_recipient(); + + const filtered_records = communications + .filter( + (record) => + record.communication_type === "Communication" && + record.communication_medium === "Email" && + (!from_recipient || record.sender === recipient) + ) + .sort((a, b) => b.creation - a.creation); + + return filtered_records[0] || null; } delete_comment(comment_name) { diff --git a/frappe/www/message.py b/frappe/www/message.py index b5035de20f..d8e359f07c 100644 --- a/frappe/www/message.py +++ b/frappe/www/message.py @@ -3,6 +3,7 @@ import frappe from frappe.utils import strip_html_tags +from frappe.utils.html_utils import clean_html no_cache = 1 @@ -26,9 +27,9 @@ def get_context(context): frappe.local.response["http_status_code"] = message["http_status_code"] if not message_context.title: - message_context.title = frappe.form_dict.title + message_context.title = clean_html(frappe.form_dict.title) if not message_context.message: - message_context.message = frappe.form_dict.message + message_context.message = clean_html(frappe.form_dict.message) return message_context