diff options
| author | Aaron Bohy <aab@odoo.com> | 2020-03-27 20:18:16 +0000 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2020-03-30 09:55:08 +0000 |
| commit | 94583df492113211b5ab3afd9d5c25ae1fe30dba (patch) | |
| tree | 424fc82d0dd26ff4ec423de609cb7fd925cf5ba7 /addons/web/static | |
| parent | 8608a5ed8dc7d14432556d2c4c469e3f8deda7f1 (diff) | |
[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
Diffstat (limited to 'addons/web/static')
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_controller.js | 7 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/list/list_controller.js | 68 | ||||
| -rw-r--r-- | addons/web/static/tests/views/list_tests.js | 101 |
3 files changed, 163 insertions, 13 deletions
diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js index f0fd3cc8c75..bbfee26e51f 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -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(); } diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js index 49e2e12ff15..c41e253c583 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -267,6 +267,39 @@ var ListController = BasicController.extend({ .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 * discarded in that case. @@ -289,6 +322,24 @@ var ListController = BasicController.extend({ }); }, /** + * 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. diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 41462827413..235cffda702 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -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); |
