Skip to content

Commit

Permalink
Merge pull request #25232 from frappe/mergify/bp/version-15-hotfix/pr…
Browse files Browse the repository at this point in the history
…-23623

feat: scoped progress bar on bulk submit/cancel (backport #23623)
  • Loading branch information
akhilnarang committed Mar 5, 2024
2 parents 5f3726e + 37e0db7 commit d733fc2
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 30 deletions.
26 changes: 18 additions & 8 deletions frappe/desk/doctype/bulk_update/bulk_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from frappe.core.doctype.submission_queue.submission_queue import queue_submission
from frappe.model.document import Document
from frappe.utils import cint
from frappe.utils.deprecations import deprecated
from frappe.utils.scheduler import is_scheduler_inactive


Expand All @@ -25,6 +26,7 @@ class BulkUpdate(Document):
update_value: DF.SmallText

# end: auto-generated types

@frappe.whitelist()
def bulk_update(self):
self.check_permission("write")
Expand All @@ -46,12 +48,12 @@ def bulk_update(self):


@frappe.whitelist()
def submit_cancel_or_update_docs(doctype, docnames, action="submit", data=None):
def submit_cancel_or_update_docs(doctype, docnames, action="submit", data=None, task_id=None):
if isinstance(docnames, str):
docnames = frappe.parse_json(docnames)

if len(docnames) < 20:
return _bulk_action(doctype, docnames, action, data)
return _bulk_action(doctype, docnames, action, data, task_id)
elif len(docnames) <= 500:
frappe.msgprint(_("Bulk operation is enqueued in background."), alert=True)
frappe.enqueue(
Expand All @@ -60,21 +62,23 @@ def submit_cancel_or_update_docs(doctype, docnames, action="submit", data=None):
docnames=docnames,
action=action,
data=data,
task_id=task_id,
queue="short",
timeout=1000,
)
else:
frappe.throw(_("Bulk operations only support up to 500 documents."), title=_("Too Many Documents"))


def _bulk_action(doctype, docnames, action, data):
def _bulk_action(doctype, docnames, action, data, task_id=None):
if data:
data = frappe.parse_json(data)

failed = []
num_documents = len(docnames)

for i, d in enumerate(docnames, 1):
doc = frappe.get_doc(doctype, d)
for idx, docname in enumerate(docnames, 1):
doc = frappe.get_doc(doctype, docname)
try:
message = ""
if action == "submit" and doc.docstatus.is_draft():
Expand All @@ -92,17 +96,23 @@ def _bulk_action(doctype, docnames, action, data):
doc.save()
message = _("Updating {0}").format(doctype)
else:
failed.append(d)
failed.append(docname)
frappe.db.commit()
show_progress(docnames, message, i, d)
frappe.publish_progress(
percent=idx / num_documents * 100,
title=message,
description=docname,
task_id=task_id,
)

except Exception:
failed.append(d)
failed.append(docname)
frappe.db.rollback()

return failed


@deprecated
def show_progress(docnames, message, i, description):
n = len(docnames)
frappe.publish_progress(float(i) * 100 / n, title=message, description=description)
42 changes: 25 additions & 17 deletions frappe/public/js/frappe/list/bulk_operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,28 +214,36 @@ export default class BulkOperations {

submit_or_cancel(docnames, action = "submit", done = null) {
action = action.toLowerCase();
frappe
.call({
method: "frappe.desk.doctype.bulk_update.bulk_update.submit_cancel_or_update_docs",
args: {
doctype: this.doctype,
action: action,
docnames: docnames,
},
const task_id = Math.random().toString(36).slice(-5);
frappe.realtime.task_subscribe(task_id);
return frappe
.xcall("frappe.desk.doctype.bulk_update.bulk_update.submit_cancel_or_update_docs", {
doctype: this.doctype,
action: action,
docnames: docnames,
task_id: task_id,
})
.then((r) => {
let failed = r.message;
if (!failed) failed = [];

if (failed.length && !r._server_messages) {
frappe.throw(
__("Cannot {0} {1}", [action, failed.map((f) => f.bold()).join(", ")])
);
.then((failed_docnames) => {
if (failed_docnames?.length) {
const comma_separated_records = frappe.utils.comma_and(failed_docnames);
switch (action) {
case "submit":
frappe.throw(__("Cannot submit {0}.", [comma_separated_records]));
break;
case "cancel":
frappe.throw(__("Cannot cancel {0}.", [comma_separated_records]));
break;
default:
frappe.throw(__("Cannot {0} {1}.", [action, comma_separated_records]));
}
}
if (failed.length < docnames.length) {
if (failed_docnames?.length < docnames.length) {
frappe.utils.play_sound(action);
if (done) done();
}
})
.finally(() => {
frappe.realtime.task_unsubscribe(task_id);
});
}

Expand Down
13 changes: 8 additions & 5 deletions frappe/realtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
from frappe.utils.data import cstr


def publish_progress(percent, title=None, doctype=None, docname=None, description=None):
def publish_progress(
percent, title=None, doctype=None, docname=None, description=None, task_id=None
):
publish_realtime(
"progress",
{"percent": percent, "title": title, "description": description},
user=None if doctype and docname else frappe.session.user,
doctype=doctype,
docname=docname,
task_id=task_id,
)


Expand All @@ -41,8 +44,11 @@ def publish_realtime(
if message is None:
message = {}

if not task_id and hasattr(frappe.local, "task_id"):
task_id = frappe.local.task_id

if event is None:
event = "task_progress" if frappe.local.task_id else "global"
event = "task_progress" if task_id else "global"
elif event == "msgprint" and not user:
user = frappe.session.user
elif event == "list_update":
Expand All @@ -51,9 +57,6 @@ def publish_realtime(
elif event == "docinfo_update":
room = get_doc_room(doctype, docname)

if not task_id and hasattr(frappe.local, "task_id"):
task_id = frappe.local.task_id

if not room:
if task_id:
after_commit = False
Expand Down

0 comments on commit d733fc2

Please sign in to comment.