diff --git a/cypress/integration/list_view.js b/cypress/integration/list_view.js index 537db0247e..0618afb9ec 100644 --- a/cypress/integration/list_view.js +++ b/cypress/integration/list_view.js @@ -25,6 +25,7 @@ context("List View", () => { "Edit", "Export", "Assign To", + "Clear Assignment", "Apply Assignment Rule", "Add Tags", "Print", @@ -35,7 +36,7 @@ context("List View", () => { cy.get(".list-header-subject > .list-subject > .list-check-all").click(); cy.findByRole("button", { name: "Actions" }).click(); cy.get(".dropdown-menu li:visible .dropdown-item") - .should("have.length", 9) + .should("have.length", 10) .each((el, index) => { cy.wrap(el).contains(actions[index]); }) diff --git a/frappe/desk/form/assign_to.py b/frappe/desk/form/assign_to.py index e0de030303..c7dc3cab5b 100644 --- a/frappe/desk/form/assign_to.py +++ b/frappe/desk/form/assign_to.py @@ -175,6 +175,20 @@ def remove(doctype, name, assign_to, ignore_permissions=False): ) +@frappe.whitelist() +def remove_multiple(doctype, names, ignore_permissions=False): + docname_list = json.loads(names) + + for name in docname_list: + assignments = get({"doctype": doctype, "name": name}) + + if not assignments: + continue + + for assignment in assignments: + remove(doctype, name, assignment.get("owner"), ignore_permissions) + + @frappe.whitelist() def close(doctype: str, name: str, assign_to: str, ignore_permissions=False): if assign_to != frappe.session.user: diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index 22cf51166d..3ec4c182f6 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -196,6 +196,27 @@ export default class BulkOperations { } } + clear_assignment(docnames, done) { + if (docnames.length > 0) { + frappe + .call({ + method: "frappe.desk.form.assign_to.remove_multiple", + args: { + doctype: this.doctype, + names: docnames, + ignore_permissions: true, + }, + freeze: true, + freeze_message: "Removing assignments...", + }) + .then(() => { + done(); + }); + } else { + frappe.msgprint(__("Select records for removing assignment")); + } + } + apply_assignment_rule(docnames, done) { if (docnames.length > 0) { frappe diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index ca8f883693..72f3cbb589 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -1814,6 +1814,30 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { }; }; + const bulk_assignment_clear = () => { + return { + label: __("Clear Assignment", null, "Button in list view actions menu"), + action: () => { + frappe.confirm( + "Are you sure you want to clear the assignments?", + () => { + this.disable_list_update = true; + bulk_operations.clear_assignment(this.get_checked_items(true), () => { + this.disable_list_update = false; + this.clear_checked_items(); + this.refresh(); + }); + }, + () => { + this.clear_checked_items(); + this.refresh(); + } + ); + }, + standard: true, + }; + }; + const bulk_assignment_rule = () => { return { label: __("Apply Assignment Rule", null, "Button in list view actions menu"), @@ -1982,6 +2006,8 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { // bulk assignment actions_menu_items.push(bulk_assignment()); + actions_menu_items.push(bulk_assignment_clear()); + actions_menu_items.push(bulk_assignment_rule()); actions_menu_items.push(bulk_add_tags());