Skip to content

Commit

Permalink
List view bulk edit option (#5107)
Browse files Browse the repository at this point in the history
* added actions button for bulk operations

also included bulk edit option

* page html refactor and added show/hide action option

* copy field object to avoid mutation

* commonify update method and other refactor

* fixed bug with progress bar level and minor fix with 'value' field display

* fixed frappe/erpnext#13063

* commonify field control method and removed unwanted code

* separate method for submit and cancel

* [minor] msgprint change

* refresh list on complete

* requested changes and refactor

* codacy fix

* code formatting, changed var name

* conflict fix

* description option for progress dialog

* extracted bulk operations to a separate file

* Refactor

commonified redundant method
get_json -> parse_json

* rename change_df -> replace_field
  • Loading branch information
surajshetty3416 authored and rmehta committed Mar 5, 2018
1 parent 2fc96e1 commit 1202ff1
Show file tree
Hide file tree
Showing 15 changed files with 513 additions and 268 deletions.
6 changes: 5 additions & 1 deletion frappe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1468,4 +1468,8 @@ def get_version(doctype, name, limit = None, head = False, raise_err = True):

@whitelist(allow_guest = True)
def ping():
return "pong"
return "pong"

def parse_json(val):
from frappe.utils import parse_json
return parse_json(val)
6 changes: 3 additions & 3 deletions frappe/async.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ def full_path(_file):
def is_file_old(file_path):
return ((time.time() - os.stat(file_path).st_mtime) > TASK_LOG_MAX_AGE)

def publish_progress(percent, title=None, doctype=None, docname=None):
publish_realtime('progress', {'percent': percent, 'title': title},
def publish_progress(percent, title=None, doctype=None, docname=None, description=None):
publish_realtime('progress', {'percent': percent, 'title': title, 'description': description},
user=frappe.session.user, doctype=doctype, docname=docname)

def publish_realtime(event=None, message=None, room=None,
Expand Down Expand Up @@ -200,6 +200,6 @@ def get_task_progress_room(task_id):
# frappe.chat
def get_chat_room(room):
room = ''.join([frappe.local.site, ":room:", room])

return room
# end frappe.chat room
7 changes: 5 additions & 2 deletions frappe/core/doctype/data_import/data_import.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ frappe.ui.form.on('Data Import', {
frm.disable_save();
frm.dashboard.clear_headline();
if (frm.doc.reference_doctype && !frm.doc.import_file) {
frm.dashboard.add_comment(__('Please attach a file to import'));
frm.page.set_indicator(__('Please attach a file to import'), 'orange');
} else {
if (frm.doc.import_status) {
frm.dashboard.add_comment(frm.doc.import_status);
const listview_settings = frappe.listview_settings['Data Import'];
const indicator = listview_settings.get_indicator(frm.doc);

frm.page.set_indicator(indicator[0], indicator[1]);

if (frm.doc.import_status==="In Progress") {
frm.dashboard.add_progress("Data Import Progress", "0");
Expand Down
15 changes: 10 additions & 5 deletions frappe/desk/doctype/bulk_update/bulk_update.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
frappe.ui.form.on('Bulk Update', {
refresh: function(frm) {
frm.page.set_primary_action(__('Update'), function() {
if(!frm.doc.update_value){
if (!frm.doc.update_value) {
frappe.throw(__('Field "value" is mandatory. Please specify value to be updated'));
}
else{
} else {
frappe.call({
method: 'frappe.desk.doctype.bulk_update.bulk_update.update',
args: {
Expand All @@ -17,13 +16,19 @@ frappe.ui.form.on('Bulk Update', {
condition: frm.doc.condition,
limit: frm.doc.limit
},
callback: function() {
frappe.hide_progress();
}).then(r => {
let failed = r.message;
if (!failed) failed = [];

if (failed.length && !r._server_messages) {
frappe.throw(__('Cannot update {0}', [failed.map(f => f.bold ? f.bold(): f).join(', ')]));
}
frappe.hide_progress();
});
}
});
},

document_type: function(frm) {
// set field options
if(!frm.doc.document_type) return;
Expand Down
54 changes: 39 additions & 15 deletions frappe/desk/doctype/bulk_update/bulk_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,47 @@ def update(doctype, field, value, condition='', limit=500):
if ';' in condition:
frappe.throw(_('; not allowed in condition'))

items = frappe.db.sql_list('''select name from `tab{0}`{1} limit 0, {2}'''.format(doctype,
condition, limit), debug=1)
n = len(items)
docnames = frappe.db.sql_list(
'''select name from `tab{0}`{1} limit 0, {2}'''.format(doctype, condition, limit)
)
data = {}
data[field] = value
return submit_cancel_or_update_docs(doctype, docnames, 'update', data)

for i, d in enumerate(items):
doc = frappe.get_doc(doctype, d)
doc.set(field, value)
@frappe.whitelist()
def submit_cancel_or_update_docs(doctype, docnames, action='submit', data=None):
docnames = frappe.parse_json(docnames)

if data:
data = frappe.parse_json(data)

failed = []

for i, d in enumerate(docnames, 1):
doc = frappe.get_doc(doctype, d)
try:
doc.save()
except Exception as e:
frappe.msgprint(_("Validation failed for {0}").format(frappe.bold(doc.name)))
raise e
if action == 'submit':
doc.submit()
message = _('Submiting {0}').format(doctype)
elif action == 'cancel':
doc.cancel()
message = _('Cancelling {0}').format(doctype)
elif action == 'update':
doc.update(data)
doc.save()
message = _('Updating {0}').format(doctype)

show_progress(docnames, message, i, d)

frappe.publish_progress(float(i)*100/n,
title = _('Updating Records'), doctype='Bulk Update', docname='Bulk Update')
except Exception:
failed.append(d)
return failed

# clear messages
frappe.local.message_log = []
frappe.msgprint(_('{0} records updated').format(n), title=_('Success'), indicator='green')
def show_progress(docnames, message, i, description):
n = len(docnames)
if n >= 10:
frappe.publish_progress(
float(i) * 100 / n,
title = message,
description = description
)
4 changes: 2 additions & 2 deletions frappe/desk/reportview.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@ def delete_items():
frappe.delete_doc(doctype, d)
if len(il) >= 5:
frappe.publish_realtime("progress",
dict(progress=[i+1, len(il)], title=_('Deleting {0}').format(doctype)),
user=frappe.session.user)
dict(progress=[i+1, len(il)], title=_('Deleting {0}').format(doctype), description=d),
user=frappe.session.user)
except Exception:
failed.append(d)

Expand Down
60 changes: 41 additions & 19 deletions frappe/public/js/frappe/form/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,19 +119,27 @@ frappe.ui.form.Layout = Class.extend({
});
},

make_field: function(df, colspan, render = false) {
replace_field: function(fieldname, df, render) {
df.fieldname = fieldname; // change of fieldname is avoided
if (this.fields_dict[fieldname] && this.fields_dict[fieldname].df) {
const fieldobj = this.init_field(df, render);
this.fields_dict[fieldname].$wrapper.remove();
this.fields_list.splice(this.fields_dict[fieldname], 1, fieldobj);
this.fields_dict[fieldname] = fieldobj;
if (this.frm) {
fieldobj.perm = this.frm.perm;
}
this.section.fields_list.splice(this.section.fields_dict[fieldname], 1, fieldobj);
this.section.fields_dict[fieldname] = fieldobj;
this.refresh();
}
},

make_field: function(df, colspan, render) {
!this.section && this.make_section();
!this.column && this.make_column();

var fieldobj = frappe.ui.form.make_control({
df: df,
doctype: this.doctype,
parent: this.column.wrapper.get(0),
frm: this.frm,
render_input: render
});

fieldobj.layout = this;
const fieldobj = this.init_field(df, render);
this.fields_list.push(fieldobj);
this.fields_dict[df.fieldname] = fieldobj;
if(this.frm) {
Expand All @@ -141,6 +149,20 @@ frappe.ui.form.Layout = Class.extend({
this.section.fields_list.push(fieldobj);
this.section.fields_dict[df.fieldname] = fieldobj;
},

init_field: function(df, render = false) {
const fieldobj = frappe.ui.form.make_control({
df: df,
doctype: this.doctype,
parent: this.column.wrapper.get(0),
frm: this.frm,
render_input: render
});

fieldobj.layout = this;
return fieldobj;
},

make_page: function(df) {
var me = this,
head = $('<div class="form-clickable-section text-center">\
Expand Down Expand Up @@ -234,7 +256,7 @@ frappe.ui.form.Layout = Class.extend({
if(cnt % 2) {
$this.addClass("shaded-section");
}
cnt ++;
cnt++;
}
});
},
Expand Down Expand Up @@ -414,11 +436,9 @@ frappe.ui.form.Layout = Class.extend({
} else {
field.grid.grid_rows[0].toggle_view(true);
}
}
else if(field.editor) {
} else if(field.editor) {
field.editor.set_focus();
}
else if(field.$input) {
} else if(field.$input) {
field.$input.focus();
}
},
Expand Down Expand Up @@ -632,11 +652,13 @@ frappe.ui.form.Column = Class.extend({
</form>\
</div>').appendTo(this.section.body)
.find("form")
.on("submit", function() { return false; });
.on("submit", function() {
return false;
});

if(this.df.label) {
$('<label class="control-label">'+ __(this.df.label)
+'</label>').appendTo(this.wrapper);
if (this.df.label) {
$('<label class="control-label">' + __(this.df.label)
+ '</label>').appendTo(this.wrapper);
}
},
resize_all_columns: function() {
Expand Down
26 changes: 0 additions & 26 deletions frappe/public/js/frappe/list/base_list.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ frappe.views.BaseList = class BaseList {
this.method = 'frappe.desk.reportview.get';

this.can_create = frappe.model.can_create(this.doctype);
this.can_delete = frappe.model.can_delete(this.doctype);
this.can_write = frappe.model.can_write(this.doctype);

this.fields = [];
Expand Down Expand Up @@ -146,34 +145,9 @@ frappe.views.BaseList = class BaseList {

setup_page_head() {
this.page.set_title(this.page_title);
this.set_menu_items();
this.set_breadcrumbs();
}

set_menu_items() {
this.page.clear_menu();
const $secondary_action = this.page.set_secondary_action(
this.secondary_action.label,
this.secondary_action.action,
this.secondary_action.icon
);
if (!this.secondary_action.icon) {
$secondary_action.addClass('hidden-xs');
} else {
$secondary_action.addClass('visible-xs');
}

this.menu_items.map(item => {
if (item.condition && item.condition() === false) {
return;
}
const $item = this.page.add_menu_item(item.label, item.action, item.standard);
if (item.class) {
$item && $item.addClass(item.class);
}
});
}

set_breadcrumbs() {
frappe.breadcrumbs.add(this.meta.module, this.doctype);
}
Expand Down
Loading

0 comments on commit 1202ff1

Please sign in to comment.