
Hey Team,
Is this feature available in frappe 14 ?

Hey Team,
Is this feature available in frappe 14 ?
we added this by making changes in the backend files
can you please guide me
Do you have knowlege in the backend
yes i do
What is your requriments and what is the purpose of these buttons
The button actions should change values of select field
Can you explain with an example
okay suppose i want to change status of Lead. button dropdown should contain options such as draft, converted etc. and selecting the option should result in changing status.
Ok let me create the logic for this one i will update you once i complete
currently i m using to create chat
thank you . looking forward for it
sorry for being late i have been busy in my project so couldn’t manage the time to update you
We are working on a new project with same senario once this is compeleted i will share the step by step guide for you thank you for your patience
@Ashique Hey
thanks for the patience here is our custom script and final results
Hey, thank you.
can you share the script
@Ashique here is the complete script to add button in list view and perform workflow actions hope this helps ![]()
i suggest you look at the script carefully and adjust it as per your requirment
as this is based on our requirment
what this script will do
it will show the status button in the list view currrently we have 3 status pending lvl 1 approve and submit so on click it will goto lvl 1 approved and then again on click it will goto submit you can also add multiple buttons in the dropdown to perform same actions
this is the final outcome
// List view settings for Shift Request
frappe.listview_settings['Shift Request'] = {
hide_name_column : true,
button: {
// Always show custom action buttons
show(doc) {
return true;
},
// Define buttons per row
get_label(doc) {
// Status button changes based on docstatus
const status_button = (() => {
if (doc.docstatus === 1) {
return `<button class="btn btn-xs btn-default" title="Approved">
<i class="fa fa-check-circle text-success"></i> Approved
</button>`;
} else if (doc.docstatus === 2) {
return `<button class="btn btn-xs btn-default" title="Cancelled">
<i class="fa fa-times-circle text-danger"></i> Cancelled
</button>`;
}
// Show action buttons based on role and workflow state
if (frappe.user.has_role("Shift Request LV-1") && doc.workflow_state === "Pending") {
return `<button onClick="approveFunction(event, this, '${doc.name}')" class="btn btn-xs btn-default" title="Approve">
<i class="fa fa-hourglass-half text-warning"></i> Approve
</button>`;
} else if (frappe.user.has_role("Shift Request Approver") && doc.workflow_state === "LV-1 Approved") {
return `<button onClick="submitFunction(event, this, '${doc.name}')" class="btn btn-xs btn-default" title="Submit">
<i class="fa fa-hourglass-half text-warning"></i> Submit
</button>`;
}
})();
// Combine all buttons (status + view/edit/delete)
const buttons = [
status_button,
`<button onClick="viewFunction(event, this, '${doc.name}')" class="btn btn-xs btn-default" title="View">
<i class="fa fa-eye"></i>
</button>`,
`<button onClick="editFunction(event, this, '${doc.name}')" class="btn btn-xs btn-default" title="Edit">
<i class="fa fa-edit"></i>
</button>`,
`<button onClick="deleteFunction(event, this, '${doc.name}')" class="btn btn-xs btn-default" title="Delete">
<i class="fa fa-trash"></i>
</button>`
];
return `
<span class="btn-group list-actions-extended" style="display: flex; gap: 4px;">
${buttons.join('\n')}
</span>
`;
},
get_description() {
return '';
}
},
onload(listview) {
// Store listview globally for refresh use
window.current_shift_listview = listview;
// Add custom status filter
listview.page.add_field({
fieldname: 'docstatus',
label: 'Status',
fieldtype: 'Select',
options: [0, 1, 2],
default: null,
input_class: 'input-xs',
placeholder: 'Status',
is_filter: 1,
condition: '=',
onchange: () => listview.refresh()
}, listview.page.page_form.find('.standard-filter-section'));
// Replace filter option labels
const doc_filter = document.querySelector("select[data-fieldname='docstatus']");
if (doc_filter) {
doc_filter.innerHTML = '';
doc_filter.add(new Option('', ''));
doc_filter.add(new Option('Pending Approval', '0'));
doc_filter.add(new Option('Approved', '1'));
doc_filter.add(new Option('Cancelled', '2'));
}
// Remove Frappe's default action buttons
new MutationObserver(() => {
$('.list-row').find('.list-actions .btn-action').remove();
}).observe(document.body, { childList: true, subtree: true });
}
};
// --- Utility Functions ---
// Prevent event bubbling and default behavior
function stopEvent(event) {
event.preventDefault();
event.stopPropagation();
}
// Delete document with confirmation
window.deleteFunction = function (event, el, doc_name) {
stopEvent(event);
frappe.confirm('Are you sure you want to delete this record?', () => {
frappe.call({
method: 'frappe.client.delete',
args: { doctype: 'Shift Request', name: doc_name },
callback: () => {
frappe.show_alert('Deleted');
window.current_shift_listview.refresh();
}
});
});
};
// Navigate to form view
window.viewFunction = function (event, el, doc_name) {
stopEvent(event);
frappe.set_route('Form', 'Shift Request', doc_name);
};
// Show editable dialog and update document
window.editFunction = function (event, el, doc_name) {
stopEvent(event);
frappe.call({
method: 'frappe.client.get',
args: {
doctype: 'Shift Request',
name: doc_name
},
callback({ message: doc }) {
const d = new frappe.ui.Dialog({
title: `Edit Shift Request: ${doc.name}`,
fields: [
{ fieldtype: 'Section Break', label: 'Shift Details' },
{
label: 'Shift Type',
fieldname: 'shift_type',
fieldtype: 'Link',
options: 'Shift Type',
default: doc.shift_type,
reqd: 1,
get_query: () => ({
filters: [
['name', 'in', [
'add your shift type if needed'
]]
]
})
},
{ fieldtype: 'Column Break' },
{ fieldtype: 'Section Break' },
{
label: 'From Date',
fieldname: 'from_date',
fieldtype: 'Date',
default: doc.from_date,
reqd: 1
},
{ fieldtype: 'Column Break' },
{
label: 'From Time',
fieldname: 'from_time',
fieldtype: 'Time',
default: doc.from_time,
reqd: 1
},
{ fieldtype: 'Section Break' },
{
label: 'To Date',
fieldname: 'to_date',
fieldtype: 'Date',
default: doc.to_date,
reqd: 1
},
{ fieldtype: 'Column Break' },
{
label: 'To Time',
fieldname: 'to_time',
fieldtype: 'Time',
default: doc.to_time,
reqd: 1
},
],
primary_action_label: 'Update',
primary_action(values) {
Object.assign(doc, values);
frappe.call({
method: 'frappe.client.save',
args: { doc },
callback: () => {
frappe.show_alert({ message: 'Updated successfully', indicator: 'green' });
d.hide();
window.current_shift_listview.refresh();
}
});
}
});
d.show();
}
});
};
// Approve document
window.approveFunction = function (event, el, doc_name) {
stopEvent(event);
frappe.confirm(`Approve ${doc_name}?`, () => {
// Fetch document before applying workflow
frappe.call({
method: 'frappe.client.get',
args: { doctype: 'Shift Request', name: doc_name },
callback: ({ message: doc }) => {
if (!doc) return frappe.msgprint('Document not found');
// Apply workflow action
frappe.xcall('frappe.model.workflow.apply_workflow', {
doc: doc,
action: 'Approve' // Can be made dynamic based on state
}).then(() => {
frappe.show_alert({ message: 'Approved Successfully', indicator: 'green' });
window.current_shift_listview.refresh();
});
}
});
});
};
// Submit (approve) document
window.submitFunction = function (event, el, doc_name) {
stopEvent(event);
frappe.confirm(`Approve ${doc_name}?`, () => {
frappe.call({
method: 'frappe.client.get',
args: { doctype: 'Shift Request', name: doc_name },
callback: ({ message: doc }) => {
frappe.call({
method: 'frappe.client.submit',
args: { doc },
callback: () => {
frappe.show_alert({
message: 'Approved',
indicator: 'green'
});
window.current_shift_listview.refresh();
}
});
}
});
});
};