diff options
| author | Aaron Bohy <aab@odoo.com> | 2020-03-27 09:56:50 +0000 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2020-03-30 09:55:08 +0000 |
| commit | 8608a5ed8dc7d14432556d2c4c469e3f8deda7f1 (patch) | |
| tree | ef67e9f8e56c5d7feccb0a722088a3d196d3be0e /addons/web/static | |
| parent | 9755e8875bf8bae1881db38d3a0ec99d98d572a8 (diff) | |
[IMP] web: adapt (un)archive feature to list selection changes
Following the new selection feature in list views, this commit
adapts the archive and unarchive actions.
Part of task 2185145
Diffstat (limited to 'addons/web/static')
7 files changed, 152 insertions, 17 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 f5944ffe253..f0fd3cc8c75 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -242,7 +242,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { * Archive the current selection * * @private - * @param {string[]} ids + * @param {number[]} ids * @param {boolean} archive * @returns {Promise} */ diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index a69f6878023..8dc540a8861 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -812,6 +812,15 @@ var BasicModel = AbstractModel.extend({ }); }, /** + * Returns the list of res_ids for a given list of local ids. + * + * @param {string[]} localIds + * @returns {integer[]} + */ + localIdsToResIds: function (localIds) { + return localIds.map(localId => this.localData[localId].res_id); + }, + /** * This helper method is designed to help developpers that want to use a * field widget outside of a view. In that case, we want a way to create * data without actually performing a fetch. @@ -1286,16 +1295,13 @@ var BasicModel = AbstractModel.extend({ /** * Archive the given records * - * @param {Array} recordIDs local ids of the records to (un)archive + * @param {integer[]} resIDs ids of the records to archive * @param {string} parentID id of the parent resource to reload * @returns {Promise<string>} resolves to the parent id */ - actionArchive: function (recordIDs, parentID) { + actionArchive: function (resIDs, parentID) { var self = this; var parent = this.localData[parentID]; - var resIDs = _.map(recordIDs, function (recordID) { - return self.localData[recordID].res_id; - }); return this._rpc({ model: parent.model, method: 'action_archive', @@ -1318,16 +1324,13 @@ var BasicModel = AbstractModel.extend({ /** * Unarchive the given records * - * @param {Array} recordIDs local ids of the records to (un)archive + * @param {integer[]} resIDs ids of the records to unarchive * @param {string} parentID id of the parent resource to reload * @returns {Promise<string>} resolves to the parent id */ - actionUnarchive: function (recordIDs, parentID) { + actionUnarchive: function (resIDs, parentID) { var self = this; var parent = this.localData[parentID]; - var resIDs = _.map(recordIDs, function (recordID) { - return self.localData[recordID].res_id; - }); return this._rpc({ model: parent.model, method: 'action_unarchive', diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index 8af47e4cd4f..7147f7aee66 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -652,7 +652,6 @@ var FormController = BasicController.extend({ */ _onSave: function (ev) { ev.stopPropagation(); // Prevent x2m lines to be auto-saved - var self = this; this._disableButtons(); this.saveRecord().then(this._enableButtons.bind(this)).guardedCatch(this._enableButtons.bind(this)); }, @@ -679,7 +678,8 @@ var FormController = BasicController.extend({ * @param {boolean} archive */ _toggleArchiveState: function (archive) { - this._archive([this.handle], archive); + const resIds = this.model.localIdsToResIds([this.handle]); + this._archive(resIds, archive); }, }); diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js index cca0a43cb5e..a908eb0d138 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -496,7 +496,7 @@ var KanbanController = BasicController.extend({ var self = this; var archive = ev.data.archive; var column = ev.target; - var recordIds = _.pluck(column.records, 'db_id'); + var recordIds = _.pluck(column.records, 'id'); if (recordIds.length) { var prom = archive ? this.model.actionArchive(recordIds, column.db_id) : 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 922d87600c5..49e2e12ff15 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -12,6 +12,7 @@ var BasicController = require('web.BasicController'); var DataExport = require('web.DataExport'); var Dialog = require('web.Dialog'); var ListConfirmDialog = require('web.ListConfirmDialog'); +var session = require('web.session'); var _t = core._t; var qweb = core.qweb; @@ -464,9 +465,33 @@ var ListController = BasicController.extend({ * * @private * @param {boolean} archive + * @returns {Promise} */ - _toggleArchiveState: function (archive) { - this._archive(this.selectedRecords, archive); + _toggleArchiveState: async function (archive) { + let resIds; + 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, + }, + }); + displayNotif = (resIds.length === session.active_ids_limit); + } else { + resIds = this.model.localIdsToResIds(this.selectedRecords); + } + await this._archive(resIds, archive); + if (displayNotif) { + const msg = _.str.sprintf( + _t("Of the %d records selected, only the first %d have been archived/unarchived."), + state.count, resIds.length + ); + this.do_notify(_t('Warning'), msg); + } }, /** * Hide the create button in non-empty grouped editable list views, as an diff --git a/addons/web/static/tests/views/kanban_model_tests.js b/addons/web/static/tests/views/kanban_model_tests.js index 81deca04968..793a5749b46 100644 --- a/addons/web/static/tests/views/kanban_model_tests.js +++ b/addons/web/static/tests/views/kanban_model_tests.js @@ -157,7 +157,7 @@ QUnit.module('Views', { assert.strictEqual(xpadGroup.count, 1, 'xpad group has one record'); // archive the column 'xphone' - var recordIDs = _.pluck(xphoneGroup.data, 'id'); + var recordIDs = xphoneGroup.data.map(record => record.res_id); await model.actionArchive(recordIDs, xphoneGroup.id); state = model.get(resultID); xphoneGroup = _.findWhere(state.data, {res_id: 37}); diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index cf0736f86f1..41462827413 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -2627,6 +2627,113 @@ QUnit.module('Views', { list.destroy(); }); + QUnit.test('archive all records matching the domain', async function (assert) { + assert.expect(6); + + // add active field on foo model and make all records active + this.data.foo.fields.active = {string: 'Active', type: 'boolean', default: true}; + 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 === 'action_archive') { + assert.deepEqual(args.args[0], [1, 2, 3, 5]); + return Promise.resolve(); + } + 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, "Archive"); + + assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); + await testUtils.dom.click($('.modal-footer .btn-primary')); + + list.destroy(); + }); + + QUnit.test('archive all records matching the domain (limit reached)', async function (assert) { + assert.expect(8); + + // add active field on foo model and make all records active + this.data.foo.fields.active = {string: 'Active', type: 'boolean', default: true}; + 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 === 'action_archive') { + assert.deepEqual(args.args[0], [1, 2, 3, 5]); + return Promise.resolve(); + } + 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, "Archive"); + + 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('pager (ungrouped and grouped mode), default limit', async function (assert) { assert.expect(4); |
