[enhance] communication inbox viewversion-14
@@ -3,14 +3,6 @@ from frappe import _ | |||||
def get_data(): | def get_data(): | ||||
return [ | return [ | ||||
{ | |||||
"module_name": "Email", | |||||
"color": "grey", | |||||
"icon": "octicon octicon-mail", | |||||
"type": "page", | |||||
"link": "email_inbox", | |||||
"label": _("Email Inbox") | |||||
}, | |||||
{ | { | ||||
"module_name": "Desk", | "module_name": "Desk", | ||||
"label": _("Tools"), | "label": _("Tools"), | ||||
@@ -58,21 +58,36 @@ frappe.ui.form.on("Communication", { | |||||
&& frm.doc.communication_medium == "Email" | && frm.doc.communication_medium == "Email" | ||||
&& frm.doc.sent_or_received == "Received") { | && frm.doc.sent_or_received == "Received") { | ||||
frm.add_custom_button(__("Mark as {0}", [frm.doc.seen? "Unread": "Read"]), function() { | |||||
frm.trigger('mark_as_read_unread'); | |||||
}, "Actions"); | |||||
frm.add_custom_button(__("Reply"), function() { | frm.add_custom_button(__("Reply"), function() { | ||||
frm.trigger('reply'); | frm.trigger('reply'); | ||||
}, "Actions"); | |||||
}); | |||||
frm.add_custom_button(__("Reply-All"), function() { | |||||
frm.add_custom_button(__("Reply All"), function() { | |||||
frm.trigger('reply_all'); | frm.trigger('reply_all'); | ||||
}, "Actions"); | }, "Actions"); | ||||
frm.add_custom_button(__("Forward"), function() { | frm.add_custom_button(__("Forward"), function() { | ||||
frm.trigger('forward_mail'); | frm.trigger('forward_mail'); | ||||
}, "Actions"); | }, "Actions"); | ||||
frm.add_custom_button(__("Mark as {0}", [frm.doc.seen? "Unread": "Read"]), function() { | |||||
frm.trigger('mark_as_read_unread'); | |||||
}, "Actions"); | |||||
frm.add_custom_button(__("Add Contact"), function() { | |||||
frm.trigger('add_to_contact'); | |||||
}, "Actions"); | |||||
if(frm.doc.email_status != "Spam") | |||||
frm.add_custom_button(__("Mark as Spam"), function() { | |||||
frm.trigger('mark_as_spam'); | |||||
}, "Actions"); | |||||
if(frm.doc.email_status != "Trash") { | |||||
frm.add_custom_button(__("Move To Trash"), function() { | |||||
frm.trigger('move_to_trash'); | |||||
}, "Actions"); | |||||
} | |||||
} | } | ||||
}, | }, | ||||
show_relink_dialog: function(frm){ | show_relink_dialog: function(frm){ | ||||
@@ -183,5 +198,48 @@ frappe.ui.form.on("Communication", { | |||||
sender: sender_email_id, | sender: sender_email_id, | ||||
attachments: frm.doc.attachments | attachments: frm.doc.attachments | ||||
} | } | ||||
}, | |||||
add_to_contact: function(frm) { | |||||
var me = this; | |||||
fullname = frm.doc.sender_full_name || "" | |||||
names = fullname.split(" ") | |||||
first_name = names[0] | |||||
last_name = names.length >= 2? names[names.length - 1]: "" | |||||
frappe.route_options = { | |||||
"email_id": frm.doc.sender, | |||||
"first_name": first_name, | |||||
"last_name": last_name, | |||||
} | |||||
frappe.new_doc("Contact") | |||||
}, | |||||
mark_as_spam: function(frm) { | |||||
frappe.call({ | |||||
method: "frappe.email.inbox.mark_as_spam", | |||||
args: { | |||||
communication: frm.doc.name, | |||||
sender: frm.doc.sender | |||||
}, | |||||
freeze: true, | |||||
callback: function(r) { | |||||
frappe.msgprint("Email has been marked as spam") | |||||
} | |||||
}) | |||||
}, | |||||
move_to_trash: function(frm) { | |||||
frappe.call({ | |||||
method: "frappe.email.inbox.mark_as_trash", | |||||
args: { | |||||
communication: frm.doc.name | |||||
}, | |||||
freeze: true, | |||||
callback: function(r) { | |||||
frappe.msgprint("Email has been moved to trash") | |||||
} | |||||
}) | |||||
} | } | ||||
}); | }); |
@@ -1223,13 +1223,42 @@ | |||||
"set_only_once": 0, | "set_only_once": 0, | ||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 1, | |||||
"columns": 0, | |||||
"fieldname": "uid", | |||||
"fieldtype": "Int", | |||||
"hidden": 1, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "UID", | |||||
"length": 0, | |||||
"no_copy": 1, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | { | ||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"fieldname": "signature", | |||||
"fieldtype": "Data", | |||||
"fieldname": "email_status", | |||||
"fieldtype": "Select", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
@@ -1237,7 +1266,37 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Signature", | |||||
"label": "Email Status", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "Open\nSpam\nTrash", | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "has_attachment", | |||||
"fieldtype": "Check", | |||||
"hidden": 1, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "Has Attachment", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"permlevel": 0, | "permlevel": 0, | ||||
@@ -1257,6 +1316,7 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
"columns": 0, | "columns": 0, | ||||
"depends_on": "eval: doc.rating > 0", | |||||
"fieldname": "feedback_section", | "fieldname": "feedback_section", | ||||
"fieldtype": "Section Break", | "fieldtype": "Section Break", | ||||
"hidden": 0, | "hidden": 0, | ||||
@@ -1363,7 +1423,7 @@ | |||||
"cancel": 0, | "cancel": 0, | ||||
"create": 1, | "create": 1, | ||||
"delete": 1, | "delete": 1, | ||||
"email": 0, | |||||
"email": 1, | |||||
"export": 0, | "export": 0, | ||||
"if_owner": 0, | "if_owner": 0, | ||||
"import": 0, | "import": 0, | ||||
@@ -1375,7 +1435,7 @@ | |||||
"set_user_permissions": 0, | "set_user_permissions": 0, | ||||
"share": 1, | "share": 1, | ||||
"submit": 0, | "submit": 0, | ||||
"write": 1 | |||||
"write": 0 | |||||
}, | }, | ||||
{ | { | ||||
"amend": 0, | "amend": 0, | ||||
@@ -1403,7 +1463,7 @@ | |||||
"cancel": 0, | "cancel": 0, | ||||
"create": 0, | "create": 0, | ||||
"delete": 0, | "delete": 0, | ||||
"email": 0, | |||||
"email": 1, | |||||
"export": 0, | "export": 0, | ||||
"if_owner": 1, | "if_owner": 1, | ||||
"import": 0, | "import": 0, | ||||
@@ -1416,16 +1476,16 @@ | |||||
"share": 0, | "share": 0, | ||||
"submit": 0, | "submit": 0, | ||||
"user_permission_doctypes": "[\"Email Account\"]", | "user_permission_doctypes": "[\"Email Account\"]", | ||||
"write": 1 | |||||
"write": 0 | |||||
} | } | ||||
], | ], | ||||
"quick_entry": 0, | "quick_entry": 0, | ||||
"read_only": 0, | "read_only": 0, | ||||
"read_only_onload": 0, | "read_only_onload": 0, | ||||
"search_fields": "subject", | "search_fields": "subject", | ||||
"show_name_in_global_search": 1, | |||||
"show_name_in_global_search": 0, | |||||
"sort_order": "DESC", | "sort_order": "DESC", | ||||
"title_field": "subject", | "title_field": "subject", | ||||
"track_changes": 1, | "track_changes": 1, | ||||
"track_seen": 0 | |||||
"track_seen": 1 | |||||
} | } |
@@ -22,19 +22,22 @@ class Communication(Document): | |||||
"""Communication represents an external communication like Email.""" | """Communication represents an external communication like Email.""" | ||||
def onload(self): | def onload(self): | ||||
"""create email flag queue""" | """create email flag queue""" | ||||
flag = frappe.db.get_value("Email Flag Queue", { | |||||
"communication": self.name, | |||||
"is_completed": 0}) | |||||
if flag: | |||||
return | |||||
frappe.get_doc({ | |||||
"doctype": "Email Flag Queue", | |||||
"action": "Read", | |||||
"communication": self.name, | |||||
"flag": "(\\SEEN)" | |||||
}).insert(ignore_permissions=True) | |||||
frappe.db.commit() | |||||
if self.communication_type == "Communication" and self.communication_medium == "Email" \ | |||||
and self.sent_or_received == "Received": | |||||
flag = frappe.db.get_value("Email Flag Queue", { | |||||
"communication": self.name, | |||||
"is_completed": 0}) | |||||
if flag: | |||||
return | |||||
frappe.get_doc({ | |||||
"doctype": "Email Flag Queue", | |||||
"action": "Read", | |||||
"communication": self.name, | |||||
"flag": "(\\SEEN)" | |||||
}).insert(ignore_permissions=True) | |||||
frappe.db.commit() | |||||
def validate(self): | def validate(self): | ||||
if self.reference_doctype and self.reference_name: | if self.reference_doctype and self.reference_name: | ||||
@@ -64,6 +67,10 @@ class Communication(Document): | |||||
def after_insert(self): | def after_insert(self): | ||||
if not (self.reference_doctype and self.reference_name): | if not (self.reference_doctype and self.reference_name): | ||||
return | return | ||||
if self.reference_doctype == "Communication" and self.sent_or_received == "Sent": | |||||
frappe.db.set_value("Communication", self.reference_name, "status", "Replied") | |||||
if self.communication_type in ("Communication", "Comment"): | if self.communication_type in ("Communication", "Comment"): | ||||
# send new comment to listening clients | # send new comment to listening clients | ||||
frappe.publish_realtime('new_communication', self.as_dict(), | frappe.publish_realtime('new_communication', self.as_dict(), | ||||
@@ -113,6 +120,13 @@ class Communication(Document): | |||||
else: | else: | ||||
self.status = "Closed" | self.status = "Closed" | ||||
# set email status to spam | |||||
email_rule = frappe.db.get_value("Email Rule", { "email_id": self.sender, "is_spam":1 }) | |||||
if self.communication_type == "Communication" and self.communication_medium == "Email" \ | |||||
and self.sent_or_received == "Sent" and email_rule: | |||||
self.email_status = "Spam" | |||||
def set_sender_full_name(self): | def set_sender_full_name(self): | ||||
if not self.sender_full_name and self.sender: | if not self.sender_full_name and self.sender: | ||||
if self.sender == "Administrator": | if self.sender == "Administrator": | ||||
@@ -2,7 +2,7 @@ frappe.listview_settings['Communication'] = { | |||||
add_fields: [ | add_fields: [ | ||||
"sent_or_received","recipients", "subject", | "sent_or_received","recipients", "subject", | ||||
"communication_medium", "communication_type", | "communication_medium", "communication_type", | ||||
"sender", "seen" | |||||
"sender", "seen", "reference_doctype", "reference_name" | |||||
], | ], | ||||
filters: [["status", "=", "Open"]], | filters: [["status", "=", "Open"]], | ||||
@@ -16,6 +16,7 @@ def get_notification_config(): | |||||
"for_other": { | "for_other": { | ||||
"Likes": "frappe.core.notifications.get_unseen_likes", | "Likes": "frappe.core.notifications.get_unseen_likes", | ||||
"Chat": "frappe.core.notifications.get_unread_messages", | "Chat": "frappe.core.notifications.get_unread_messages", | ||||
"Email": "frappe.core.notifications.get_unread_emails", | |||||
} | } | ||||
} | } | ||||
@@ -63,3 +64,19 @@ def get_unseen_likes(): | |||||
and owner is not null and owner!=%(user)s | and owner is not null and owner!=%(user)s | ||||
and reference_owner=%(user)s | and reference_owner=%(user)s | ||||
and seen=0""", {"user": frappe.session.user})[0][0] | and seen=0""", {"user": frappe.session.user})[0][0] | ||||
def get_unread_emails(): | |||||
"returns unread emails for a user" | |||||
return frappe.db.sql("""\ | |||||
SELECT count(*) | |||||
FROM `tabCommunication` | |||||
WHERE communication_type='Communication' | |||||
AND communication_medium="Email" | |||||
AND email_status not in ("Spam", "Trash") | |||||
AND email_account in ( | |||||
SELECT distinct email_account from `tabUser Email` WHERE parent=%(user)s | |||||
) | |||||
AND modified >= DATE_SUB(NOW(),INTERVAL 1 YEAR) | |||||
AND seen=0 | |||||
""", {"user": frappe.session.user})[0][0] |
@@ -43,9 +43,21 @@ $.extend(frappe.desktop, { | |||||
link: 'modules' | link: 'modules' | ||||
}; | }; | ||||
explore_icon.app_icon = frappe.ui.app_icon.get_html(explore_icon); | explore_icon.app_icon = frappe.ui.app_icon.get_html(explore_icon); | ||||
all_icons.push(explore_icon); | all_icons.push(explore_icon); | ||||
var inbox_icon = { | |||||
module_name: 'Communication', | |||||
label: 'Email Inbox', | |||||
_label: __('Email Inbox'), | |||||
_id: 'Email Inbox', | |||||
_doctype: 'Communication', | |||||
icon: 'fa fa-envelope-o', | |||||
color: '#589494', | |||||
link: 'List/Communication/Inbox' | |||||
} | |||||
inbox_icon.app_icon = frappe.ui.app_icon.get_html(inbox_icon) | |||||
all_icons.push(inbox_icon); | |||||
frappe.desktop.wrapper.html(frappe.render_template(template, { | frappe.desktop.wrapper.html(frappe.render_template(template, { | ||||
// all visible icons | // all visible icons | ||||
desktop_items: all_icons, | desktop_items: all_icons, | ||||
@@ -569,7 +569,6 @@ class EmailAccount(Document): | |||||
if self.email_sync_option == "ALL": | if self.email_sync_option == "ALL": | ||||
max_uid = get_max_email_uid(self.name) | max_uid = get_max_email_uid(self.name) | ||||
last_uid = max_uid + int(self.initial_sync_count or 100) if max_uid == 1 else "*" | last_uid = max_uid + int(self.initial_sync_count or 100) if max_uid == 1 else "*" | ||||
print "UID {}:{}".format(max_uid, last_uid) | |||||
return "UID {}:{}".format(max_uid, last_uid) | return "UID {}:{}".format(max_uid, last_uid) | ||||
else: | else: | ||||
return self.email_sync_option or "UNSEEN" | return self.email_sync_option or "UNSEEN" | ||||
@@ -1,5 +1,6 @@ | |||||
{ | { | ||||
"allow_copy": 1, | "allow_copy": 1, | ||||
"allow_guest_to_view": 0, | |||||
"allow_import": 0, | "allow_import": 0, | ||||
"allow_rename": 0, | "allow_rename": 0, | ||||
"beta": 0, | "beta": 0, | ||||
@@ -45,7 +46,7 @@ | |||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"fieldname": "communication", | "fieldname": "communication", | ||||
"fieldtype": "Link", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
@@ -56,7 +57,7 @@ | |||||
"label": "Communication", | "label": "Communication", | ||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"options": "Communication", | |||||
"options": "", | |||||
"permlevel": 0, | "permlevel": 0, | ||||
"precision": "", | "precision": "", | ||||
"print_hide": 0, | "print_hide": 0, | ||||
@@ -129,17 +130,17 @@ | |||||
"unique": 0 | "unique": 0 | ||||
} | } | ||||
], | ], | ||||
"has_web_view": 0, | |||||
"hide_heading": 0, | "hide_heading": 0, | ||||
"hide_toolbar": 0, | "hide_toolbar": 0, | ||||
"idx": 0, | "idx": 0, | ||||
"image_view": 0, | "image_view": 0, | ||||
"in_create": 1, | "in_create": 1, | ||||
"in_dialog": 0, | |||||
"is_submittable": 0, | "is_submittable": 0, | ||||
"issingle": 0, | "issingle": 0, | ||||
"istable": 0, | "istable": 0, | ||||
"max_attachments": 0, | "max_attachments": 0, | ||||
"modified": "2017-03-01 05:24:47.756892", | |||||
"modified": "2017-03-13 07:54:07.987640", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"module": "Email", | "module": "Email", | ||||
"name": "Email Flag Queue", | "name": "Email Flag Queue", | ||||
@@ -0,0 +1,8 @@ | |||||
// Copyright (c) 2017, Frappe Technologies and contributors | |||||
// For license information, please see license.txt | |||||
frappe.ui.form.on('Email Rule', { | |||||
refresh: function(frm) { | |||||
} | |||||
}); |
@@ -0,0 +1,122 @@ | |||||
{ | |||||
"allow_copy": 1, | |||||
"allow_guest_to_view": 0, | |||||
"allow_import": 0, | |||||
"allow_rename": 0, | |||||
"autoname": "field:email_id", | |||||
"beta": 0, | |||||
"creation": "2017-03-13 09:20:56.387135", | |||||
"custom": 0, | |||||
"docstatus": 0, | |||||
"doctype": "DocType", | |||||
"document_type": "", | |||||
"editable_grid": 1, | |||||
"engine": "InnoDB", | |||||
"fields": [ | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "email_id", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "Email ID", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "Email", | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "is_spam", | |||||
"fieldtype": "Check", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "Is Spam", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
} | |||||
], | |||||
"has_web_view": 0, | |||||
"hide_heading": 0, | |||||
"hide_toolbar": 0, | |||||
"idx": 0, | |||||
"image_view": 0, | |||||
"in_create": 1, | |||||
"is_submittable": 0, | |||||
"issingle": 0, | |||||
"istable": 0, | |||||
"max_attachments": 0, | |||||
"modified": "2017-03-13 09:26:38.441858", | |||||
"modified_by": "Administrator", | |||||
"module": "Email", | |||||
"name": "Email Rule", | |||||
"name_case": "", | |||||
"owner": "Administrator", | |||||
"permissions": [ | |||||
{ | |||||
"amend": 0, | |||||
"apply_user_permissions": 0, | |||||
"cancel": 0, | |||||
"create": 0, | |||||
"delete": 0, | |||||
"email": 1, | |||||
"export": 1, | |||||
"if_owner": 0, | |||||
"import": 0, | |||||
"permlevel": 0, | |||||
"print": 1, | |||||
"read": 1, | |||||
"report": 1, | |||||
"role": "System Manager", | |||||
"set_user_permissions": 0, | |||||
"share": 1, | |||||
"submit": 0, | |||||
"write": 0 | |||||
} | |||||
], | |||||
"quick_entry": 1, | |||||
"read_only": 0, | |||||
"read_only_onload": 0, | |||||
"show_name_in_global_search": 0, | |||||
"sort_field": "modified", | |||||
"sort_order": "DESC", | |||||
"track_changes": 0, | |||||
"track_seen": 0 | |||||
} |
@@ -0,0 +1,10 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2017, Frappe Technologies and contributors | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
from frappe.model.document import Document | |||||
class EmailRule(Document): | |||||
pass |
@@ -0,0 +1,10 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2017, Frappe Technologies and Contributors | |||||
# See license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
import unittest | |||||
class TestEmailRule(unittest.TestCase): | |||||
pass |
@@ -17,20 +17,29 @@ def get_email_accounts(user=None): | |||||
"all_accounts": "" | "all_accounts": "" | ||||
} | } | ||||
email_accounts.append({ | |||||
"email_account": "Sent", | |||||
"email_id": "Sent Mail" | |||||
}) | |||||
all_accounts = ",".join([ account.get("email_account") for account in accounts ]) | all_accounts = ",".join([ account.get("email_account") for account in accounts ]) | ||||
if len(accounts) > 1: | if len(accounts) > 1: | ||||
email_accounts.append({ | email_accounts.append({ | ||||
"email_account": all_accounts, | "email_account": all_accounts, | ||||
"email_id": "All Accounts" | "email_id": "All Accounts" | ||||
}) | }) | ||||
email_accounts.extend(accounts) | email_accounts.extend(accounts) | ||||
email_accounts.extend([ | |||||
{ | |||||
"email_account": "Sent", | |||||
"email_id": "Sent Mail" | |||||
}, | |||||
{ | |||||
"email_account": "Spam", | |||||
"email_id": "Spam" | |||||
}, | |||||
{ | |||||
"email_account": "Trash", | |||||
"email_id": "Trash" | |||||
} | |||||
]) | |||||
return { | return { | ||||
"email_accounts": email_accounts, | "email_accounts": email_accounts, | ||||
"all_accounts": all_accounts | "all_accounts": all_accounts | ||||
@@ -77,3 +86,84 @@ def create_email_flag_queue(names, action, flag="(\\Seen)"): | |||||
update_modified=False) | update_modified=False) | ||||
except Found: | except Found: | ||||
pass | pass | ||||
@frappe.whitelist() | |||||
def mark_as_trash(communication): | |||||
"""set email status to trash""" | |||||
frappe.db.set_value("Communication", communication, "email_status", "Trash") | |||||
@frappe.whitelist() | |||||
def mark_as_spam(communication, sender): | |||||
""" set email status to spam """ | |||||
email_rule = frappe.db.get_value("Email Rule", { "email_id": sender }) | |||||
if not email_rule: | |||||
frappe.get_doc({ | |||||
"doctype": "Email Rule", | |||||
"email_id": sender, | |||||
"is_spam": 1 | |||||
}).insert(ignore_permissions=True) | |||||
frappe.db.set_value("Communication", communication, "email_status", "Spam") | |||||
def link_communication_to_document(doc, reference_doctype, reference_name, ignore_communication_links): | |||||
if not ignore_communication_links: | |||||
doc.reference_doctype = reference_doctype | |||||
doc.reference_name = reference_name | |||||
doc.status = "Linked" | |||||
doc.save(ignore_permissions=True) | |||||
@frappe.whitelist() | |||||
def make_issue_from_communication(communication, ignore_communication_links=False): | |||||
""" raise a issue from email """ | |||||
doc = frappe.get_doc("Communication", communication) | |||||
issue = frappe.get_doc({ | |||||
"doctype": "Issue", | |||||
"subject": doc.subject, | |||||
"raised_by": doc.sender | |||||
}).insert(ignore_permissions=True) | |||||
link_communication_to_document(doc, "Issue", issue.name, ignore_communication_links) | |||||
return issue.name | |||||
@frappe.whitelist() | |||||
def make_lead_from_communication(communication, ignore_communication_links=False): | |||||
""" raise a issue from email """ | |||||
doc = frappe.get_doc("Communication", communication) | |||||
frappe.errprint(doc.sender_full_name) | |||||
lead_name = frappe.db.get_value("Lead", {"email_id": doc.sender}) | |||||
if not lead_name: | |||||
lead = frappe.get_doc({ | |||||
"doctype": "Lead", | |||||
"lead_name": doc.sender_full_name, | |||||
"email_id": doc.sender | |||||
}) | |||||
lead.flags.ignore_mandatory = True | |||||
lead.flags.ignore_permissions = True | |||||
lead.insert() | |||||
lead_name = lead.name | |||||
link_communication_to_document(doc, "Lead", lead_name, ignore_communication_links) | |||||
return lead_name | |||||
@frappe.whitelist() | |||||
def make_opportunity_from_communication(communication, ignore_communication_links=False): | |||||
doc = frappe.get_doc("Communication", communication) | |||||
lead = doc.reference_name if doc.reference_doctype == "Lead" else None | |||||
if not lead: | |||||
lead = make_lead_from_communication(communication, ignore_communication_links=True) | |||||
enquiry_from = "Lead" | |||||
opportunity = frappe.get_doc({ | |||||
"doctype": "Opportunity", | |||||
"enquiry_from": enquiry_from, | |||||
"lead": lead | |||||
}).insert(ignore_permissions=True) | |||||
link_communication_to_document(doc, "Opportunity", opportunity.name, ignore_communication_links) | |||||
return opportunity.name |
@@ -1,84 +0,0 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
import json | |||||
from frappe.model.document import Document | |||||
from frappe.desk.form.load import get_attachments | |||||
@frappe.whitelist() | |||||
def get_email_content(name): | |||||
docinfo = frappe.desk.form.load.get_attachments("Communication", name) | |||||
content = frappe.db.get_value("Communication", name, "content") | |||||
return docinfo, content | |||||
@frappe.whitelist() | |||||
def create_flag_queue(names, action, flag): | |||||
names = json.loads(names) | |||||
class Found(Exception): | |||||
pass | |||||
for item in names: | |||||
if item.get("uid"): | |||||
state = frappe.db.get_value("Communication", item.get("name"), "seen") | |||||
frappe.errprint(state) | |||||
# check states are correct | |||||
if (action =='Read' and state == 0) or (action =='Unread' and state == 1): | |||||
try: | |||||
queue = frappe.db.sql("""select name, action, flag from `tabEmail Flag Queue` | |||||
where communication = %(name)s""", {"name":item.get("name")}, as_dict=True) | |||||
for q in queue: | |||||
# is same email with same flag | |||||
if q.flag == flag: | |||||
# to prevent flag local and server states being out of sync | |||||
if q.action != action: | |||||
frappe.delete_doc("Email Flag Queue", q.name) | |||||
raise Found | |||||
flag_queue = frappe.get_doc({ | |||||
"doctype": "Email Flag Queue", | |||||
"communication": item.get("name"), | |||||
"action": action, | |||||
"flag": flag | |||||
}) | |||||
flag_queue.save(ignore_permissions=True); | |||||
except Found: | |||||
pass | |||||
@frappe.whitelist() | |||||
def setnomatch(name): | |||||
frappe.db.set_value("Communication", name, "nomatch", 1, update_modified=False) | |||||
@frappe.whitelist() | |||||
def update_local_flags(names, field, val): | |||||
names = json.loads(names) | |||||
for d in names: | |||||
frappe.db.set_value("Communication", d.get("name"), field, val, update_modified=False) | |||||
@frappe.whitelist() | |||||
def get_accounts(user): | |||||
email_accounts = [] | |||||
accounts = frappe.get_all("User Email", filters={ "parent": user }, | |||||
fields=["email_account as account", "email_id as title"], | |||||
distinct=True, order_by="idx") | |||||
if not accounts: | |||||
return None | |||||
all_accounts = ",".join([ account.get("account") for account in accounts ]) | |||||
if len(accounts) > 1: | |||||
email_accounts.append({ | |||||
"account": all_accounts, | |||||
"title": "All Accounts" | |||||
}) | |||||
email_accounts.extend(accounts) | |||||
return { | |||||
"email_accounts": email_accounts, | |||||
"all_accounts": all_accounts | |||||
} |
@@ -1,665 +0,0 @@ | |||||
frappe.provide("frappe.email") | |||||
frappe.pages['email_inbox'].on_page_load = function(wrapper) { | |||||
frappe.ui.make_app_page({ | |||||
parent: wrapper, | |||||
title: 'Email Inbox', | |||||
icon: 'fa fa-inbox', | |||||
single_column: false | |||||
}); | |||||
frappe.model.with_doctype('Communication', function() { | |||||
wrapper.inbox = new frappe.email.EmailInbox({ | |||||
method: 'frappe.desk.reportview.get', | |||||
wrapper: wrapper, | |||||
page: wrapper.page, | |||||
no_loading: true | |||||
}); | |||||
}); | |||||
}; | |||||
frappe.pages['email_inbox'].refresh = function(wrapper) { | |||||
if (wrapper.inbox) { | |||||
wrapper.inbox.refresh() | |||||
} | |||||
}; | |||||
frappe.email.EmailInbox = frappe.ui.Listing.extend({ | |||||
init: function(opts) { | |||||
$.extend(this, opts); | |||||
wrap = this; | |||||
this.wrapper = opts.wrapper; | |||||
this.page_length = 20; | |||||
this.start = 0; | |||||
this.no_result_message = 'No Emails to Display'; | |||||
this.get_accounts(); | |||||
}, | |||||
setup_inbox: function() { | |||||
var me = this; | |||||
// setup listing | |||||
me.make({ | |||||
doctype: 'Communication', | |||||
page: me.page, | |||||
method: 'frappe.desk.reportview.get', | |||||
get_args: me.get_args, | |||||
parent: me.page.main, | |||||
start: 0, | |||||
show_filters: true | |||||
}); | |||||
this.render_sidebar(); | |||||
this.render_headers(); | |||||
this.render_buttons(); | |||||
this.init_select_all(); | |||||
this.setup_notifications(); | |||||
this.refresh(); | |||||
}, | |||||
get_accounts: function() { | |||||
// get all the configured email account for the user | |||||
var me = this; | |||||
frappe.call({ | |||||
method: 'frappe.email.page.email_inbox.get_accounts', | |||||
args: { | |||||
'user': user | |||||
}, | |||||
callback:function(r){ | |||||
me.page.sidebar.empty() | |||||
if(!r.message) { | |||||
frappe.msgprint(__("No Email Account assigned to you. Please contact your System Administrator")); | |||||
setTimeout(function() { | |||||
if (frappe.session.user==="Administrator") | |||||
frappe.set_route("List", "User"); | |||||
else | |||||
frappe.set_route(''); | |||||
}, 3000); | |||||
} | |||||
me.accounts = r.message; | |||||
me.setup_inbox(); | |||||
} | |||||
}); | |||||
}, | |||||
refresh:function(){ | |||||
delete frappe.route_flags.create_contact; | |||||
delete frappe.route_flags.update_contact; | |||||
this.run(); | |||||
}, | |||||
render_sidebar: function (data) { | |||||
var me = this; | |||||
frappe.call({ | |||||
method: 'frappe.email.page.email_inbox.get_accounts', | |||||
args:{user:frappe.user["name"]}, | |||||
async:false, | |||||
callback:function(list){ | |||||
var buttons = '<div class="layout-main-section overlay-sidebar">'; | |||||
if (list["message"]){ | |||||
me.accounts = []; | |||||
var rows = ""; | |||||
for (var i = 0;i<list["message"].length;i++) | |||||
{ | |||||
rows += '<div class="list-row inbox-select"> <div class="row"><a class="inbox-item ellipsis col-md-12" title ="'+list["message"][i]["email_id"]+'" data-account="'+list["message"][i]["email_account"]+'" style="margin-left: 10px;">'+list["message"][i]["email_id"]+'</a> </div></div>'; | |||||
me.accounts.push({name:list["message"][i]["email_account"],email:list["message"][i]["email_id"]}) | |||||
} | |||||
me.allaccounts = $.map(me.accounts,function(v){return v.name}).join(","); | |||||
buttons += '<div class="list-row inbox-select list-row-head" style="font-weight:bold"> <div class="row"><a class="inbox-item ellipsis col-md-12 " title ="All Accounts" data-account="'+me.allaccounts+'" style="margin-left: 10px;">All Accounts</a> </div></div>'; | |||||
buttons += rows; | |||||
buttons += '<div class="list-row inbox-select"> <div class="row"><a class="inbox-item ellipsis col-md-12 " title ="Sent" data-account="Sent" style="margin-left: 10px;">Sent</a> </div></div>'; | |||||
me.account = me.allaccounts; | |||||
me.default_filters=[ | |||||
["Communication", "communication_type", "=", "Communication"], | |||||
["Communication", "email_account", "in", me.account], | |||||
["Communication", "sent_or_received", "=", "Received"]] | |||||
me.page.sidebar.empty().append(buttons); | |||||
$(".inbox-select").on("click",function(btn){ | |||||
me.account = $(btn.currentTarget).find(".inbox-item").data("account"); | |||||
$(me.page.sidebar).find(".list-row").removeClass("list-row-head").css("font-weight","normal"); | |||||
$(btn.currentTarget).closest(".list-row").addClass("list-row-head").css("font-weight","bold"); | |||||
me.cur_page = 1; | |||||
$(me.page.main).find(".list-select-all,.list-row-checkbox").prop("checked",false); | |||||
me.toggle_actions(); | |||||
if(me.account=="Sent"){ | |||||
me.filter_list.default_filters=[ | |||||
["Communication", "communication_type", "=", "Communication"], | |||||
["Communication", "sent_or_received", "=", "Sent"]] | |||||
}else { | |||||
me.filter_list.default_filters = [ | |||||
["Communication", "communication_type", "=", "Communication"], | |||||
["Communication", "email_account", "in", me.account], | |||||
["Communication", "sent_or_received", "=", "Received"]]; | |||||
} | |||||
me.filter_list.clear_filters(); | |||||
if (me.filter_list.reload_stats){me.filter_list.reload_stats()} | |||||
me.refresh(); | |||||
}); | |||||
} | |||||
} | |||||
}) | |||||
}, | |||||
toggle_accounts: function() { | |||||
$(this.page.main).find(".list-select-all,.list-delete").prop("checked", false); | |||||
this.toggle_actions(); | |||||
this.filter_list.clear_filters(); | |||||
this.refresh(); | |||||
}, | |||||
render_headers: function(){ | |||||
$(".layout-main-section-wrapper").css("padding-left","0px").css("padding-right","0px"); | |||||
var data = { | |||||
"start":this.start, | |||||
"page_length":this.page_length.toString() | |||||
}; | |||||
headers_html = frappe.render_template("inbox_headers", data) | |||||
this.list_header = $(headers_html).appendTo(this.page.main.find(".list-headers")); | |||||
}, | |||||
get_args: function(){ | |||||
var args = { | |||||
doctype: this.doctype, | |||||
fields: [ | |||||
"name", "sender", "sender_full_name", "communication_date", "recipients", | |||||
"cc","communication_medium", "subject", "status" ,"reference_doctype", | |||||
"reference_name", "timeline_doctype", "timeline_name", "timeline_label", | |||||
"sent_or_received", "uid", "message_id", "seen" | |||||
], | |||||
filters: this.get_email_filters(), | |||||
order_by: 'communication_date desc', | |||||
save_list_settings: false | |||||
}; | |||||
return args; | |||||
}, | |||||
get_email_filters: function() { | |||||
filters = this.filter_list.get_filters() | |||||
if(this.account == "Sent") { | |||||
this.filter_list.default_filters = [ | |||||
["Communication", "communication_type", "=", "Communication"], | |||||
["Communication", "communication_medium", "=", "Email"], | |||||
["Communication", "user", "=", user], | |||||
["Communication", "sent_or_received", "=", "Sent"] | |||||
] | |||||
} else { | |||||
this.filter_list.default_filters = [ | |||||
["Communication", "communication_type", "=", "Communication"], | |||||
["Communication", "communication_medium", "=", "Email"], | |||||
["Communication", "sent_or_received", "=", "Received"], | |||||
["Communication", "email_account", "in", this.account], | |||||
] | |||||
} | |||||
$.extend(filters, this.filter_list.default_filters) | |||||
return filters; | |||||
}, | |||||
setup_notifications: function() { | |||||
// setup real time email notification using frappe.realtime | |||||
var me = this; | |||||
frappe.realtime.on("new_email", function(data) { | |||||
for(var i =0; i<me.accounts.length; i++) { | |||||
if (data.account == me.accounts[i].name) { | |||||
frappe.utils.notify(data.account, "you have "+data.number+" new emails", {}, function () { | |||||
window.focus(); | |||||
me.account = data.account; | |||||
$(me.page.sidebar).find(".list-row").removeClass("list-row-head").css("font-weight", "normal"); | |||||
$('.inbox-item[data-account="' + data.account + '" ]').closest(".list-row").addClass("list-row-head").css("font-weight","bold"); | |||||
me.refresh(); | |||||
}); | |||||
if(!me.fresh &&(data.account == me.account || me.account == me.all_accounts)) { | |||||
me.fresh = true; | |||||
me.refresh(); | |||||
} | |||||
} | |||||
} | |||||
me.fresh = false | |||||
}); | |||||
}, | |||||
render_list: function(data) { | |||||
var me = this | |||||
$(me.wrapper).find(".result-list").empty(); | |||||
$.each(data, function(idx, email) { | |||||
$(frappe.render_template("inbox_list", {data: email})) | |||||
.data("data", email) | |||||
.appendTo($(me.wrapper).find(".result-list")) | |||||
}); | |||||
//click action | |||||
$(me.wrapper).find(".result-list").find(".list-row").click(function(btn) { | |||||
if ($(btn.target).hasClass("noclick")) | |||||
return | |||||
var row = $(btn.target).closest(".list-row").data("data"); | |||||
if($(btn.target).hasClass("relink-link")){ | |||||
me.relink(row); | |||||
return | |||||
} | |||||
if(me.account != "Sent") { | |||||
if ($(btn.target).hasClass("company-link")) { | |||||
me.company_select(row, true); | |||||
return | |||||
} | |||||
} | |||||
me.email_open(row); | |||||
}); | |||||
}, | |||||
company_select: function(row, nomatch) { | |||||
var me = this; | |||||
var fields = [ | |||||
{ | |||||
"fieldtype": "Heading", | |||||
"label": __("Create new Contact to Match Email Address"), | |||||
"fieldname": "Option1" | |||||
}, | |||||
{ | |||||
"fieldtype": "Button", | |||||
"label": __("Create/Add new Contact"), | |||||
"fieldname":"newcontact", | |||||
"description": __('Create new Contact for a Customer, Supplier, User or Organisation to Match "') + row.sender + __('" Against') | |||||
} | |||||
]; | |||||
if (!nomatch) { | |||||
fields.push({ | |||||
"fieldtype": "Heading", | |||||
"label": __("Do not Match"), | |||||
"fieldname": "Option3" | |||||
}); | |||||
fields.push({ | |||||
"fieldtype": "Button", | |||||
"label": __("Do not Match"), | |||||
"fieldname":"nomatch" | |||||
}) | |||||
} | |||||
var d = new frappe.ui.Dialog ({ | |||||
title: __("Match Emails to a Company"), | |||||
fields: fields | |||||
}); | |||||
d.get_input("newcontact").on("click", function (frm) { | |||||
d.hide(); | |||||
delete frappe.route_flags.update_contact; | |||||
frappe.route_flags.create_contact = 1; | |||||
var name_split = row.sender_full_name?row.sender_full_name.split(' '):["",""]; | |||||
row.nomatch = 1; | |||||
frappe.route_options = { | |||||
"email_id": row.sender, | |||||
"first_name": name_split[0], | |||||
"last_name":name_split[name_split.length-1], | |||||
"status": "Passive" | |||||
}; | |||||
frappe.model.with_doctype("Contact", function() { | |||||
var doc = frappe.model.get_new_doc("Contact"); | |||||
frappe.set_route("Form", "Contact", doc.name); | |||||
}) | |||||
}); | |||||
if (!nomatch) { | |||||
d.get_input("nomatch").on("click", function (frm) { | |||||
d.hide(); | |||||
frappe.call({ | |||||
method: 'frappe.email.page.email_inbox.setnomatch', | |||||
args: { | |||||
name: row.name | |||||
} | |||||
}); | |||||
row.nomatch = 1; | |||||
if (!nomatch) { | |||||
me.email_open(row) | |||||
} | |||||
}); | |||||
} | |||||
d.show(); | |||||
}, | |||||
email_open: function(row) { | |||||
var me = this; | |||||
me.actions_opened = false; | |||||
if(me.open_email == row.name){ | |||||
return | |||||
} | |||||
me.open_email = row.name | |||||
//mark email as read | |||||
if(me.account!="Sent") { | |||||
this.mark_read(row); | |||||
} | |||||
//start of open email | |||||
var emailitem = new frappe.ui.Dialog ({ | |||||
title: __(row.subject), | |||||
fields: [{ | |||||
"fieldtype": "HTML", | |||||
"fieldname": "email" | |||||
}] | |||||
}); | |||||
//prompt for match | |||||
if (!row.timeline_label && !row.nomatch && me.account!="Sent") { | |||||
setTimeout(function () { | |||||
if (frappe.ui.open_dialogs.indexOf(emailitem) != -1 && !me.actions_opened) { | |||||
me.company_select(row) | |||||
}}, 4000); | |||||
} | |||||
var c = me.prepare_email(row); | |||||
emailitem.fields_dict.email.$wrapper.html(frappe.render_template("inbox_email", {data:c})); | |||||
$(emailitem.$wrapper).find(".reply").find("a").attr("target", "_blank"); | |||||
//Action buttons | |||||
$(emailitem.$wrapper).find(".text-right").prepend(frappe.render_template("inbox_email_actions",{data:row})).on("click", function () { | |||||
me.actions_opened = true; | |||||
}); | |||||
$(emailitem.$wrapper).find(".relink-link").on("click", function () { | |||||
me.relink(row); }); | |||||
$(emailitem.$wrapper).find(".delete-link").on("click", function () { | |||||
me.delete_email({n:row.name, u:row.uid}); | |||||
emailitem.hide() | |||||
}); | |||||
$(emailitem.$wrapper).find(".company-link").on("click", function () { | |||||
me.company_select(row, true)}); | |||||
me.add_reply_btn_event(emailitem, c); | |||||
//adjust sizing | |||||
$(".modal-dialog").addClass("modal-lg"); | |||||
$(emailitem.$wrapper).find(".modal-title") | |||||
.parent() | |||||
.removeClass("col-xs-7") | |||||
.addClass("col-xs-7 col-sm-8 col-md-9"); | |||||
$(emailitem.$wrapper).find(".text-right") | |||||
.parent() | |||||
.removeClass("col-xs-5") | |||||
.addClass("col-xs-5 col-sm-4 col-md-3"); | |||||
//setup close | |||||
emailitem.onhide = function() { | |||||
me.open_email = null | |||||
} | |||||
emailitem.show(); | |||||
}, | |||||
add_reply_btn_event: function (emailitem, c) { | |||||
var me = this; | |||||
//reply | |||||
$(emailitem.$wrapper).find(".reply-link").on("click", function () { | |||||
var sender = ""; | |||||
for (var i=0;i<me.accounts.length;i++){ | |||||
if(me.accounts[i].name===me.account){ | |||||
sender = me.accounts[i].email; | |||||
break; | |||||
} | |||||
} | |||||
new frappe.views.CommunicationComposer({ | |||||
doc: { | |||||
doctype: c.reference_doctype, | |||||
name: c.reference_name | |||||
}, | |||||
sender: sender, | |||||
subject: "Re: " + c.subject, | |||||
recipients: c.sender, | |||||
last_email: c, | |||||
attachments: c.attachments | |||||
}); | |||||
}); | |||||
//reply-all | |||||
$(emailitem.$wrapper).find(".reply-all-link").on("click", function () { | |||||
var sender = ""; | |||||
for (var i=0;i<me.accounts.length;i++){ | |||||
if(me.accounts[i].name===me.account){ | |||||
sender = me.accounts[i].email; | |||||
break; | |||||
} | |||||
} | |||||
new frappe.views.CommunicationComposer({ | |||||
doc: { | |||||
doctype: c.reference_doctype, | |||||
name: c.reference_name | |||||
}, | |||||
sender:sender, | |||||
subject: "Re: " + c.subject, | |||||
recipients: (c.sender + (c.recipients ? ", "+c.recipients:"") + (c.cc ? ", "+c.cc:"")).replace(sender,""), | |||||
last_email: c, | |||||
attachments:c.attachments | |||||
}); | |||||
}); | |||||
//forward | |||||
$(emailitem.$wrapper).find(".forward-link").on("click", function () { | |||||
var sender = ""; | |||||
for (var i=0;i<me.accounts.length;i++){ | |||||
if(me.accounts[i].name===me.account){ | |||||
sender = me.accounts[i].email; | |||||
break; | |||||
} | |||||
} | |||||
var communication = new frappe.views.CommunicationComposer({ | |||||
doc: { | |||||
doctype: c.reference_doctype, | |||||
name: c.reference_name | |||||
}, | |||||
sender:sender, | |||||
subject: "FW: " + c.subject, | |||||
last_email: c, | |||||
forward:true, | |||||
attachments:c.attachments | |||||
}); | |||||
$(communication.dialog.fields_dict.select_attachments.wrapper).find("input[type=checkbox]").prop("checked",true) | |||||
}); | |||||
}, | |||||
relink: function(row){ | |||||
var me = this; | |||||
var callback = function(frm){ | |||||
$(me.wrapper).find(".row-named[data-name="+row.name+"]").find(".reference-document") | |||||
.html(values["reference_name"]) | |||||
.attr("href",'#Form/'+values["reference_doctype"]+ '/'+values["reference_name"]) | |||||
.attr("title","Linked Doctype: "+values["reference_doctype"]); | |||||
row.reference_doctype = values["reference_doctype"]; | |||||
row.reference_name = values["reference_name"]; | |||||
} | |||||
frappe.timeline.relink_dialog(row.name, row.reference_doctype, row.reference_name, callback); | |||||
}, | |||||
prepare_email: function(c){ | |||||
var me = this; | |||||
frappe.call({ | |||||
method:'frappe.email.page.email_inbox.get_email_content', | |||||
args:{ | |||||
doctype:"Communication", | |||||
name:c.name | |||||
}, | |||||
async:false, | |||||
callback:function(r){ | |||||
c.attachments =r["message"][0]; | |||||
c.content = r["message"][1]; | |||||
} | |||||
}); | |||||
c.doctype = "Communication"; | |||||
c.comment_on = comment_when(c.communication_date); | |||||
if (c.attachments && typeof c.attachments === "string") | |||||
c.attachments = JSON.parse(c.attachments); | |||||
if (!c.comment_type) | |||||
c.comment_type = "Email"; | |||||
c.comment = c.content; | |||||
if (c.comment_type == "Email") { | |||||
c.comment = c.comment.split("<!-- original-reply -->")[0]; | |||||
c.comment = frappe.utils.strip_original_content(c.comment); | |||||
c.comment = frappe.dom.remove_script_and_style(c.comment); | |||||
c.original_comment = c.comment; | |||||
c.comment = frappe.utils.toggle_blockquote(c.comment); | |||||
} | |||||
if (!frappe.utils.is_html(c.comment)) { | |||||
c.comment_html = frappe.markdown(__(c.comment)); | |||||
} else { | |||||
c.comment_html = c.comment; | |||||
c.comment_html = frappe.utils.strip_whitespace(c.comment_html); | |||||
c.comment_html = c.comment_html.replace(/</g,"<").replace(/>/g,">") | |||||
} | |||||
// bold @mentions | |||||
if (c.comment_type === "Comment") { | |||||
c.comment_html = c.comment_html.replace(/(^|\W)(@\w+)/g, "$1<b>$2</b>"); | |||||
} | |||||
return c | |||||
}, | |||||
init_select_all: function () { | |||||
var me = this; | |||||
$(".list-select-all").on("click", function () { | |||||
$(me.wrapper).find('.list-row-checkbox').prop("checked", $(this).prop("checked")); | |||||
me.toggle_actions(); | |||||
}); | |||||
$(me.wrapper).on("click", ".list-row-checkbox", function (event) { | |||||
me.toggle_actions(); | |||||
// multi-select using shift key | |||||
var $this = $(this); | |||||
if (event.shiftKey && $this.prop("checked")) { | |||||
var $end_row = $this.parents(".list-row"); | |||||
var $start_row = $end_row.prevAll(".list-row") | |||||
.find(".list-row-checkbox:checked").last().parents(".list-row"); | |||||
if ($start_row) { | |||||
$start_row.nextUntil($end_row).find(".list-row-checkbox").prop("checked", true); | |||||
} | |||||
} | |||||
}); | |||||
// after delete, hide delete button | |||||
me.toggle_actions(); | |||||
}, | |||||
render_buttons: function(){ | |||||
var me = this; | |||||
me.page.add_action_item("Delete", function(){ me.delete_email() }); | |||||
me.page.add_action_item("Mark as Unread", function(){ me.mark_unread() }); | |||||
me.page.add_action_item("Mark as Read", function(){ me.mark_read() }); | |||||
me.page.set_primary_action("New Email", function(){ | |||||
var sender = ""; | |||||
for (var i=0;i<me.accounts.length;i++){ | |||||
if(me.accounts[i].name===me.account){ | |||||
sender = me.accounts[i].email | |||||
break; | |||||
} | |||||
} | |||||
new frappe.views.CommunicationComposer({ | |||||
doc: {}, | |||||
sender: sender | |||||
}); | |||||
}, "fa-plus", "New Email"); | |||||
}, | |||||
toggle_actions: function () { | |||||
var me = this; | |||||
if (me.page.main.find(".list-row-checkbox:checked").length) { | |||||
//show buttons | |||||
$(me.page.actions_btn_group).show(); | |||||
$(me.page.btn_primary).hide() | |||||
} else { | |||||
//hide button | |||||
$(me.page.actions_btn_group).hide(); | |||||
$(me.page.btn_primary).show() | |||||
} | |||||
}, | |||||
delete_email: function(data){ | |||||
var me = this; | |||||
if (!data) { | |||||
var names = $.map(me.action_checked_items('.data("data")'), function(v){ | |||||
return {name:v.name, uid:v.uid} | |||||
}); | |||||
me.action_checked_items('.remove()') | |||||
} else { | |||||
var names = [{name:data.name, uid:data.uid}] | |||||
} | |||||
}, | |||||
mark_unread: function(){ | |||||
var me = this; | |||||
var names = $.map(me.action_checked_items('.data("data")'), function(v){ | |||||
return {name:v.name, uid:v.uid} | |||||
}); | |||||
me.create_flag_queue(names, "Unread", "SEEN"); | |||||
me.action_checked_items('.css("font-weight", "BOLD")'); | |||||
me.update_local_flags(names, "seen", "0") | |||||
}, | |||||
mark_read: function(data){ | |||||
var me = this; | |||||
if (!data) { | |||||
var names = $.map(me.action_checked_items('.data("data")'), function(v){return {name:v.name, uid:v.uid}}); | |||||
me.action_checked_items('.css("font-weight", "normal")') | |||||
} else { | |||||
var names = [{name:data.name, uid:data.uid}]; | |||||
$(".row-named").filter("[data-name=" + data.name + "]").css("font-weight", "normal") | |||||
} | |||||
me.create_flag_queue(names, "Read", "SEEN"); | |||||
me.update_local_flags(names, "seen", "1"); | |||||
}, | |||||
create_flag_queue: function(names, action, flag){ | |||||
frappe.call({ | |||||
method: 'frappe.email.page.email_inbox.create_flag_queue', | |||||
args:{ | |||||
names: JSON.stringify(names), | |||||
action: action, | |||||
flag: flag | |||||
} | |||||
}) | |||||
}, | |||||
update_local_flags:function(names,field,val){ | |||||
frappe.call({ | |||||
method: 'frappe.email.page.email_inbox.update_local_flags', | |||||
args:{ | |||||
names: JSON.stringify(names), | |||||
field: field, | |||||
val: val | |||||
} | |||||
}) | |||||
$('.list-row-checkbox:checked').prop( "checked", false ); | |||||
}, | |||||
action_checked_items: function(action) { | |||||
return $.map(this.page.main.find('.list-row-checkbox:checked'), function(e) { | |||||
return eval('$(e).closest(".row-named")'+action); | |||||
}); | |||||
}, | |||||
}); |
@@ -1,19 +0,0 @@ | |||||
<ul class="list-unstyled sidebar-menu user-actions"> | |||||
<li class="divider"></li> | |||||
</ul> | |||||
<ul class="list-unstyled sidebar-menu standard-actions"> | |||||
<li class="divider"></li> | |||||
<li class="list-link" data-view="List"> | |||||
<a class="email-account" data-account="Sent">{%= __("Sent") %}</a> | |||||
</li> | |||||
</ul> | |||||
<ul class="list-unstyled sidebar-menu standard-actions"> | |||||
<li class="divider"></li> | |||||
<li class="list-link"><h6>Email Accounts</h6></li> | |||||
{% for(var i=0, l=data.length; i<l; i++) { %} | |||||
<li class="divider"></li> | |||||
<li class="list-link" data-view="List"> | |||||
<a class="email-account {%= i==0?"strong": "" %}" data-account="{%= data[i].account %}">{%= __(data[i].title) %}</a> | |||||
</li> | |||||
{% } %} | |||||
</ul> |
@@ -1,45 +0,0 @@ | |||||
<div class="list-row row-named" data-name="{%= data.name %}" style=" {%= data.seen ? "font-weight:normal" : "font-weight:bold" %}"> | |||||
<div class="row doclist-row has-checkbox"> | |||||
<div class="col-mg-5 col-sm-12 list-row-left"> | |||||
<div class="row"> | |||||
<div class="col-sm-2 list-col ellipsis col-xs-12"> | |||||
<span class="list-value"> | |||||
<input class="list-row-checkbox noclick" type="checkbox" style="margin: 0 7px 0 0; vertical-align: middle;"> | |||||
{% if (data.sender_full_name){var sender = data.sender_full_name} else {var sender = data.sender} %} | |||||
<a class="grey" title="{%= sender %}">{%= sender %}</a> | |||||
</span> | |||||
</div> | |||||
<div class="col-sm-4 list-col ellipsis col-xs-12"> | |||||
<span class="list-value"> | |||||
<a class="grey" title="{%= data.name %}">{%= data.subject %}</a> | |||||
</span> | |||||
</div> | |||||
<div class="col-sm-2 list-col ellipsis hidden-xs"> | |||||
<span class="list-value"> | |||||
<a class="h6 text-muted grey noclick" data-filter="timeline_doctype,=,{%= data.timeline_doctype %}" title="Linked Doctype: {%= data.reference_doctype %}" href="#Form/{%= data.timeline_doctype %}/{%= data.timeline_name %}">{%= data.timeline_label%}</a> | |||||
</span> | |||||
</div> | |||||
<div class="col-sm-2 list-col ellipsis hidden-xs"> | |||||
<span class="list-value"> | |||||
<i class="h6 fa fa-link text-muted relink-link pull-right" style="padding: 0px 0px; margin-right: 10px; font-size: 1.1em;"></i> | |||||
<a class="text-muted grey noclick reference-document" title="Linked Doctype: {%= data.reference_doctype %}" href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}">{%= data.reference_name %}</a> | |||||
</span> | |||||
</div> | |||||
<div class="col-sm-1 list-col ellipsis hidden-xs"> | |||||
<span class="list-value"> | |||||
<span> | |||||
{% if(data.has_attachment){ %} | |||||
<i class="fa fa-paperclip fa-large"></i> | |||||
{% } %} | |||||
</span> | |||||
</span> | |||||
</div> | |||||
<div class="col-sm-1 list-col ellipsis hidden-xs" > | |||||
<span class="list-value"> | |||||
{%= comment_when(data.communication_date,true) %} | |||||
</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> |
@@ -171,3 +171,4 @@ execute:frappe.rename_doc('Country', 'Syrian Arab Republic', 'Syria', ignore_if_ | |||||
frappe.patches.v8_0.rename_listsettings_to_usersettings | frappe.patches.v8_0.rename_listsettings_to_usersettings | ||||
frappe.patches.v7_2.update_communications | frappe.patches.v7_2.update_communications | ||||
frappe.patches.v8_0.deprecate_integration_broker | frappe.patches.v8_0.deprecate_integration_broker | ||||
frappe.patches.v8_0.setup_email_inbox |
@@ -0,0 +1,22 @@ | |||||
import frappe, json | |||||
def execute(): | |||||
""" | |||||
depricate email inbox page if exists | |||||
remove desktop icon for email inbox page if exists | |||||
patch to remove Custom DocPerm for communication | |||||
""" | |||||
if frappe.db.exists("Page", "email_inbox"): | |||||
frappe.delete_doc("Page", "email_inbox") | |||||
desktop_icon = frappe.db.get_value("Desktop Icon", { | |||||
"module_name": "Email", | |||||
"type": "Page", | |||||
"link": "email_inbox" | |||||
}) | |||||
if desktop_icon: | |||||
frappe.delete_doc("Desktop Icon", desktop_icon) | |||||
frappe.db.sql("""update `tabCustom DocPerm` set `write`=0, email=1 where parent='Communication'""") |
@@ -255,6 +255,8 @@ | |||||
"public/js/frappe/views/image/image_view_item_main_head.html", | "public/js/frappe/views/image/image_view_item_main_head.html", | ||||
"public/js/frappe/views/image/photoswipe_dom.html", | "public/js/frappe/views/image/photoswipe_dom.html", | ||||
"public/js/frappe/views/inbox/inbox_no_result.html", | |||||
"public/js/frappe/views/inbox/select_email_inbox.html", | |||||
"public/js/frappe/views/inbox/inbox_view_item_row.html", | "public/js/frappe/views/inbox/inbox_view_item_row.html", | ||||
"public/js/frappe/views/inbox/inbox_view_item_main_head.html", | "public/js/frappe/views/inbox/inbox_view_item_main_head.html", | ||||
@@ -595,3 +595,6 @@ select.form-control { | |||||
box-shadow: none; | box-shadow: none; | ||||
} | } | ||||
} | } | ||||
body[data-route^="Form/Communication"] textarea[data-fieldname="subject"] { | |||||
height: 80px !important; | |||||
} |
@@ -374,3 +374,10 @@ | |||||
.gantt .details-container .standard-image { | .gantt .details-container .standard-image { | ||||
display: block; | display: block; | ||||
} | } | ||||
.inbox-attachment, | |||||
.inbox-link { | |||||
margin-right: 7px; | |||||
} | |||||
.select-inbox { | |||||
padding: 30px 30px; | |||||
} |
@@ -13,9 +13,15 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="timeline-new-email"> | <div class="timeline-new-email"> | ||||
<button class="btn btn-default btn-new-email btn-xs"> | |||||
{% if(doctype === "Communication") { %} | |||||
<button class="btn btn-default btn-reply-email btn-xs"> | |||||
{%= __("Reply") %} | |||||
</button> | |||||
{% } else { %} | |||||
<button class="btn btn-default btn-new-email btn-xs"> | |||||
{%= __("New Email") %} | {%= __("New Email") %} | ||||
</button> | </button> | ||||
{% } %} | |||||
</div> | </div> | ||||
<div class="timeline-items"> | <div class="timeline-items"> | ||||
@@ -11,7 +11,7 @@ frappe.ui.form.Timeline = Class.extend({ | |||||
make: function() { | make: function() { | ||||
var me = this; | var me = this; | ||||
this.wrapper = $(frappe.render_template("timeline", | this.wrapper = $(frappe.render_template("timeline", | ||||
{})).appendTo(this.parent); | |||||
{doctype: this.frm.doctype})).appendTo(this.parent); | |||||
this.list = this.wrapper.find(".timeline-items"); | this.list = this.wrapper.find(".timeline-items"); | ||||
this.input = this.wrapper.find(".form-control"); | this.input = this.wrapper.find(".form-control"); | ||||
@@ -35,15 +35,7 @@ frappe.ui.form.Timeline = Class.extend({ | |||||
} | } | ||||
}); | }); | ||||
this.email_button = this.wrapper.find(".btn-new-email") | |||||
.on("click", function() { | |||||
new frappe.views.CommunicationComposer({ | |||||
doc: me.frm.doc, | |||||
txt: frappe.markdown(me.input.val()), | |||||
frm: me.frm, | |||||
recipients: me.get_recipient() | |||||
}) | |||||
}); | |||||
this.setup_email_button(); | |||||
this.list.on("click", ".toggle-blockquote", function() { | this.list.on("click", ".toggle-blockquote", function() { | ||||
$(this).parent().siblings("blockquote").toggleClass("hidden"); | $(this).parent().siblings("blockquote").toggleClass("hidden"); | ||||
@@ -82,6 +74,33 @@ frappe.ui.form.Timeline = Class.extend({ | |||||
}, | }, | ||||
setup_email_button: function() { | |||||
var me = this; | |||||
selector = this.frm.doctype === "Communication"? ".btn-reply-email": ".btn-new-email" | |||||
this.email_button = this.wrapper.find(selector) | |||||
.on("click", function() { | |||||
args = { | |||||
doc: me.frm.doc, | |||||
frm: me.frm, | |||||
recipients: me.get_recipient() | |||||
} | |||||
if(me.frm.doctype === "Communication") { | |||||
$.extend(args, { | |||||
txt: "", | |||||
last_email: me.frm.doc, | |||||
recipients: me.frm.doc.sender, | |||||
subject: __("Re: {0}", [me.frm.doc.subject]), | |||||
}); | |||||
} else { | |||||
$.extend(args, { | |||||
txt: frappe.markdown(me.input.val()) | |||||
}); | |||||
} | |||||
new frappe.views.CommunicationComposer(args) | |||||
}); | |||||
}, | |||||
refresh: function(scroll_to_end) { | refresh: function(scroll_to_end) { | ||||
var me = this; | var me = this; | ||||
@@ -524,5 +524,20 @@ frappe.views.ListRenderer = Class.extend({ | |||||
render_icon: function (parent, icon_class, label) { | render_icon: function (parent, icon_class, label) { | ||||
var icon_html = `<i class='${icon_class}' title='${__(label) || ''}'></i>`; | var icon_html = `<i class='${icon_class}' title='${__(label) || ''}'></i>`; | ||||
$(parent).append(icon_html); | $(parent).append(icon_html); | ||||
} | |||||
}, | |||||
make_no_result: function () { | |||||
var new_button = frappe.boot.user.can_create.includes(this.doctype) | |||||
? (`<p><button class='btn btn-primary btn-sm' | |||||
list_view_doc='${this.doctype}'> | |||||
${__('Make a new ' + __(this.doctype))} | |||||
</button></p>`) | |||||
: ''; | |||||
var no_result_message = | |||||
`<div class='msg-box no-border'> | |||||
<p>${__('No {0} found', [__(this.doctype)])}</p> | |||||
${new_button} | |||||
</div>`; | |||||
return no_result_message; | |||||
}, | |||||
}); | }); |
@@ -40,7 +40,6 @@ | |||||
{{ __("Email Inbox") }} <span class="caret"></span> | {{ __("Email Inbox") }} <span class="caret"></span> | ||||
</a> | </a> | ||||
<ul class="dropdown-menu email-account-dropdown" style="max-height: 300px; overflow-y: auto;"> | <ul class="dropdown-menu email-account-dropdown" style="max-height: 300px; overflow-y: auto;"> | ||||
<li class="new-email-account"><a>{{ __("New Email Account") }}</a></li> | |||||
</ul> | </ul> | ||||
</div> | </div> | ||||
</li> | </li> | ||||
@@ -247,6 +247,12 @@ frappe.views.ListSidebar = Class.extend({ | |||||
var $dropdown = this.page.sidebar.find('.email-account-dropdown'); | var $dropdown = this.page.sidebar.find('.email-account-dropdown'); | ||||
var divider = false; | var divider = false; | ||||
if(has_common(roles, ["System Manager", "Administrator"])) { | |||||
$('<li class="new-email-account"><a>'+ __("New Email Account") +'</a></li>') | |||||
.appendTo($dropdown) | |||||
} | |||||
accounts = frappe.boot.email_accounts; | accounts = frappe.boot.email_accounts; | ||||
accounts.forEach(function(account) { | accounts.forEach(function(account) { | ||||
@@ -158,6 +158,7 @@ frappe.views.ListView = frappe.ui.BaseList.extend({ | |||||
this.init_filters(); | this.init_filters(); | ||||
this.set_title(); | this.set_title(); | ||||
this.init_headers(); | this.init_headers(); | ||||
this.no_result_message = this.list_renderer.make_no_result() | |||||
}, | }, | ||||
setup_list_renderer: function () { | setup_list_renderer: function () { | ||||
@@ -327,7 +328,7 @@ frappe.views.ListView = frappe.ui.BaseList.extend({ | |||||
page_length: this.list_renderer.page_length, | page_length: this.list_renderer.page_length, | ||||
show_filters: false, | show_filters: false, | ||||
new_doctype: this.doctype, | new_doctype: this.doctype, | ||||
no_result_message: this.make_no_result(), | |||||
no_result_message: this.list_renderer.make_no_result(), | |||||
show_no_result: function() { | show_no_result: function() { | ||||
return me.list_renderer.show_no_result; | return me.list_renderer.show_no_result; | ||||
} | } | ||||
@@ -346,8 +347,12 @@ frappe.views.ListView = frappe.ui.BaseList.extend({ | |||||
if (this.list_renderer.settings.list_view_doc) { | if (this.list_renderer.settings.list_view_doc) { | ||||
this.list_renderer.settings.list_view_doc(this); | this.list_renderer.settings.list_view_doc(this); | ||||
} else { | } else { | ||||
$(this.wrapper).on('click', `button[list_view_doc='${this.doctype}']`, function () { | |||||
me.make_new_doc.apply(me, [me.doctype]); | |||||
doctype = this.list_renderer.no_result_doctype? this.list_renderer.no_result_doctype: this.doctype | |||||
$(this.wrapper).on('click', `button[list_view_doc='${doctype}']`, function () { | |||||
if (me.list_renderer.make_new_doc) | |||||
me.list_renderer.make_new_doc() | |||||
else | |||||
me.make_new_doc.apply(me, [me.doctype]); | |||||
}); | }); | ||||
} | } | ||||
}, | }, | ||||
@@ -492,22 +497,6 @@ frappe.views.ListView = frappe.ui.BaseList.extend({ | |||||
}) | }) | ||||
}, | }, | ||||
make_no_result: function () { | |||||
var new_button = frappe.boot.user.can_create.includes(this.doctype) | |||||
? (`<p><button class='btn btn-primary btn-sm' | |||||
list_view_doc='${this.doctype}'> | |||||
${__('Make a new ' + __(this.doctype))} | |||||
</button></p>`) | |||||
: ''; | |||||
var no_result_message = | |||||
`<div class='msg-box no-border'> | |||||
<p>${__('No {0} found', [__(this.doctype)])}</p> | |||||
${new_button} | |||||
</div>`; | |||||
return no_result_message; | |||||
}, | |||||
get_args: function () { | get_args: function () { | ||||
var args = { | var args = { | ||||
doctype: this.doctype, | doctype: this.doctype, | ||||
@@ -83,6 +83,7 @@ frappe.ui.notifications.config = { | |||||
"ToDo": { label: __("To Do") }, | "ToDo": { label: __("To Do") }, | ||||
"Chat": { label: __("Chat"), route: "chat"}, | "Chat": { label: __("Chat"), route: "chat"}, | ||||
"Event": { label: __("Calendar"), route: "List/Event/Calendar" }, | "Event": { label: __("Calendar"), route: "List/Event/Calendar" }, | ||||
"Email": { label: __("Email"), route: "List/Communication/Inbox" }, | |||||
"Likes": { | "Likes": { | ||||
label: __("Likes"), | label: __("Likes"), | ||||
click: function() { | click: function() { | ||||
@@ -86,13 +86,12 @@ frappe.views.CommunicationComposer = Class.extend({ | |||||
// add from if user has access to multiple email accounts | // add from if user has access to multiple email accounts | ||||
email_accounts = frappe.boot.email_accounts.filter(function(account, idx){ | email_accounts = frappe.boot.email_accounts.filter(function(account, idx){ | ||||
return !inList(["All Accounts", "Sent"], account.email_account) | |||||
return !inList(["All Accounts", "Sent", "Spam", "Trash"], account.email_account) | |||||
}) | }) | ||||
if(frappe.boot.email_accounts && email_accounts.length > 1) { | if(frappe.boot.email_accounts && email_accounts.length > 1) { | ||||
fields = [ | fields = [ | ||||
{label: __("From"), fieldtype: "Select", reqd: 1, fieldname: "sender", | {label: __("From"), fieldtype: "Select", reqd: 1, fieldname: "sender", | ||||
options: accounts.map(function(e) { return e.email_id; }) } | |||||
options: email_accounts.map(function(e) { return e.email_id; }) } | |||||
].concat(fields); | ].concat(fields); | ||||
} | } | ||||
@@ -0,0 +1,8 @@ | |||||
<div class="msg-box no-border"> | |||||
<p>{{ __("No {} found", [doctype]) }}</p> | |||||
<p> | |||||
<button class="btn btn-primary btn-sm btn-no-result" list_view_doc="{{ doctype }}"> | |||||
{{__(label) }} | |||||
</button> | |||||
</p> | |||||
</div> |
@@ -8,27 +8,35 @@ frappe.views.InboxView = frappe.views.ListRenderer.extend({ | |||||
name: 'Inbox', | name: 'Inbox', | ||||
render_view: function(values) { | render_view: function(values) { | ||||
var me = this; | var me = this; | ||||
var email_account = this.get_email_account(); | |||||
this.emails = values; | this.emails = values; | ||||
// save email account in user_settings | // save email account in user_settings | ||||
frappe.model.user_settings.save("Communication", 'Inbox', { | frappe.model.user_settings.save("Communication", 'Inbox', { | ||||
last_email_account: email_account | |||||
last_email_account: this.current_email_account | |||||
}); | }); | ||||
this.render_inbox_view(); | this.render_inbox_view(); | ||||
}, | }, | ||||
render_inbox_view: function() { | render_inbox_view: function() { | ||||
var html = this.emails.map(this.render_email_row.bind(this)).join(""); | |||||
var html = "" | |||||
email_account = this.get_current_email_account() | |||||
if(email_account) | |||||
html = this.emails.map(this.render_email_row.bind(this)).join(""); | |||||
else | |||||
html = this.get_inbox_selector_html() | |||||
this.container = $('<div>') | this.container = $('<div>') | ||||
.addClass('inbox-container') | .addClass('inbox-container') | ||||
.appendTo(this.wrapper); | .appendTo(this.wrapper); | ||||
this.container.append(html); | this.container.append(html); | ||||
if(!this.current_email_account) | |||||
this.bind_email_inbox_selector() | |||||
}, | }, | ||||
render_email_row: function(email) { | render_email_row: function(email) { | ||||
if(!email.css_seen && email.seen) | if(!email.css_seen && email.seen) | ||||
email.css_seen = "seen" | email.css_seen = "seen" | ||||
if(email.has_attachment) | |||||
email.attachment_html = '<span class="text-muted"><i class="fa fa-paperclip fa-large"></i></span>' | |||||
return frappe.render_template("inbox_view_item_row", { | return frappe.render_template("inbox_view_item_row", { | ||||
data: email, | data: email, | ||||
@@ -37,19 +45,19 @@ frappe.views.InboxView = frappe.views.ListRenderer.extend({ | |||||
}, | }, | ||||
set_defaults: function() { | set_defaults: function() { | ||||
this._super(); | this._super(); | ||||
this.show_no_result = false; | |||||
this.page_title = __("Email Inbox"); | this.page_title = __("Email Inbox"); | ||||
}, | }, | ||||
init_settings: function() { | init_settings: function() { | ||||
this._super(); | this._super(); | ||||
// this.show_no_result = false; | |||||
this.filters = this.get_inbox_filters(); | this.filters = this.get_inbox_filters(); | ||||
}, | }, | ||||
should_refresh: function() { | should_refresh: function() { | ||||
var to_refresh = this._super(); | var to_refresh = this._super(); | ||||
if(!to_refresh) { | if(!to_refresh) { | ||||
this.last_email_account = this.current_email_account || ''; | this.last_email_account = this.current_email_account || ''; | ||||
this.current_email_account = this.get_email_account(); | |||||
this.current_email_account = this.get_current_email_account(); | |||||
this.is_sent_emails = this.current_email_account === "Sent"? true: false | this.is_sent_emails = this.current_email_account === "Sent"? true: false | ||||
to_refresh = this.current_email_account !== this.last_email_account; | to_refresh = this.current_email_account !== this.last_email_account; | ||||
@@ -57,44 +65,115 @@ frappe.views.InboxView = frappe.views.ListRenderer.extend({ | |||||
if(to_refresh){ | if(to_refresh){ | ||||
this.list_view.page.main.find(".list-headers").empty(); | this.list_view.page.main.find(".list-headers").empty(); | ||||
this.list_view.init_headers(); | |||||
} | } | ||||
return to_refresh; | return to_refresh; | ||||
}, | }, | ||||
get_inbox_filters: function() { | get_inbox_filters: function() { | ||||
var email_account = this.get_email_account(); | |||||
var email_account = this.get_current_email_account(); | |||||
var default_filters = [ | var default_filters = [ | ||||
["Communication", "communication_type", "=", "Communication", true], | ["Communication", "communication_type", "=", "Communication", true], | ||||
["Communication", "communication_medium", "=", "Email", true], | ["Communication", "communication_medium", "=", "Email", true], | ||||
] | ] | ||||
var filters = [] | var filters = [] | ||||
if (email_account === "Sent") | |||||
if (email_account === "Sent") { | |||||
filters = default_filters.concat([ | filters = default_filters.concat([ | ||||
["Communication", "sent_or_received", "=", "Sent", true] | |||||
["Communication", "sent_or_received", "=", "Sent", true], | |||||
["Communication", "email_status", "not in", "Spam,Trash", true], | |||||
]) | ]) | ||||
else | |||||
} | |||||
else if (inList(["Spam", "Trash"], email_account)) { | |||||
filters = default_filters.concat([ | |||||
["Communication", "email_status", "=", email_account, true], | |||||
["Communication", "email_account", "in", frappe.boot.all_accounts, true] | |||||
]) | |||||
} | |||||
else { | |||||
filters = default_filters.concat([ | filters = default_filters.concat([ | ||||
["Communication", "sent_or_received", "=", "Received", true], | ["Communication", "sent_or_received", "=", "Received", true], | ||||
["Communication", "email_account", "=", email_account, true] | |||||
["Communication", "email_account", "=", email_account, true], | |||||
["Communication", "email_status", "not in", "Spam,Trash", true], | |||||
]) | ]) | ||||
} | |||||
return filters | return filters | ||||
}, | }, | ||||
get_header_html: function() { | get_header_html: function() { | ||||
var header = frappe.render_template('inbox_view_item_main_head', { | |||||
_checkbox: ((frappe.model.can_delete(this.doctype) || this.settings.selectable) | |||||
&& !this.no_delete), | |||||
is_sent_emails: this.is_sent_emails | |||||
}); | |||||
var header = "" | |||||
if(this.current_email_account) { | |||||
header = frappe.render_template('inbox_view_item_main_head', { | |||||
_checkbox: ((frappe.model.can_delete(this.doctype) || this.settings.selectable) | |||||
&& !this.no_delete), | |||||
is_sent_emails: this.is_sent_emails | |||||
}); | |||||
} | |||||
return header; | return header; | ||||
}, | }, | ||||
get_email_account: function() { | |||||
get_current_email_account: function() { | |||||
var route = frappe.get_route(); | var route = frappe.get_route(); | ||||
if(!route[3] || !frappe.boot.email_accounts.find(b => b.email_account === route[3])) { | if(!route[3] || !frappe.boot.email_accounts.find(b => b.email_account === route[3])) { | ||||
frappe.throw(__(`Email Account <b>${route[3] || ''}</b> not found`)); | |||||
return; | |||||
// frappe.throw(__(`Email Account <b>${route[3] || ''}</b> not found`)); | |||||
return ""; | |||||
} | } | ||||
return route[3]; | return route[3]; | ||||
}, | |||||
make_no_result: function () { | |||||
var no_result_message = "" | |||||
email_account = this.get_current_email_account(); | |||||
if (inList(["Spam", "Trash"], email_account)) { | |||||
return __("No {0} mail", [email_account]) | |||||
} else if(!email_account) { | |||||
// email account is not configured | |||||
this.no_result_doctype = "Email Account" | |||||
args = { | |||||
doctype: "Email Account", | |||||
label: "New Email Account" | |||||
} | |||||
} else { | |||||
// no sent mail | |||||
this.no_result_doctype = "Communication"; | |||||
args = { | |||||
doctype: "Communication", | |||||
label: "Compose Email" | |||||
} | |||||
} | |||||
var no_result_message = frappe.render_template("inbox_no_result", args) | |||||
return no_result_message; | |||||
}, | |||||
get_inbox_selector_html: function() { | |||||
email_account_map = {} | |||||
$.each(frappe.boot.email_accounts, function(idx, account){ | |||||
email_account_map[account.email_id] = account.email_account | |||||
}); | |||||
html = frappe.render_template("select_email_inbox", { | |||||
email_accounts: email_account_map, | |||||
current_email_account: this.current_email_account, | |||||
is_system_manager: has_common(["System Manager", "Administrator"], roles), | |||||
is_inbox_configured: Object.keys(email_account_map).length | |||||
}) | |||||
if(!Object.keys(email_account_map).length) | |||||
this.no_result_doctype = "Email Account" | |||||
return html | |||||
}, | |||||
bind_email_inbox_selector: function() { | |||||
// bind email_account on_change event | |||||
var me = this; | |||||
this.container.find('select[data-fieldname="email_inbox"]').on("change", function(event) { | |||||
inbox = $(event.target).val(); | |||||
frappe.set_route("List", "Communication", "Inbox", inbox) | |||||
}) | |||||
}, | |||||
make_new_doc: function() { | |||||
if (this.no_result_doctype == "Communication") { | |||||
new frappe.views.CommunicationComposer({ | |||||
doc: {} | |||||
}) | |||||
} else { | |||||
frappe.new_doc(this.no_result_doctype) | |||||
} | |||||
} | } | ||||
}); | }); |
@@ -21,10 +21,25 @@ | |||||
</div> | </div> | ||||
<div class="col-sm-2 col-xs-2 text-right list-row-right" style="padding-left:0px"> | <div class="col-sm-2 col-xs-2 text-right list-row-right" style="padding-left:0px"> | ||||
<div class="visible-xs"> | <div class="visible-xs"> | ||||
{%= data.attachment_html %} | |||||
<span class="text-muted inbox-attachment"> | |||||
{% if(data.has_attachment) { %} | |||||
<i class="fa fa-paperclip fa-large"></i> | |||||
{% } %} | |||||
</span> | |||||
</div> | </div> | ||||
<div class="hidden-xs"> | <div class="hidden-xs"> | ||||
{%= data.attachment_html %} | |||||
<span class="text-muted inbox-attachment"> | |||||
{% if(data.reference_doctype && data.reference_name) { %} | |||||
<a class="text-muted grey" href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}"> | |||||
<i class="fa fa-link fa-large"></i> | |||||
</a> | |||||
{% } %} | |||||
</span> | |||||
<span class="text-muted inbox-attachment"> | |||||
{% if(data.has_attachment) { %} | |||||
<i class="fa fa-paperclip fa-large"></i> | |||||
{% } %} | |||||
</span> | |||||
<span class="list-row-modified text-muted"> | <span class="list-row-modified text-muted"> | ||||
{%= comment_when(data.modified, true) %} | {%= comment_when(data.modified, true) %} | ||||
</span> | </span> | ||||
@@ -0,0 +1,32 @@ | |||||
<div class="no-result"> | |||||
{% if(is_inbox_configured) { %} | |||||
<div class="select-inbox no-border"> | |||||
<div class="form-group"> | |||||
<div class="clearfix"> | |||||
<label class="control-label" style="padding-right: 0px;">Email Inbox</label> | |||||
</div> | |||||
<div class="control-input-wrapper"> | |||||
<div class="control-input"> | |||||
<select type="text" autocomplete="off" class="input-with-feedback form-control bold" maxlength="140" data-fieldtype="Select" data-fieldname="email_inbox" placeholder=""> | |||||
<option value=""></option> | |||||
{% for(var email_id in email_accounts) { %} | |||||
<option value="{%= email_accounts[email_id] %}">{%= email_id %}</option> | |||||
{% } %} | |||||
</select> | |||||
</div> | |||||
<p class="help-box small text-muted hidden-xs">Please Select Email Inbox</p> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{% } else if(!is_system_manager) { %} | |||||
<div class="msg-box no-border"> | |||||
<p>Email Account is not assigned, Please contact System Manager</p> | |||||
</div> | |||||
{% } else { %} | |||||
{%= frappe.render_template("inbox_no_result", { | |||||
doctype: "Email Account", | |||||
label: "Email Account", | |||||
action: `frappe.new_doc("Email Account")` | |||||
}) %} | |||||
{% } %} | |||||
</div> |
@@ -767,3 +767,7 @@ select.form-control { | |||||
// } | // } | ||||
} | } | ||||
} | } | ||||
body[data-route^="Form/Communication"] textarea[data-fieldname="subject"] { | |||||
height: 80px !important; | |||||
} |
@@ -455,4 +455,12 @@ | |||||
display: block; | display: block; | ||||
} | } | ||||
} | } | ||||
} | |||||
.inbox-attachment, .inbox-link { | |||||
margin-right: 7px; | |||||
} | |||||
.select-inbox { | |||||
padding: 30px 30px; | |||||
} | } |