Delete from list view

Hello all

I found that when we have workflow enabled for doctype, I can’t find the delete option from the listview of that doctype, if i inactive the workflow then i will be able to delete the record from the listview until i make the workflow active again. how can i solve this, any suggestions will be appreciated. Thank you

2 Likes

Please share the workflow image, that you created in the Workflow doctype.

That possible, when you haven’t added a Doc Status 2, so first you have to add the doc status 2 and check it.

i’ve added the workflow state 2 in my workflow, still I am not able to delete the records

Hey, I am correcting my statement, I forgot one thing from my brain that when workflow is enabled submit, canceled, and delete buttons you can’t access from listview so they don’t show in listview.

is there anything we can do about it if we want to perform bulk delete from Listview?

Maybe it’s not possible if workflow is enabled. If have a solution then i will update you.

Yeah I have the same experience - when you have a workflow activated, it’s not possible to delete from list_view (presumbly because there is no option to create a ‘delete’ action from the workflow)

Hello all,
here is a reason:

I had to do small workaround for bulk edit on specific doctypes with workflow.

Jiri Sir

1 Like

Hello. Can you please share what was the workaround?

Hello @DonDowner ,
I used client script(apply to List) and original parts of js code for bulk edit:

function edit(listview, docnames, field_mappings, done) {
		let field_options = Object.keys(field_mappings).sort(function (a, b) { //řazení polí
			return __(cstr(field_mappings[a].label)).localeCompare(
				cstr(__(field_mappings[b].label))
			);
		});
		const status_regex = /status/i;

		const default_field = field_options.find((value) => status_regex.test(value));

		const dialog = new frappe.ui.Dialog({
			title: __("Bulk Edit"),
			fields: [
				{
					fieldtype: "Select",
					options: field_options,
					default: default_field,
					label: __("Field"),
					fieldname: "field",
					reqd: 1,
					onchange: () => {
						set_value_field(dialog);
					},
				},
				{
					fieldtype: "Data",
					label: __("Value"),
					fieldname: "value",
					onchange() {
						show_help_text();
					},
				},
			],
			primary_action: ({ value }) => {
				const fieldname = field_mappings[dialog.get_value("field")].fieldname;
				dialog.disable_primary_action();
				frappe
					.call({
						method: "frappe.desk.doctype.bulk_update.bulk_update.submit_cancel_or_update_docs",
						args: {
							doctype: listview.doctype,
							freeze: true,
							docnames: docnames,
							action: "update",
							data: {
								[fieldname]: value || null,
							},
						},
					})
					.then((r) => {
						let failed = r.message || [];

						if (failed.length && !r._server_messages) {
							dialog.enable_primary_action();
							frappe.throw(
								__("Cannot update {0}", [
									failed.map((f) => (f.bold ? f.bold() : f)).join(", "),
								])
							);
						}
						done();
						dialog.hide();
						frappe.show_alert(__("Updated successfully"));
					});
			},
			primary_action_label: __("Update {0} records", [docnames.length]),
		});
		function set_value_field(dialogObj) {
			const new_df = Object.assign({}, field_mappings[dialogObj.get_value("field")]);
			/* if the field label has status in it and
			if it has select fieldtype with no default value then
			set a default value from the available option. */
			if (
				new_df.label.match(status_regex) &&
				new_df.fieldtype === "Select" &&
				!new_df.default
			) {
				let options = [];
				if (typeof new_df.options === "string") {
					options = new_df.options.split("\n");
				}
				//set second option as default if first option is an empty string
				new_df.default = options[0] || options[1];
			}
			new_df.label = __("Value");
			new_df.onchange = show_help_text;

			delete new_df.depends_on;
			dialogObj.replace_field("value", new_df);
			show_help_text();
		}

		function show_help_text() {
			let value = dialog.get_value("value");
			if (value == null || value === "") {
				dialog.set_df_property(
					"value",
					"description",
					__("You have not entered a value. The field will be set to empty.")
				);
			} else {
				dialog.set_df_property("value", "description", "");
			}
		}

		dialog.refresh();
		dialog.show();
}
function bulk_edit(listview){
    
    //copy function that control editable docfields
    const is_field_editable = (field_doc) => {
		return (
			field_doc.fieldname &&
			frappe.model.is_value_type(field_doc) &&
			field_doc.fieldtype !== "Read Only" &&
			!field_doc.hidden &&
			!field_doc.read_only &&
			!field_doc.is_virtual
		);
	};
    
    
    let field_mappings = {};
    
    frappe.meta.get_docfields(listview.doctype).forEach((field_doc) => {
		if (is_field_editable(field_doc)) {
			field_mappings[field_doc.label] = Object.assign({}, field_doc);
		}
    });
    
    listview.disable_list_update = true;
	edit(listview,listview.get_checked_items(true), field_mappings, () => {
		listview.disable_list_update = false;
		listview.refresh();
	});
    
    
}

and finally I extended the original list functions (Task dct in this cause):

let original_settings = frappe.listview_settings.Task || {};

let add_custom_buttons = {
    refresh: function (listview){
          listview.page.add_action_item(__("Edit"), () => {bulk_edit(listview);});    
    }
};

$.extend( true, original_settings, add_custom_buttons);