diff --git a/frappe/contacts/address_and_contact.py b/frappe/contacts/address_and_contact.py index 5a004f153b..51f13fb1a1 100644 --- a/frappe/contacts/address_and_contact.py +++ b/frappe/contacts/address_and_contact.py @@ -146,6 +146,7 @@ def delete_contact_and_address(doctype, docname): if len(doc.links)==1: doc.delete() +@frappe.whitelist() def filter_dynamic_link_doctypes(doctype, txt, searchfield, start, page_len, filters): if not txt: txt = "" diff --git a/frappe/contacts/doctype/address/address.py b/frappe/contacts/doctype/address/address.py index b85d578353..57dea8284c 100644 --- a/frappe/contacts/doctype/address/address.py +++ b/frappe/contacts/doctype/address/address.py @@ -230,6 +230,7 @@ def get_company_address(company): return ret +@frappe.whitelist() def address_query(doctype, txt, searchfield, start, page_len, filters): from frappe.desk.reportview import get_match_cond @@ -237,16 +238,17 @@ def address_query(doctype, txt, searchfield, start, page_len, filters): link_name = filters.pop('link_name') condition = "" - for fieldname, value in iteritems(filters): - condition += " and {field}={value}".format( - field=fieldname, - value=value - ) - meta = frappe.get_meta("Address") + for fieldname, value in iteritems(filters): + if meta.get_field(fieldname) or fieldname in frappe.db.DEFAULT_COLUMNS: + condition += " and {field}={value}".format( + field=fieldname, + value=frappe.db.escape(value)) + searchfields = meta.get_search_fields() - if searchfield: + if searchfield and (meta.get_field(searchfield)\ + or searchfield in frappe.db.DEFAULT_COLUMNS): searchfields.append(searchfield) search_condition = '' @@ -289,4 +291,4 @@ def get_condensed_address(doc): return ", ".join([doc.get(d) for d in fields if doc.get(d)]) def update_preferred_address(address, field): - frappe.db.set_value('Address', address, field, 0) \ No newline at end of file + frappe.db.set_value('Address', address, field, 0) diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py index 4cf209541c..8240940d2f 100644 --- a/frappe/contacts/doctype/contact/contact.py +++ b/frappe/contacts/doctype/contact/contact.py @@ -182,19 +182,17 @@ def update_contact(doc, method): contact.flags.ignore_mandatory = True contact.save(ignore_permissions=True) +@frappe.whitelist() def contact_query(doctype, txt, searchfield, start, page_len, filters): from frappe.desk.reportview import get_match_cond + if not frappe.get_meta("Contact").get_field(searchfield)\ + or searchfield not in frappe.db.DEFAULT_COLUMNS: + return [] + link_doctype = filters.pop('link_doctype') link_name = filters.pop('link_name') - condition = "" - for fieldname, value in iteritems(filters): - condition += " and {field}={value}".format( - field=fieldname, - value=value - ) - return frappe.db.sql("""select `tabContact`.name, `tabContact`.first_name, `tabContact`.last_name from @@ -209,9 +207,7 @@ def contact_query(doctype, txt, searchfield, start, page_len, filters): order by if(locate(%(_txt)s, `tabContact`.name), locate(%(_txt)s, `tabContact`.name), 99999), `tabContact`.idx desc, `tabContact`.name - limit %(start)s, %(page_len)s """.format( - mcond=get_match_cond(doctype), - key=searchfield), { + limit %(start)s, %(page_len)s """.format(mcond=get_match_cond(doctype), key=searchfield), { 'txt': '%' + txt + '%', '_txt': txt.replace("%", ""), 'start': start, diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js index 6d33d7717b..ee6eb3289d 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js @@ -176,7 +176,7 @@ frappe.ui.form.on('Dashboard Chart', { set_chart_field_options: function(frm) { let filters = frm.doc.filters_json.length > 2 ? JSON.parse(frm.doc.filters_json) : null; - if (frm.doc.dynamic_filters_json.length > 2) { + if (frm.doc.dynamic_filters_json && frm.doc.dynamic_filters_json.length > 2) { filters = frappe.dashboard_utils.get_all_filters(frm.doc); } frappe.xcall( diff --git a/frappe/desk/doctype/number_card/number_card.js b/frappe/desk/doctype/number_card/number_card.js index 8e05a28783..42899a4ebb 100644 --- a/frappe/desk/doctype/number_card/number_card.js +++ b/frappe/desk/doctype/number_card/number_card.js @@ -215,7 +215,7 @@ frappe.ui.form.on('Number Card', { set_report_field_options: function(frm) { let filters = frm.doc.filters_json.length > 2 ? JSON.parse(frm.doc.filters_json) : null; - if (frm.doc.dynamic_filters_json.length > 2) { + if (frm.doc.dynamic_filters_json && frm.doc.dynamic_filters_json.length > 2) { filters = frappe.dashboard_utils.get_all_filters(frm.doc); } frappe.xcall( diff --git a/frappe/email/doctype/email_account/email_account.js b/frappe/email/doctype/email_account/email_account.js index 71f9cccb0d..83896e0af7 100644 --- a/frappe/email/doctype/email_account/email_account.js +++ b/frappe/email/doctype/email_account/email_account.js @@ -95,6 +95,11 @@ frappe.ui.form.on("Email Account", { enable_incoming: function(frm) { frm.doc.no_remaining = null; //perform full sync //frm.set_df_property("append_to", "reqd", frm.doc.enable_incoming); + frm.trigger("warn_autoreply_on_incoming"); + }, + + enable_auto_reply: function(frm) { + frm.trigger("warn_autoreply_on_incoming"); }, notify_if_unreplied: function(frm) { @@ -184,7 +189,18 @@ frappe.ui.form.on("Email Account", { read as well as unread message from server. This may also cause the duplication\ of Communication (emails)."); frappe.confirm(msg, null, function() { - frm.set_value("email_sync_option", "ALL"); + frm.set_value("email_sync_option", "UNSEEN"); + }); + } + }, + + warn_autoreply_on_incoming: function(frm) { + if (frm.doc.enable_incoming && frm.doc.enable_auto_reply && frm.doc.__islocal) { + var msg = __("Enabling auto reply on an incoming email account will send automated replies \ + to all the synchronized emails. Do you wish to continue?"); + frappe.confirm(msg, null, function() { + frm.set_value("enable_auto_reply", 0); + frappe.show_alert({message: __("Disabled Auto Reply"), indicator: "blue"}); }); } } diff --git a/frappe/public/css/email.css b/frappe/public/css/email.css index 40c6149927..5c398009ff 100644 --- a/frappe/public/css/email.css +++ b/frappe/public/css/email.css @@ -7,6 +7,12 @@ body { p { margin: 1em 0 !important; } +.ql-editor { + white-space: normal; +} +.ql-editor p { + margin: 0 !important; +} hr { border-top: 1px solid #d1d8dd; } diff --git a/frappe/public/js/frappe/form/controls/text_editor.js b/frappe/public/js/frappe/form/controls/text_editor.js index e367989b81..3fe0b60ae0 100644 --- a/frappe/public/js/frappe/form/controls/text_editor.js +++ b/frappe/public/js/frappe/form/controls/text_editor.js @@ -69,7 +69,6 @@ Quill.register(CustomColor, true); frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ make_wrapper() { this._super(); - this.$wrapper.find(".like-disabled-input").addClass('ql-editor'); }, make_input() { @@ -201,6 +200,10 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ let value = this.quill ? this.quill.root.innerHTML : ''; // hack to retain space sequence. value = value.replace(/(\s)(\s)/g, ' '); + + if (!$(value).find('.ql-editor').length) { + value = `
" + (value==null ? "" : $("").text(value).html()) + ""
diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js
index f5a06311e9..f4bcecc68e 100644
--- a/frappe/public/js/frappe/form/grid_row.js
+++ b/frappe/public/js/frappe/form/grid_row.js
@@ -392,8 +392,11 @@ export default class GridRow {
// sync get_query
field.get_query = this.grid.get_field(df.fieldname).get_query;
- field.df.onchange = function() {
- me.grid.grid_rows[this.doc.idx-1].refresh_field(this.df.fieldname);
+
+ var field_on_change_function = field.df.onchange;
+ field.df.onchange = function(e) {
+ field_on_change_function && field_on_change_function(e);
+ me.grid.grid_rows[this.doc.idx - 1].refresh_field(this.df.fieldname);
};
field.refresh();
if(field.$input) {
diff --git a/frappe/public/js/frappe/form/templates/form_sidebar.html b/frappe/public/js/frappe/form/templates/form_sidebar.html
index 1f5c8b5cf6..67e674b1c1 100644
--- a/frappe/public/js/frappe/form/templates/form_sidebar.html
+++ b/frappe/public/js/frappe/form/templates/form_sidebar.html
@@ -111,7 +111,7 @@
{% if(frappe.get_form_sidebar_extension) { %}
- {{ frappe.get_form_sidebar_extension() }}
+ {{ frappe.get_form_sidebar_extension() }}
{% } %}
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index 53d946f75d..29b21242af 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -44,26 +44,6 @@ frappe.views.CommunicationComposer = Class.extend({
}
});
- $(document).on("upload_complete", function(event, attachment) {
- if(me.dialog.display) {
- var wrapper = $(me.dialog.fields_dict.select_attachments.wrapper);
-
- // find already checked items
- var checked_items = wrapper.find('[data-file-name]:checked').map(function() {
- return $(this).attr("data-file-name");
- });
-
- // reset attachment list
- me.render_attach();
-
- // check latest added
- checked_items.push(attachment.name);
-
- $.each(checked_items, function(i, filename) {
- wrapper.find('[data-file-name="'+ filename +'"]').prop("checked", true);
- });
- }
- })
this.prepare();
this.dialog.show();
@@ -387,77 +367,86 @@ frappe.views.CommunicationComposer = Class.extend({
folder: 'Home/Attachments',
on_success: attachment => {
this.attachments.push(attachment);
- this.render_attach();
+ this.render_attachment_rows(attachment);
}
};
- if(this.frm) {
+ if (this.frm) {
args = {
doctype: this.frm.doctype,
docname: this.frm.docname,
folder: 'Home/Attachments',
on_success: attachment => {
this.frm.attachments.attachment_uploaded(attachment);
- this.render_attach();
+ this.render_attachment_rows(attachment);
}
- }
+ };
}
- $(""
- +__("Select Attachments")+"
\
- ").appendTo(attach.empty())
+ $(`
+
+ ${__("Select Attachments")}
+
+
+
+ `).appendTo(attach.empty());
+
attach
.find(".add-more-attachments a")
- .on('click',() => new frappe.ui.FileUploader(args));
- this.render_attach();
+ .on('click', () => new frappe.ui.FileUploader(args));
+ this.render_attachment_rows();
},
- render_attach:function(){
- var fields = this.dialog.fields_dict;
- var attach = $(fields.select_attachments.wrapper).find(".attach-list").empty();
- var files = [];
- if (this.attachments && this.attachments.length) {
- files = files.concat(this.attachments);
- }
- if (cur_frm) {
- files = files.concat(cur_frm.get_files());
- }
+ render_attachment_rows: function(attachment) {
+ const select_attachments = this.dialog.fields_dict.select_attachments;
+ const attachment_rows = $(select_attachments.wrapper).find(".attach-list");
+ if (attachment) {
+ attachment_rows.append(this.get_attachment_row(attachment, true));
+ } else {
+ let files = [];
+ if (this.attachments && this.attachments.length) {
+ files = files.concat(this.attachments);
+ }
+ if (this.frm) {
+ files = files.concat(this.frm.get_files());
+ }
- if(files.length) {
- $.each(files, function(i, f) {
- if (!f.file_name) return;
- f.file_url = frappe.urllib.get_full_url(f.file_url);
-
- $(repl(''
- + '
', f))
- .appendTo(attach)
- });
- }
- this.select_attachments();
- },
- select_attachments:function(){
- let me = this;
- if(me.dialog.display) {
- let wrapper = $(me.dialog.fields_dict.select_attachments.wrapper);
-
- let unchecked_items = wrapper.find('[data-file-name]:not(:checked)').map(function() {
- return $(this).attr("data-file-name");
- });
-
- $.each(unchecked_items, function(i, filename) {
- wrapper.find('[data-file-name="'+ filename +'"]').prop("checked", true);
- });
+ if (files.length) {
+ $.each(files, (i, f) => {
+ if (!f.file_name) return;
+ if (!attachment_rows.find(`[data-file-name="${f.name}"]`).length) {
+ f.file_url = frappe.urllib.get_full_url(f.file_url);
+ attachment_rows.append(this.get_attachment_row(f));
+ }
+ });
+ }
}
},
+
+ get_attachment_row(attachment, checked) {
+ return $(`
+
+
`);
+ },
+
setup_email: function() {
// email
- var me = this;
var fields = this.dialog.fields_dict;
if(this.attach_document_print) {
diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js
index 9e7e5cbdd6..95a3577698 100644
--- a/frappe/public/js/frappe/views/reports/report_view.js
+++ b/frappe/public/js/frappe/views/reports/report_view.js
@@ -768,10 +768,12 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
const index = this.fields.findIndex(f => column.field === f[0]);
if (index === -1) return;
const field = this.fields[index];
- if (field[0] === 'name' && this.group_by === null) {
+
+ if (field[0] === 'name') {
this.refresh();
frappe.throw(__('Cannot remove ID field'));
}
+
this.fields.splice(index, 1);
this.build_fields();
this.setup_columns();
@@ -850,7 +852,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
columns: 2,
options: columns[this.doctype]
.filter(df => {
- return !df.hidden;
+ return !df.hidden && df.fieldname !== 'name';
})
.map(df => ({
label: __(df.label),
diff --git a/frappe/public/less/email.less b/frappe/public/less/email.less
index b6d9540586..bf0507138b 100644
--- a/frappe/public/less/email.less
+++ b/frappe/public/less/email.less
@@ -10,6 +10,13 @@ p {
margin: 1em 0 !important;
}
+.ql-editor {
+ white-space: normal;
+ p {
+ margin: 0 !important;
+ }
+}
+
hr {
border-top: 1px solid @border-color;
}
@@ -210,4 +217,4 @@ hr {
.report-title {
margin-bottom: 20px;
}
-/* csslint ignore:end */
+/* csslint ignore:end */
\ No newline at end of file
diff --git a/frappe/public/less/form_grid.less b/frappe/public/less/form_grid.less
index 5cb04a252c..d9e7d8bceb 100644
--- a/frappe/public/less/form_grid.less
+++ b/frappe/public/less/form_grid.less
@@ -98,6 +98,10 @@
text-align: right;
}
+.grid-row .grid-row-check {
+ margin-top: 12px;
+}
+
.grid-row > .row {
.col:last-child {
margin-right: -10px;
diff --git a/frappe/public/less/quill.less b/frappe/public/less/quill.less
index 98c762bb4a..514d8993cd 100644
--- a/frappe/public/less/quill.less
+++ b/frappe/public/less/quill.less
@@ -78,7 +78,7 @@
}
}
-.ql-editor .mention {
+.ql-editor:not(.read-mode) .mention {
height: auto;
width: auto;
border-radius: 10px;
@@ -133,3 +133,7 @@
margin-top: 0px;
margin-bottom: 0px;
}
+
+.ql-editor.read-mode {
+ padding: 0;
+}
\ No newline at end of file
diff --git a/frappe/public/scss/website.scss b/frappe/public/scss/website.scss
index c89641b238..3c11d23252 100644
--- a/frappe/public/scss/website.scss
+++ b/frappe/public/scss/website.scss
@@ -1,3 +1,4 @@
+@import '~quill/dist/quill.core';
@import 'variables';
@import 'frappe/public/css/font-awesome';
@import '~bootstrap/scss/bootstrap';
@@ -11,6 +12,20 @@
@import 'portal';
@import 'doc';
+.ql-editor.read-mode {
+ padding: 0;
+ line-height: 1.6;
+
+ h1,
+ h2,
+ h3,
+ h4,
+ h5 {
+ margin-top: 0.5em;
+ margin-bottom: 0.25em;
+ }
+}
+
.container {
padding-left: 1.25rem;
padding-right: 1.25rem;
@@ -338,4 +353,4 @@ h5.modal-title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
-}
\ No newline at end of file
+}
diff --git a/frappe/templates/base.html b/frappe/templates/base.html
index 0b82b3dac2..8c843a44a4 100644
--- a/frappe/templates/base.html
+++ b/frappe/templates/base.html
@@ -42,7 +42,11 @@
{{ head_include or "" }}
{% endblock -%}
- {%- block style %}{%- endblock -%}
+ {%- block style %}
+ {% if colocated_css -%}
+
+ {%- endif %}
+ {%- endblock -%}
{%- endfor -%}
- {%- block script %}{%- endblock %}
+ {%- block script %}
+ {% if colocated_js -%}
+
+ {%- endif %}
+ {%- endblock %}
{%- block body_include %}{{ body_include or "" }}{% endblock -%}