diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 55d57a0a82..e6f735e9d7 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -202,11 +202,13 @@ def get_versions(doc): @frappe.whitelist() def get_communications(doctype, name, start=0, limit=20): + from frappe.utils import cint + doc = frappe.get_doc(doctype, name) if not doc.has_permission("read"): raise frappe.PermissionError - return _get_communications(doctype, name, start, limit) + return _get_communications(doctype, name, cint(start), cint(limit)) def get_comments( @@ -253,7 +255,7 @@ def get_point_logs(doctype, docname): ) -def _get_communications(doctype, name, start=0, limit=100): +def _get_communications(doctype, name, start=0, limit=20): communications = get_communication_data(doctype, name, start, limit) for c in communications: if c.communication_type == "Communication": diff --git a/frappe/public/js/frappe/form/footer/base_timeline.js b/frappe/public/js/frappe/form/footer/base_timeline.js index af07b1cb95..d7ae78d748 100644 --- a/frappe/public/js/frappe/form/footer/base_timeline.js +++ b/frappe/public/js/frappe/form/footer/base_timeline.js @@ -82,6 +82,18 @@ class BaseTimeline { items.forEach((item) => this.add_timeline_item(item, append_at_the_end)); } + add_timeline_items_based_on_creation(items) { + items.forEach((item) => { + this.timeline_items_wrapper.find(".timeline-item").each((i, el) => { + let creation = $(el).attr("data-timestamp"); + if (creation && new Date(creation) < new Date(item.creation)) { + $(el).before(this.get_timeline_item(item)); + return false; + } + }); + }); + } + get_timeline_item(item) { // item can have content*, creation*, // timeline_badge, icon, icon_size, @@ -90,6 +102,7 @@ class BaseTimeline { timeline_item.attr({ "data-doctype": item.doctype, "data-name": item.name, + "data-timestamp": item.creation, }); if (item.icon) { timeline_item.append(` @@ -114,6 +127,23 @@ class BaseTimeline { if (item.id) { timeline_content.attr("id", item.id); } + + if (item.append_load_more) { + timeline_item.append( + `
+ +
` + ); + } + + timeline_item.find(".btn-load-more").on("click", async () => { + let more_items = await this.get_more_communication_timeline_contents(); + timeline_item.find(".timeline-load-more").remove(); + this.add_timeline_items_based_on_creation(more_items); + }); + return timeline_item; } } diff --git a/frappe/public/js/frappe/form/footer/form_timeline.js b/frappe/public/js/frappe/form/footer/form_timeline.js index 5514693c05..4d2b8e8a1c 100644 --- a/frappe/public/js/frappe/form/footer/form_timeline.js +++ b/frappe/public/js/frappe/form/footer/form_timeline.js @@ -193,7 +193,7 @@ class FormTimeline extends BaseTimeline { return view_timeline_contents; } - get_communication_timeline_contents() { + get_communication_timeline_contents(more_items) { let communication_timeline_contents = []; let icon_set = { Email: "mail", @@ -201,7 +201,8 @@ class FormTimeline extends BaseTimeline { Meeting: "calendar", Other: "dot-horizontal", }; - (this.doc_info.communications || []).forEach((communication) => { + let items = more_items ? more_items : this.doc_info.communications || []; + items.forEach((communication) => { let medium = communication.communication_medium; communication_timeline_contents.push({ icon: icon_set[medium], @@ -214,9 +215,34 @@ class FormTimeline extends BaseTimeline { name: communication.name, }); }); + + if (communication_timeline_contents.length >= 20) { + communication_timeline_contents[ + communication_timeline_contents.length - 1 + ].append_load_more = true; + } + return communication_timeline_contents; } + async get_more_communication_timeline_contents() { + let more_items = []; + let response = await frappe.call({ + method: "frappe.desk.form.load.get_communications", + args: { + doctype: this.doc_info.doctype, + name: this.doc_info.name, + start: this.doc_info.communications.length, + limit: 20, + }, + }); + if (response.message) { + this.doc_info.communications.push(...response.message); + more_items = this.get_communication_timeline_contents(response.message); + } + return more_items; + } + get_communication_timeline_content(doc, allow_reply = true) { doc._url = frappe.utils.get_form_link("Communication", doc.name); this.set_communication_doc_status(doc); diff --git a/frappe/public/scss/desk/timeline.scss b/frappe/public/scss/desk/timeline.scss index a99f2648e8..187fc4bc6c 100644 --- a/frappe/public/scss/desk/timeline.scss +++ b/frappe/public/scss/desk/timeline.scss @@ -95,6 +95,11 @@ $threshold: 34; .timeline-badge { @include timeline-badge(var(--timeline-item-icon-size)) } + .timeline-load-more { + margin-left: calc(var(--timeline-item-left-margin) + var(--padding-sm)); + width: var(--timeline-content-max-width); + text-align: center; + } .timeline-message-box { .content {