From 9f053ce5ee37dde033c03eee88eee772528b526e Mon Sep 17 00:00:00 2001 From: AarDG10 Date: Fri, 17 Oct 2025 18:42:09 +0530 Subject: [PATCH] feat: Cancel Button Added for Data Import --- .../core/doctype/data_import/data_import.js | 28 ++++++++++++++++++- .../core/doctype/data_import/data_import.py | 19 ++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/data_import/data_import.js b/frappe/core/doctype/data_import/data_import.js index f45e5e3c15..af8e44e6de 100644 --- a/frappe/core/doctype/data_import/data_import.js +++ b/frappe/core/doctype/data_import/data_import.js @@ -42,6 +42,7 @@ frappe.ui.form.on("Data Import", { frm.page.set_indicator(__("In Progress"), "orange"); frm.trigger("update_primary_action"); + frm.trigger("show_cancel_import_btn"); // hide progress when complete if (data.current === data.total) { setTimeout(() => { @@ -108,7 +109,12 @@ frappe.ui.form.on("Data Import", { if (frm.doc.status !== "Success") { if (!frm.is_new() && frm.has_import_file()) { let label = frm.doc.status === "Pending" ? __("Start Import") : __("Retry"); - frm.page.set_primary_action(label, () => frm.events.start_import(frm)); + frm.page.set_primary_action(label, () => { + frm.events.start_import(frm); + if (label === "Retry") { + frm.trigger("show_cancel_import_btn"); + } + }); } else { frm.page.set_primary_action(__("Save"), () => frm.save()); } @@ -170,6 +176,26 @@ frappe.ui.form.on("Data Import", { }); }, + show_cancel_import_btn(frm) { + frm.add_custom_button(__("Cancel Import"), () => { + frappe.confirm( + __( + "This will terminate the job immediately and might be dangerous, are you sure?" + ), + () => { + frappe + .xcall("frappe.core.doctype.data_import.data_import.stop_data_import", { + doc_name: frm.doc.name, + }) + .then((r) => { + frappe.show_alert(__("Job Stopped Successfully")); + frm.reload_doc(); + }); + } + ); + }); + }, + show_report_error_button(frm) { if (frm.doc.status === "Error") { frappe.db diff --git a/frappe/core/doctype/data_import/data_import.py b/frappe/core/doctype/data_import/data_import.py index e49d1b93db..8bf62c6c9f 100644 --- a/frappe/core/doctype/data_import/data_import.py +++ b/frappe/core/doctype/data_import/data_import.py @@ -3,6 +3,8 @@ import os +from rq.command import send_stop_job_command +from rq.exceptions import InvalidJobOperation from rq.timeouts import JobTimeoutException import frappe @@ -12,7 +14,7 @@ from frappe.core.doctype.data_import.importer import Importer from frappe.model import CORE_DOCTYPES from frappe.model.document import Document from frappe.modules.import_file import import_file_by_path -from frappe.utils.background_jobs import enqueue, is_job_enqueued +from frappe.utils.background_jobs import enqueue, get_redis_conn, is_job_enqueued from frappe.utils.csvutils import validate_google_sheets_url BLOCKED_DOCTYPES = CORE_DOCTYPES - {"User", "Role", "Print Format"} @@ -151,6 +153,21 @@ def form_start_import(data_import: str): return di.start_import() +@frappe.whitelist() +def stop_data_import(doc_name: str): + """Stop a running Data Import job.""" + data_import = frappe.get_doc("Data Import", doc_name) + data_import.check_permission("write") + + rq_job_id = f"{frappe.local.site}||data_import||{doc_name}" + job_id = rq_job_id.replace(":", "|") # patching the change in job id format (for timestamp part) + try: + send_stop_job_command(connection=get_redis_conn(), job_id=job_id) + except InvalidJobOperation: + frappe.msgprint(_("Job is not running."), title=_("Invalid Operation")) + return {"status": "success", "message": "Job stopped successfully"} + + def start_import(data_import): """This method runs in background job""" data_import = frappe.get_doc("Data Import", data_import)