From bf6cb1a49f626e42a0cf4c288a46607022dbd8a9 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 6 Mar 2024 13:28:55 +0530 Subject: [PATCH 01/10] feat: move bulk print operation to the background Signed-off-by: Akhil Narang --- .../public/js/frappe/list/bulk_operations.js | 42 ++++----- frappe/utils/print_format.py | 91 +++++++++++++++---- 2 files changed, 90 insertions(+), 43 deletions(-) diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index 69ccd59600..ce0fec922d 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -35,11 +35,6 @@ export default class BulkOperations { return; } - if (valid_docs.length > 50) { - frappe.msgprint(__("You can only print upto 50 documents at a time")); - return; - } - const dialog = new frappe.ui.Dialog({ title: __("Print Documents"), fields: [ @@ -102,28 +97,25 @@ export default class BulkOperations { pdf_options = JSON.stringify({ "page-size": args.page_size }); } - const w = window.open( - "/api/method/frappe.utils.print_format.download_multi_pdf?" + - "doctype=" + - encodeURIComponent(this.doctype) + - "&name=" + - encodeURIComponent(json_string) + - "&format=" + - encodeURIComponent(print_format) + - "&no_letterhead=" + - (with_letterhead ? "0" : "1") + - "&letterhead=" + - encodeURIComponent(letterhead) + - "&options=" + - encodeURIComponent(pdf_options) - ); + const task_id = Math.random().toString(36).slice(-5); + frappe.realtime.task_subscribe(task_id); + frappe.realtime.on(`task_progress:${task_id}`, (data) => { + frappe.msgprint( + `Please click here to download the PDF` + ); + }); - if (!w) { - frappe.msgprint(__("Please enable pop-ups")); - return; - } + frappe.call("frappe.utils.print_format.download_multi_pdf", { + doctype: this.doctype, + name: json_string, + format: print_format, + no_letterhead: with_letterhead ? "0" : "1", + letterhead: letterhead, + options: pdf_options, + task_id: task_id, + }); + dialog.hide(); }); - dialog.show(); } diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index 29c76d7615..294c64aa2c 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -19,7 +19,35 @@ from frappe.www.printview import validate_print_permission @frappe.whitelist() -def download_multi_pdf(doctype, name, format=None, no_letterhead=False, letterhead=None, options=None): +def download_multi_pdf( + doctype, + name, + format=None, + no_letterhead=False, + letterhead=None, + options=None, + task_id=None, +): + """ + Calls _download_multi_pdf with the given parameters and returns the URL of the generated PDF + + """ + frappe.enqueue( + _download_multi_pdf, + doctype=doctype, + name=name, + format=format, + no_letterhead=no_letterhead, + letterhead=letterhead, + options=options, + task_id=task_id, + ) + frappe.local.response["http_status_code"] = 201 + + +def _download_multi_pdf( + doctype, name, format=None, no_letterhead=False, letterhead=None, options=None, task_id=None +): """Return a PDF compiled by concatenating multiple documents. The documents can be from a single DocType or multiple DocTypes. @@ -52,6 +80,7 @@ def download_multi_pdf(doctype, name, format=None, no_letterhead=False, letterhe Returns: PDF: A PDF generated by the concatenation of the mentioned input docs + """ import json @@ -63,23 +92,35 @@ def download_multi_pdf(doctype, name, format=None, no_letterhead=False, letterhe if not isinstance(doctype, dict): result = json.loads(name) + total_docs = len(result) # Concatenating pdf files - for ss in result: - pdf_writer = frappe.get_print( - doctype, - ss, - format, - as_pdf=True, - output=pdf_writer, - no_letterhead=no_letterhead, - letterhead=letterhead, - pdf_options=options, + for idx, ss in enumerate(result): + try: + pdf_writer = frappe.get_print( + doctype, + ss, + format, + as_pdf=True, + output=pdf_writer, + no_letterhead=no_letterhead, + letterhead=letterhead, + pdf_options=options, + ) + except Exception: + frappe.publish_realtime(task_id=task_id, message={"message": "Failed"}) + + # Publish progress + frappe.publish_progress( + percent=(idx + 1) / total_docs * 100, + title="Creating PDF", + description=f"{idx+1} out of {total_docs}", + task_id=task_id, ) - frappe.local.response.filename = "{doctype}.pdf".format( - doctype=doctype.replace(" ", "-").replace("/", "-") - ) + else: + total_docs = sum([len(doctype[dt]) for dt in doctype]) + count = 1 for doctype_name in doctype: for doc_name in doctype[doctype_name]: try: @@ -94,19 +135,33 @@ def download_multi_pdf(doctype, name, format=None, no_letterhead=False, letterhe pdf_options=options, ) except Exception: + frappe.publish_realtime(task_id=task_id, message="Failed") frappe.log_error( title="Error in Multi PDF download", message=f"Permission Error on doc {doc_name} of doctype {doctype_name}", reference_doctype=doctype_name, reference_name=doc_name, ) - frappe.local.response.filename = f"{name}.pdf" + count += 1 + frappe.publish_progress( + percent=count / total_docs * 100, + title="Creating PDF", + description=f"{count} out of {total_docs}", + task_id=task_id, + ) with BytesIO() as merged_pdf: pdf_writer.write(merged_pdf) - frappe.local.response.filecontent = merged_pdf.getvalue() - - frappe.local.response.type = "pdf" + _file = frappe.get_doc( + { + "doctype": "File", + "file_name": f"{task_id}.pdf", + "content": merged_pdf.getvalue(), + "is_private": 1, + } + ) + _file.save() + frappe.publish_realtime(f"task_progress:{task_id}", message={"file_url": _file.unique_url}) @deprecated From 5d0db0c00414e4b170061e4f8f6f67856cc444d9 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Tue, 12 Mar 2024 15:40:26 +0530 Subject: [PATCH 02/10] fix: open PDF in new tab Signed-off-by: Akhil Narang --- frappe/public/js/frappe/list/bulk_operations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index ce0fec922d..f1ae55643e 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -101,7 +101,7 @@ export default class BulkOperations { frappe.realtime.task_subscribe(task_id); frappe.realtime.on(`task_progress:${task_id}`, (data) => { frappe.msgprint( - `Please click here to download the PDF` + `Please click here to download the PDF` ); }); From 9bf22b79e46bfb043915b99829f7c7f12f4c709b Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Tue, 12 Mar 2024 15:46:32 +0530 Subject: [PATCH 03/10] fix: update message Signed-off-by: Akhil Narang --- frappe/utils/print_format.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index 294c64aa2c..a70bbc54fb 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -113,8 +113,8 @@ def _download_multi_pdf( # Publish progress frappe.publish_progress( percent=(idx + 1) / total_docs * 100, - title="Creating PDF", - description=f"{idx+1} out of {total_docs}", + title=_("Please keep this tab open until the operation is complete."), + description=_(f"Printed {idx + 1} documents out of {total_docs}."), task_id=task_id, ) @@ -145,8 +145,8 @@ def _download_multi_pdf( count += 1 frappe.publish_progress( percent=count / total_docs * 100, - title="Creating PDF", - description=f"{count} out of {total_docs}", + title=_("Please keep this tab open until the operation is complete."), + description=_(f"Printed {count} documents out of {total_docs}."), task_id=task_id, ) From 1caae030aedcba76acb1218efc409907bfbeb80e Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 13 Mar 2024 11:28:19 +0530 Subject: [PATCH 04/10] fix: add back a limitation to number of the documents Don't allow printing more than 500 documents Signed-off-by: Akhil Narang --- frappe/public/js/frappe/list/bulk_operations.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index f1ae55643e..5fc1cc91ff 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -10,6 +10,7 @@ export default class BulkOperations { const is_submittable = frappe.model.is_submittable(this.doctype); const allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled); const letterheads = this.get_letterhead_options(); + const MAX_PRINT_LIMIT = 500; const valid_docs = docs .filter((doc) => { @@ -35,6 +36,13 @@ export default class BulkOperations { return; } + if (valid_docs.length > MAX_PRINT_LIMIT) { + frappe.msgprint( + __("You can only print upto {0} documents at a time", [MAX_PRINT_LIMIT]) + ); + return; + } + const dialog = new frappe.ui.Dialog({ title: __("Print Documents"), fields: [ From 5a6bff9de7bb43f747cffe5b5592e93efd200774 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 13 Mar 2024 13:08:47 +0530 Subject: [PATCH 05/10] fix: let backend generate task ID Signed-off-by: Akhil Narang --- .../public/js/frappe/list/bulk_operations.js | 37 ++++++++++--------- frappe/utils/print_format.py | 7 ++-- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index 5fc1cc91ff..fd1f852d5a 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -105,24 +105,25 @@ export default class BulkOperations { pdf_options = JSON.stringify({ "page-size": args.page_size }); } - const task_id = Math.random().toString(36).slice(-5); - frappe.realtime.task_subscribe(task_id); - frappe.realtime.on(`task_progress:${task_id}`, (data) => { - frappe.msgprint( - `Please click here to download the PDF` - ); - }); - - frappe.call("frappe.utils.print_format.download_multi_pdf", { - doctype: this.doctype, - name: json_string, - format: print_format, - no_letterhead: with_letterhead ? "0" : "1", - letterhead: letterhead, - options: pdf_options, - task_id: task_id, - }); - dialog.hide(); + frappe + .call("frappe.utils.print_format.download_multi_pdf", { + doctype: this.doctype, + name: json_string, + format: print_format, + no_letterhead: with_letterhead ? "0" : "1", + letterhead: letterhead, + options: pdf_options, + }) + .then((response) => { + let task_id = response.message.task_id; + frappe.realtime.task_subscribe(task_id); + frappe.realtime.on(`task_progress:${task_id}`, (data) => { + frappe.msgprint( + `Please click here to download the PDF` + ); + }); + dialog.hide(); + }); }); dialog.show(); } diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index a70bbc54fb..a74850b4dd 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -1,4 +1,5 @@ import os +import uuid from io import BytesIO from pypdf import PdfWriter @@ -26,12 +27,11 @@ def download_multi_pdf( no_letterhead=False, letterhead=None, options=None, - task_id=None, ): """ - Calls _download_multi_pdf with the given parameters and returns the URL of the generated PDF - + Calls _download_multi_pdf with the given parameters and returns a task ID """ + task_id = str(uuid.uuid4()) frappe.enqueue( _download_multi_pdf, doctype=doctype, @@ -43,6 +43,7 @@ def download_multi_pdf( task_id=task_id, ) frappe.local.response["http_status_code"] = 201 + return {"task_id": task_id} def _download_multi_pdf( From 508e4d9ae3233aecdf95df4cf84fb9876a174b78 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 13 Mar 2024 13:09:16 +0530 Subject: [PATCH 06/10] fix: make filename more user-friendly Signed-off-by: Akhil Narang --- frappe/utils/print_format.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index a74850b4dd..d811490649 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -83,6 +83,7 @@ def _download_multi_pdf( PDF: A PDF generated by the concatenation of the mentioned input docs """ + filename = "" import json @@ -94,6 +95,7 @@ def _download_multi_pdf( if not isinstance(doctype, dict): result = json.loads(name) total_docs = len(result) + filename = f"{doctype}_" # Concatenating pdf files for idx, ss in enumerate(result): @@ -123,6 +125,7 @@ def _download_multi_pdf( total_docs = sum([len(doctype[dt]) for dt in doctype]) count = 1 for doctype_name in doctype: + filename += f"{doctype_name}_" for doc_name in doctype[doctype_name]: try: pdf_writer = frappe.get_print( @@ -156,7 +159,7 @@ def _download_multi_pdf( _file = frappe.get_doc( { "doctype": "File", - "file_name": f"{task_id}.pdf", + "file_name": f"{filename}{task_id}.pdf", "content": merged_pdf.getvalue(), "is_private": 1, } From 5e37ac740e6b7335bb1eaf8594418a74de2dbd97 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 13 Mar 2024 14:33:26 +0530 Subject: [PATCH 07/10] refactor(bulk_print): choose queue dynamically Update docstrings and type hints a bit Signed-off-by: Akhil Narang --- frappe/utils/print_format.py | 54 +++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index d811490649..40198e80fa 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -1,3 +1,5 @@ +import http +import json import os import uuid from io import BytesIO @@ -21,41 +23,52 @@ from frappe.www.printview import validate_print_permission @frappe.whitelist() def download_multi_pdf( - doctype, - name, - format=None, - no_letterhead=False, - letterhead=None, - options=None, + doctype: str | dict[str, list[str]], + name: str | list[str], + format: str | None = None, + no_letterhead: bool = False, + letterhead: str | None = None, + options: str | None = None, ): """ Calls _download_multi_pdf with the given parameters and returns a task ID """ task_id = str(uuid.uuid4()) + if isinstance(doctype, dict): + doc_count = sum([len(doctype[dt]) for dt in doctype]) + else: + doc_count = len(json.loads(name)) + frappe.enqueue( _download_multi_pdf, doctype=doctype, name=name, + task_id=task_id, format=format, no_letterhead=no_letterhead, letterhead=letterhead, options=options, - task_id=task_id, + queue="long" if doc_count > 20 else "short", ) - frappe.local.response["http_status_code"] = 201 + frappe.local.response["http_status_code"] = http.HTTPStatus.CREATED return {"task_id": task_id} def _download_multi_pdf( - doctype, name, format=None, no_letterhead=False, letterhead=None, options=None, task_id=None + doctype: str | dict[str, list[str]], + name: str | list[str], + task_id: str, + format: str | None = None, + no_letterhead: bool = False, + letterhead: str | None = None, + options: str | None = None, ): """Return a PDF compiled by concatenating multiple documents. The documents can be from a single DocType or multiple DocTypes. - Note: The design may seem a little weird, but it exists exists to - ensure backward compatibility. The correct way to use this function is to - pass a dict to doctype as described below + Note: The design may seem a little weird, but it exists to ensure backward compatibility. + The correct way to use this function is to pass a dict to doctype as described below NEW FUNCTIONALITY ================= @@ -80,13 +93,10 @@ def _download_multi_pdf( Print Format to be used Returns: - PDF: A PDF generated by the concatenation of the mentioned input docs - + Publishes a link to the PDF to the given task ID """ filename = "" - import json - pdf_writer = PdfWriter() if isinstance(options, str): @@ -116,8 +126,10 @@ def _download_multi_pdf( # Publish progress frappe.publish_progress( percent=(idx + 1) / total_docs * 100, - title=_("Please keep this tab open until the operation is complete."), - description=_(f"Printed {idx + 1} documents out of {total_docs}."), + title=_("PDF Generation in Progress"), + description=_( + f"{idx + 1}/{total_docs} complete | Please leave this tab open until completion." + ), task_id=task_id, ) @@ -149,8 +161,10 @@ def _download_multi_pdf( count += 1 frappe.publish_progress( percent=count / total_docs * 100, - title=_("Please keep this tab open until the operation is complete."), - description=_(f"Printed {count} documents out of {total_docs}."), + title=_("PDF Generation in Progress"), + description=_( + f"{count}/{total_docs} complete | Please leave this tab open until completion." + ), task_id=task_id, ) From 0ec3e4a683f247a4921b70b467018fbe1f40b8de Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 13 Mar 2024 14:55:14 +0530 Subject: [PATCH 08/10] refactor: add in a new endpoint for background printing Let the original one stay as-is for backward compatibility Signed-off-by: Akhil Narang --- .../public/js/frappe/list/bulk_operations.js | 2 +- frappe/utils/print_format.py | 90 +++++++++++++------ 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index fd1f852d5a..eee6980dfd 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -106,7 +106,7 @@ export default class BulkOperations { } frappe - .call("frappe.utils.print_format.download_multi_pdf", { + .call("frappe.utils.print_format.download_multi_pdf_async", { doctype: this.doctype, name: json_string, format: print_format, diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index 40198e80fa..441f5fa79e 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -31,7 +31,22 @@ def download_multi_pdf( options: str | None = None, ): """ - Calls _download_multi_pdf with the given parameters and returns a task ID + Calls _download_multi_pdf with the given parameters and returns the response + """ + return _download_multi_pdf(doctype, name, format, no_letterhead, options) + + +@frappe.whitelist() +def download_multi_pdf_async( + doctype: str | dict[str, list[str]], + name: str | list[str], + format: str | None = None, + no_letterhead: bool = False, + letterhead: str | None = None, + options: str | None = None, +): + """ + Calls _download_multi_pdf with the given parameters in a background job, returns task ID """ task_id = str(uuid.uuid4()) if isinstance(doctype, dict): @@ -57,11 +72,11 @@ def download_multi_pdf( def _download_multi_pdf( doctype: str | dict[str, list[str]], name: str | list[str], - task_id: str, format: str | None = None, no_letterhead: bool = False, letterhead: str | None = None, options: str | None = None, + task_id: str | None = None, ): """Return a PDF compiled by concatenating multiple documents. @@ -121,16 +136,23 @@ def _download_multi_pdf( pdf_options=options, ) except Exception: - frappe.publish_realtime(task_id=task_id, message={"message": "Failed"}) + if task_id: + frappe.publish_realtime(task_id=task_id, message={"message": "Failed"}) # Publish progress - frappe.publish_progress( - percent=(idx + 1) / total_docs * 100, - title=_("PDF Generation in Progress"), - description=_( - f"{idx + 1}/{total_docs} complete | Please leave this tab open until completion." - ), - task_id=task_id, + if task_id: + frappe.publish_progress( + percent=(idx + 1) / total_docs * 100, + title=_("PDF Generation in Progress"), + description=_( + f"{idx + 1}/{total_docs} complete | Please leave this tab open until completion." + ), + task_id=task_id, + ) + + if task_id is None: + frappe.local.response.filename = "{doctype}.pdf".format( + doctype=doctype.replace(" ", "-").replace("/", "-") ) else: @@ -151,35 +173,45 @@ def _download_multi_pdf( pdf_options=options, ) except Exception: - frappe.publish_realtime(task_id=task_id, message="Failed") + if task_id: + frappe.publish_realtime(task_id=task_id, message="Failed") frappe.log_error( title="Error in Multi PDF download", message=f"Permission Error on doc {doc_name} of doctype {doctype_name}", reference_doctype=doctype_name, reference_name=doc_name, ) + count += 1 - frappe.publish_progress( - percent=count / total_docs * 100, - title=_("PDF Generation in Progress"), - description=_( - f"{count}/{total_docs} complete | Please leave this tab open until completion." - ), - task_id=task_id, - ) + + if task_id: + frappe.publish_progress( + percent=count / total_docs * 100, + title=_("PDF Generation in Progress"), + description=_( + f"{count}/{total_docs} complete | Please leave this tab open until completion." + ), + task_id=task_id, + ) + if task_id is None: + frappe.local.response.filename = f"{name}.pdf" with BytesIO() as merged_pdf: pdf_writer.write(merged_pdf) - _file = frappe.get_doc( - { - "doctype": "File", - "file_name": f"{filename}{task_id}.pdf", - "content": merged_pdf.getvalue(), - "is_private": 1, - } - ) - _file.save() - frappe.publish_realtime(f"task_progress:{task_id}", message={"file_url": _file.unique_url}) + if task_id: + _file = frappe.get_doc( + { + "doctype": "File", + "file_name": f"{filename}{task_id}.pdf", + "content": merged_pdf.getvalue(), + "is_private": 1, + } + ) + _file.save() + frappe.publish_realtime(f"task_progress:{task_id}", message={"file_url": _file.unique_url}) + else: + frappe.local.response.filecontent = merged_pdf.getvalue() + frappe.local.response.type = "pdf" @deprecated From 6a5af14049bf21f34bd6815a7c55d83213a4df28 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 13 Mar 2024 15:03:34 +0530 Subject: [PATCH 09/10] fix: unsubscribe from task after completion Also update event name to be more logical Signed-off-by: Akhil Narang --- frappe/public/js/frappe/list/bulk_operations.js | 4 +++- frappe/utils/print_format.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index eee6980dfd..de48f33456 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -117,10 +117,12 @@ export default class BulkOperations { .then((response) => { let task_id = response.message.task_id; frappe.realtime.task_subscribe(task_id); - frappe.realtime.on(`task_progress:${task_id}`, (data) => { + frappe.realtime.on(`task_complete:${task_id}`, (data) => { frappe.msgprint( `Please click here to download the PDF` ); + frappe.realtime.task_unsubscribe(task_id); + frappe.realtime.off(`task_complete:${task_id}`); }); dialog.hide(); }); diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index 441f5fa79e..fde49db3a0 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -208,7 +208,7 @@ def _download_multi_pdf( } ) _file.save() - frappe.publish_realtime(f"task_progress:{task_id}", message={"file_url": _file.unique_url}) + frappe.publish_realtime(f"task_complete:{task_id}", message={"file_url": _file.unique_url}) else: frappe.local.response.filecontent = merged_pdf.getvalue() frappe.local.response.type = "pdf" From 5f087edab76ecd051499f2e9178d1e853b417c59 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Wed, 13 Mar 2024 15:50:15 +0530 Subject: [PATCH 10/10] refactor: make download button a primary action, update text Signed-off-by: Akhil Narang --- frappe/public/js/frappe/list/bulk_operations.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index de48f33456..464c90a8e8 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -118,9 +118,15 @@ export default class BulkOperations { let task_id = response.message.task_id; frappe.realtime.task_subscribe(task_id); frappe.realtime.on(`task_complete:${task_id}`, (data) => { - frappe.msgprint( - `Please click here to download the PDF` - ); + frappe.msgprint({ + title: __("Bulk PDF Export"), + message: __("Your PDF is ready for download"), + primary_action: { + label: __("Download PDF"), + client_action: "window.open", + args: data.file_url, + }, + }); frappe.realtime.task_unsubscribe(task_id); frappe.realtime.off(`task_complete:${task_id}`); });