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 {