[IMP] web: adapt delete feature to list selection changes
Following the new selection feature in list views, this commit adapts the delete action. Part of task 2185145
This commit is contained in:
@@ -346,9 +346,10 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
|
||||
.then(self._onDeletedRecords.bind(self, ids));
|
||||
}
|
||||
if (this.confirmOnDelete) {
|
||||
Dialog.confirm(this, _t("Are you sure you want to delete this record ?"), {
|
||||
confirm_callback: doIt,
|
||||
});
|
||||
const message = ids.length > 1 ?
|
||||
_t("Are you sure you want to delete these records?") :
|
||||
_t("Are you sure you want to delete this record?");
|
||||
Dialog.confirm(this, message, { confirm_callback: doIt });
|
||||
} else {
|
||||
doIt();
|
||||
}
|
||||
|
||||
@@ -266,6 +266,39 @@ var ListController = BasicController.extend({
|
||||
return this.renderer.updateState(state, {noRender: true})
|
||||
.then(this._setMode.bind(this, 'readonly', id));
|
||||
},
|
||||
/**
|
||||
* Deletes records matching the current domain. We limit the number of
|
||||
* deleted records to the 'active_ids_limit' config parameter.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_deleteRecordsInCurrentDomain: function () {
|
||||
const doIt = async () => {
|
||||
const state = this.model.get(this.handle, {raw: true});
|
||||
const resIds = await this._domainToResIds(state.getDomain(), session.active_ids_limit);
|
||||
await this._rpc({
|
||||
model: this.modelName,
|
||||
method: 'unlink',
|
||||
args: [resIds],
|
||||
context: state.getContext(),
|
||||
});
|
||||
if (resIds.length === session.active_ids_limit) {
|
||||
const msg = _.str.sprintf(
|
||||
_t("Of the %d records selected, only the first %d have been deleted."),
|
||||
state.count, resIds.length
|
||||
);
|
||||
this.do_notify(_t('Warning'), msg);
|
||||
}
|
||||
this.reload();
|
||||
};
|
||||
if (this.confirmOnDelete) {
|
||||
Dialog.confirm(this, _t("Are you sure you want to delete these records ?"), {
|
||||
confirm_callback: doIt,
|
||||
});
|
||||
} else {
|
||||
doIt();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* To improve performance, list view must not be rerendered if it is asked
|
||||
* to discard all its changes. Indeed, only the in-edition row needs to be
|
||||
@@ -288,6 +321,24 @@ var ListController = BasicController.extend({
|
||||
self.updateButtons('readonly');
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Returns the ids of records matching the given domain.
|
||||
*
|
||||
* @private
|
||||
* @param {Array[]} domain
|
||||
* @param {integer} [limit]
|
||||
* @returns {integer[]}
|
||||
*/
|
||||
_domainToResIds: function (domain, limit) {
|
||||
return this._rpc({
|
||||
model: this.modelName,
|
||||
method: 'search',
|
||||
args: [domain],
|
||||
kwargs: {
|
||||
limit: limit,
|
||||
},
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @returns {DataExport} the export dialog widget
|
||||
* @private
|
||||
@@ -472,14 +523,7 @@ var ListController = BasicController.extend({
|
||||
let displayNotif = false;
|
||||
const state = this.model.get(this.handle, {raw: true});
|
||||
if (this.isDomainSelected) {
|
||||
resIds = await this._rpc({
|
||||
model: this.modelName,
|
||||
method: 'search',
|
||||
args: [state.getDomain()],
|
||||
kwargs: {
|
||||
limit: session.active_ids_limit,
|
||||
},
|
||||
});
|
||||
resIds = await this._domainToResIds(state.getDomain(), session.active_ids_limit);
|
||||
displayNotif = (resIds.length === session.active_ids_limit);
|
||||
} else {
|
||||
resIds = this.model.localIdsToResIds(this.selectedRecords);
|
||||
@@ -610,8 +654,12 @@ var ListController = BasicController.extend({
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onDeleteSelectedRecords: function () {
|
||||
this._deleteRecords(this.selectedRecords);
|
||||
_onDeleteSelectedRecords: async function () {
|
||||
if (this.isDomainSelected) {
|
||||
this._deleteRecordsInCurrentDomain();
|
||||
} else {
|
||||
this._deleteRecords(this.selectedRecords);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Handler called when the user clicked on the 'Discard' button.
|
||||
|
||||
@@ -2581,6 +2581,107 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('delete all records matching the domain', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
this.data.foo.records.push({id: 5, bar: true, foo: "xxx"});
|
||||
|
||||
var list = await createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree limit="2"><field name="foo"/></tree>',
|
||||
domain: [['bar', '=', true]],
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'unlink') {
|
||||
assert.deepEqual(args.args[0], [1, 2, 3, 5]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: {
|
||||
notification: NotificationService.extend({
|
||||
notify: function () {
|
||||
throw new Error('should not display a notification');
|
||||
},
|
||||
}),
|
||||
},
|
||||
viewOptions: {
|
||||
hasActionMenus: true,
|
||||
},
|
||||
});
|
||||
|
||||
assert.containsNone(list, 'div.o_control_panel .o_cp_action_menus');
|
||||
assert.containsN(list, 'tbody td.o_list_record_selector', 2, "should have 2 records");
|
||||
|
||||
await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
|
||||
|
||||
assert.containsOnce(list, 'div.o_control_panel .o_cp_action_menus');
|
||||
assert.containsOnce(list, '.o_list_selection_box .o_list_select_domain');
|
||||
|
||||
await testUtils.dom.click(list.$('.o_list_selection_box .o_list_select_domain'));
|
||||
await cpHelpers.toggleActionMenu(list);
|
||||
await cpHelpers.toggleMenuItem(list, "Delete");
|
||||
|
||||
assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed');
|
||||
await testUtils.dom.click($('.modal-footer .btn-primary'));
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('delete all records matching the domain (limit reached)', async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
this.data.foo.records.push({id: 5, bar: true, foo: "xxx"});
|
||||
this.data.foo.records.push({id: 6, bar: true, foo: "yyy"});
|
||||
|
||||
var list = await createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree limit="2"><field name="foo"/></tree>',
|
||||
domain: [['bar', '=', true]],
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'unlink') {
|
||||
assert.deepEqual(args.args[0], [1, 2, 3, 5]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
services: {
|
||||
notification: NotificationService.extend({
|
||||
notify: function () {
|
||||
assert.step('notify');
|
||||
},
|
||||
}),
|
||||
},
|
||||
session: {
|
||||
active_ids_limit: 4,
|
||||
},
|
||||
viewOptions: {
|
||||
hasActionMenus: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
assert.containsNone(list, 'div.o_control_panel .o_cp_action_menus');
|
||||
assert.containsN(list, 'tbody td.o_list_record_selector', 2, "should have 2 records");
|
||||
|
||||
await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
|
||||
|
||||
assert.containsOnce(list, 'div.o_control_panel .o_cp_action_menus');
|
||||
assert.containsOnce(list, '.o_list_selection_box .o_list_select_domain');
|
||||
|
||||
await testUtils.dom.click(list.$('.o_list_selection_box .o_list_select_domain'));
|
||||
await cpHelpers.toggleActionMenu(list);
|
||||
await cpHelpers.toggleMenuItem(list, "Delete");
|
||||
|
||||
assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed');
|
||||
await testUtils.dom.click($('.modal-footer .btn-primary'));
|
||||
|
||||
assert.verifySteps(['notify']);
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('archiving one record', async function (assert) {
|
||||
assert.expect(12);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user