[IMP] web: selection in list views
This commit allows the user to apply actions to all records matching the current domain in list views. It also ensures that the user is aware of the set of records actually selected. The number of selected records is now displayed in the control panel, and the user can, with an additional click, select all records matching the current domain instead of the ones of the current page. Task 2185145
This commit is contained in:
@@ -26,7 +26,7 @@ class Http(models.AbstractModel):
|
||||
version_info = odoo.service.common.exp_version()
|
||||
|
||||
user_context = request.session.get_context() if request.session.uid else {}
|
||||
|
||||
IrConfigSudo = self.env['ir.config_parameter'].sudo()
|
||||
session_info = {
|
||||
"uid": request.session.uid,
|
||||
"is_system": user._is_system() if request.session.uid else False,
|
||||
@@ -40,7 +40,8 @@ class Http(models.AbstractModel):
|
||||
"partner_display_name": user.partner_id.display_name,
|
||||
"company_id": user.company_id.id if request.session.uid else None, # YTI TODO: Remove this from the user context
|
||||
"partner_id": user.partner_id.id if request.session.uid and user.partner_id else None,
|
||||
"web.base.url": self.env['ir.config_parameter'].sudo().get_param('web.base.url', default=''),
|
||||
"web.base.url": IrConfigSudo.get_param('web.base.url', default=''),
|
||||
"active_ids_limit": int(IrConfigSudo.get_param('web.active_ids_limit', default='20000')),
|
||||
}
|
||||
if self.env.user.has_group('base.group_user'):
|
||||
# the following is only useful in the context of a webclient bootstrapping
|
||||
|
||||
@@ -3,7 +3,6 @@ odoo.define('web.ActionMenus', function (require) {
|
||||
|
||||
const Context = require('web.Context');
|
||||
const DropdownMenu = require('web.DropdownMenu');
|
||||
const pyUtils = require('web.py_utils');
|
||||
const Registry = require('web.Registry');
|
||||
|
||||
const { Component } = owl;
|
||||
@@ -95,15 +94,25 @@ odoo.define('web.ActionMenus', function (require) {
|
||||
* @param {OwlEvent} ev
|
||||
*/
|
||||
async _executeAction(action) {
|
||||
const activeIdsContext = {
|
||||
active_id: this.props.activeIds[0],
|
||||
active_ids: this.props.activeIds,
|
||||
active_model: this.env.action.res_model,
|
||||
select_all: this.props.selectAll || false,
|
||||
};
|
||||
if (this.props.domain) {
|
||||
activeIdsContext.active_domain = this.props.domain;
|
||||
let activeIds = this.props.activeIds;
|
||||
if (this.props.isDomainSelected) {
|
||||
activeIds = await this.rpc({
|
||||
model: this.env.action.res_model,
|
||||
method: 'search',
|
||||
args: [this.props.domain],
|
||||
kwargs: {
|
||||
limit: this.env.session.active_ids_limit,
|
||||
},
|
||||
});
|
||||
}
|
||||
const activeIdsContext = {
|
||||
active_id: activeIds[0],
|
||||
active_ids: activeIds,
|
||||
active_model: this.env.action.res_model,
|
||||
// keep active_domain in context for backward compatibility
|
||||
// reasons, and to allow actions to bypass the active_ids_limit
|
||||
active_domain: this.props.domain,
|
||||
};
|
||||
|
||||
const context = new Context(this.props.context, activeIdsContext).eval();
|
||||
const result = await this.rpc({
|
||||
@@ -149,9 +158,10 @@ odoo.define('web.ActionMenus', function (require) {
|
||||
|
||||
ActionMenus.components = { DropdownMenu };
|
||||
ActionMenus.props = {
|
||||
activeIds: { type: Array, element: [Number|String] }, // virtual IDs are strings.
|
||||
activeIds: { type: Array, element: [Number | String] }, // virtual IDs are strings.
|
||||
context: Object,
|
||||
domain: { type: Array, optional: 1 },
|
||||
isDomainSelected: { type: Boolean, optional: 1 },
|
||||
items: {
|
||||
type: Object,
|
||||
shape: {
|
||||
@@ -160,7 +170,6 @@ odoo.define('web.ActionMenus', function (require) {
|
||||
other: { type: Array, optional: 1 },
|
||||
},
|
||||
},
|
||||
selectAll: { type: Boolean, optional: 1 },
|
||||
};
|
||||
ActionMenus.template = 'web.ActionMenus';
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ var ListController = BasicController.extend({
|
||||
buttons_template: 'ListView.buttons',
|
||||
events: _.extend({}, BasicController.prototype.events, {
|
||||
'click .o_list_export_xlsx': '_onDirectExportData',
|
||||
'click .o_list_select_domain': '_onSelectDomain',
|
||||
}),
|
||||
custom_events: _.extend({}, BasicController.prototype.custom_events, {
|
||||
activate_next_widget: '_onActivateNextWidget',
|
||||
@@ -54,7 +55,8 @@ var ListController = BasicController.extend({
|
||||
this.selectedRecords = params.selectedRecords || [];
|
||||
this.multipleRecordsSavingPromise = null;
|
||||
this.fieldChangedPrevented = false;
|
||||
this.selectAll = false;
|
||||
this.isPageSelected = false; // true iff all records of the page are selected
|
||||
this.isDomainSelected = false; // true iff the user selected all records matching the domain
|
||||
Object.defineProperty(this, 'mode', {
|
||||
get: () => this.renderer.isEditable() ? 'edit' : 'readonly',
|
||||
set: () => {},
|
||||
@@ -128,20 +130,22 @@ var ListController = BasicController.extend({
|
||||
*/
|
||||
renderButtons: function ($node) {
|
||||
if (this.noLeaf || !this.hasButtons) {
|
||||
return;
|
||||
this.hasButtons = false;
|
||||
this.$buttons = $('<div>');
|
||||
} else {
|
||||
this.$buttons = $(qweb.render(this.buttons_template, {widget: this}));
|
||||
this.$buttons.on('click', '.o_list_button_add', this._onCreateRecord.bind(this));
|
||||
this._assignCreateKeyboardBehavior(this.$buttons.find('.o_list_button_add'));
|
||||
this.$buttons.find('.o_list_button_add').tooltip({
|
||||
delay: {show: 200, hide: 0},
|
||||
title: function () {
|
||||
return qweb.render('CreateButton.tooltip');
|
||||
},
|
||||
trigger: 'manual',
|
||||
});
|
||||
this.$buttons.on('mousedown', '.o_list_button_discard', this._onDiscardMousedown.bind(this));
|
||||
this.$buttons.on('click', '.o_list_button_discard', this._onDiscard.bind(this));
|
||||
}
|
||||
this.$buttons = $(qweb.render(this.buttons_template, {widget: this}));
|
||||
this.$buttons.on('click', '.o_list_button_add', this._onCreateRecord.bind(this));
|
||||
this._assignCreateKeyboardBehavior(this.$buttons.find('.o_list_button_add'));
|
||||
this.$buttons.find('.o_list_button_add').tooltip({
|
||||
delay: {show: 200, hide: 0},
|
||||
title: function () {
|
||||
return qweb.render('CreateButton.tooltip');
|
||||
},
|
||||
trigger: 'manual',
|
||||
});
|
||||
this.$buttons.on('mousedown', '.o_list_button_discard', this._onDiscardMousedown.bind(this));
|
||||
this.$buttons.on('click', '.o_list_button_discard', this._onDiscard.bind(this));
|
||||
if ($node) {
|
||||
this.$buttons.appendTo($node);
|
||||
}
|
||||
@@ -153,15 +157,20 @@ var ListController = BasicController.extend({
|
||||
*/
|
||||
update: function (params, options) {
|
||||
var self = this;
|
||||
let res_ids;
|
||||
if (options && options.keepSelection) {
|
||||
// filter out removed records from selection
|
||||
var res_ids = this.model.get(this.handle).res_ids;
|
||||
res_ids = this.model.get(this.handle).res_ids;
|
||||
this.selectedRecords = _.filter(this.selectedRecords, function (id) {
|
||||
return _.contains(res_ids, self.model.get(id).res_id);
|
||||
});
|
||||
} else {
|
||||
this.selectedRecords = [];
|
||||
}
|
||||
if (this.selectedRecords.length === 0 || this.selectedRecords.length < res_ids.length) {
|
||||
this.isDomainSelected = false;
|
||||
this.isPageSelected = false;
|
||||
}
|
||||
|
||||
params.selectedRecords = this.selectedRecords;
|
||||
return this._super.apply(this, arguments);
|
||||
@@ -174,16 +183,16 @@ var ListController = BasicController.extend({
|
||||
* @param {string} mode either 'readonly' or 'edit'
|
||||
*/
|
||||
updateButtons: function (mode) {
|
||||
if (!this.$buttons) {
|
||||
return;
|
||||
}
|
||||
this.$buttons.toggleClass('o-editing', mode === 'edit');
|
||||
const state = this.model.get(this.handle, {raw: true});
|
||||
if (state.count) {
|
||||
this.$('.o_list_export_xlsx').show();
|
||||
} else {
|
||||
this.$('.o_list_export_xlsx').hide();
|
||||
if (this.hasButtons) {
|
||||
this.$buttons.toggleClass('o-editing', mode === 'edit');
|
||||
const state = this.model.get(this.handle, {raw: true});
|
||||
if (state.count) {
|
||||
this.$('.o_list_export_xlsx').show();
|
||||
} else {
|
||||
this.$('.o_list_export_xlsx').hide();
|
||||
}
|
||||
}
|
||||
this._updateSelectionBox();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -354,9 +363,9 @@ var ListController = BasicController.extend({
|
||||
}
|
||||
return Object.assign(props, {
|
||||
items: Object.assign({}, this.toolbarActions, { other: otherActionItems }),
|
||||
context: this.model.get(this.handle, { raw: true }).getContext(),
|
||||
context: state.getContext(),
|
||||
domain: state.getDomain(),
|
||||
selectAll: this.selectAll,
|
||||
isDomainSelected: this.isDomainSelected,
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -484,7 +493,7 @@ var ListController = BasicController.extend({
|
||||
* @private
|
||||
*/
|
||||
_toggleCreateButton: function () {
|
||||
if (this.$buttons) {
|
||||
if (this.hasButtons) {
|
||||
var state = this.model.get(this.handle);
|
||||
var createHidden = this.renderer.isEditable() && state.groupedBy.length && state.data.length;
|
||||
this.$buttons.find('.o_list_button_add').toggleClass('o_hidden', !!createHidden);
|
||||
@@ -499,6 +508,31 @@ var ListController = BasicController.extend({
|
||||
this._toggleCreateButton();
|
||||
this.updateButtons('readonly');
|
||||
},
|
||||
/**
|
||||
* When records are selected, a box is displayed in the control panel (next
|
||||
* to the buttons). It indicates the number of selected records, and allows
|
||||
* the user to select the whole domain instead of the current page (when the
|
||||
* page is selected). This function renders and displays this box when at
|
||||
* least one record is selected.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_updateSelectionBox() {
|
||||
if (this.$selectionBox) {
|
||||
this.$selectionBox.remove();
|
||||
this.$selectionBox = null;
|
||||
}
|
||||
if (this.selectedRecords.length) {
|
||||
const state = this.model.get(this.handle, {raw: true});
|
||||
this.$selectionBox = $(qweb.render('ListView.selection', {
|
||||
isDomainSelected: this.isDomainSelected,
|
||||
isPageSelected: this.isPageSelected,
|
||||
nbSelected: this.selectedRecords.length,
|
||||
nbTotal: state.count,
|
||||
}));
|
||||
this.$selectionBox.appendTo(this.$buttons);
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
@@ -690,6 +724,15 @@ var ListController = BasicController.extend({
|
||||
.then(ev.data.onSuccess)
|
||||
.guardedCatch(ev.data.onFailure);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onSelectDomain: function (ev) {
|
||||
ev.preventDefault();
|
||||
this.isDomainSelected = true;
|
||||
this._updateSelectionBox();
|
||||
this._updateControlPanel();
|
||||
},
|
||||
/**
|
||||
* When the current selection changes (by clicking on the checkboxes on the
|
||||
* left), we need to display (or hide) the 'sidebar'.
|
||||
@@ -699,7 +742,9 @@ var ListController = BasicController.extend({
|
||||
*/
|
||||
_onSelectionChanged: function (ev) {
|
||||
this.selectedRecords = ev.data.selection;
|
||||
this.selectAll = ev.data.allChecked;
|
||||
this.isPageSelected = ev.data.allChecked;
|
||||
this.isDomainSelected = false;
|
||||
this._updateSelectionBox();
|
||||
this._updateControlPanel();
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -348,3 +348,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Selection box (next to the buttons, in ControlPanel)
|
||||
$selected-box-color: #e7f2f6;
|
||||
.o_list_selection_box {
|
||||
display: inline-block;
|
||||
padding: $btn-padding-y $btn-padding-x;
|
||||
vertical-align: middle; // align with the buttons
|
||||
border: 1px solid $selected-box-color;
|
||||
background-color: $selected-box-color;
|
||||
.o_list_select_domain {
|
||||
font-weight: bold;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,6 +859,18 @@
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ListView.selection">
|
||||
<div class="o_list_selection_box">
|
||||
<t t-if="isDomainSelected">All <t t-esc="nbTotal"/> selected</t>
|
||||
<t t-else="">
|
||||
<t t-esc="nbSelected"/> selected
|
||||
<a t-if="isPageSelected and nbTotal > nbSelected" href="#" class="o_list_select_domain">
|
||||
<i class="fa fa-arrow-right"/> Select all <t t-esc="nbTotal"/>
|
||||
</a>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ListView.confirmModal">
|
||||
<main role="alert">
|
||||
<p>
|
||||
|
||||
@@ -105,7 +105,6 @@ odoo.define('web.action_menus_tests', function (require) {
|
||||
active_id: 23,
|
||||
active_ids: [23],
|
||||
active_model: 'hobbit',
|
||||
select_all: false, // default props
|
||||
};
|
||||
assert.deepEqual(args.context, expectedContext);
|
||||
assert.step('load-action');
|
||||
@@ -178,7 +177,6 @@ odoo.define('web.action_menus_tests', function (require) {
|
||||
active_id: 23,
|
||||
active_ids: [23],
|
||||
active_model: 'hobbit',
|
||||
select_all: false, // default props
|
||||
};
|
||||
assert.deepEqual(args.context, expectedContext);
|
||||
assert.step('load-action');
|
||||
|
||||
@@ -1093,6 +1093,20 @@ var MockServer = Class.extend({
|
||||
}
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* Simulate a 'search' operation
|
||||
*
|
||||
* @private
|
||||
* @param {string} model
|
||||
* @param {Array} args
|
||||
* @param {Object} kwargs
|
||||
* @param {integer} [kwargs.limit]
|
||||
* @returns {integer[]}
|
||||
*/
|
||||
_mockSearch: function (model, args, kwargs) {
|
||||
const limit = kwargs.limit || Number.MAX_VALUE;
|
||||
return this._getRecords(model, args[0]).map(r => r.id).slice(0, limit);
|
||||
},
|
||||
/**
|
||||
* Simulate a 'search_count' operation
|
||||
*
|
||||
@@ -1340,6 +1354,9 @@ var MockServer = Class.extend({
|
||||
case 'read_progress_bar':
|
||||
return Promise.resolve(this._mockReadProgressBar(args.model, args.kwargs));
|
||||
|
||||
case 'search':
|
||||
return Promise.resolve(this._mockSearch(args.model, args.args, args.kwargs));
|
||||
|
||||
case 'search_count':
|
||||
return Promise.resolve(this._mockSearchCount(args.model, args.args));
|
||||
|
||||
|
||||
@@ -1251,8 +1251,76 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('selection box is properly displayed (single page)', async function (assert) {
|
||||
assert.expect(11);
|
||||
|
||||
var list = await createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree><field name="foo"/><field name="bar"/></tree>',
|
||||
});
|
||||
|
||||
assert.containsN(list, '.o_data_row', 4);
|
||||
assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
|
||||
// select a record
|
||||
await testUtils.dom.click(list.$('.o_data_row:first .o_list_record_selector input'));
|
||||
assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
assert.containsNone(list.$('.o_list_selection_box'), '.o_list_select_domain');
|
||||
assert.strictEqual(list.$('.o_list_selection_box').text().trim(), '1 selected');
|
||||
|
||||
// select all records of first page
|
||||
await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
|
||||
assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
assert.containsNone(list.$('.o_list_selection_box'), '.o_list_select_domain');
|
||||
assert.strictEqual(list.$('.o_list_selection_box').text().trim(), '4 selected');
|
||||
|
||||
// unselect a record
|
||||
await testUtils.dom.click(list.$('.o_data_row:nth(1) .o_list_record_selector input'));
|
||||
assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
assert.containsNone(list.$('.o_list_selection_box'), '.o_list_select_domain');
|
||||
assert.strictEqual(list.$('.o_list_selection_box').text().trim(), '3 selected');
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('selection box is properly displayed (multi pages)', async function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
var list = await createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree limit="3"><field name="foo"/><field name="bar"/></tree>',
|
||||
});
|
||||
|
||||
assert.containsN(list, '.o_data_row', 3);
|
||||
assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
|
||||
// select a record
|
||||
await testUtils.dom.click(list.$('.o_data_row:first .o_list_record_selector input'));
|
||||
assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
assert.containsNone(list.$('.o_list_selection_box'), '.o_list_select_domain');
|
||||
assert.strictEqual(list.$('.o_list_selection_box').text().trim(), '1 selected');
|
||||
|
||||
// select all records of first page
|
||||
await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
|
||||
assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
assert.containsOnce(list.$('.o_list_selection_box'), '.o_list_select_domain');
|
||||
assert.strictEqual(list.$('.o_list_selection_box').text().replace(/\s+/g, ' ').trim(),
|
||||
'3 selected Select all 4');
|
||||
|
||||
// select all domain
|
||||
await testUtils.dom.click(list.$('.o_list_selection_box .o_list_select_domain'));
|
||||
assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
assert.strictEqual(list.$('.o_list_selection_box').text().trim(), 'All 4 selected');
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('selection is reset on reload', async function (assert) {
|
||||
assert.expect(5);
|
||||
assert.expect(8);
|
||||
|
||||
var list = await createView({
|
||||
View: ListView,
|
||||
@@ -1264,6 +1332,7 @@ QUnit.module('Views', {
|
||||
'</tree>',
|
||||
});
|
||||
|
||||
assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '32',
|
||||
"total should be 32 (no record selected)");
|
||||
|
||||
@@ -1271,6 +1340,7 @@ QUnit.module('Views', {
|
||||
var $firstRowSelector = list.$('tbody .o_list_record_selector input').first();
|
||||
testUtils.dom.click($firstRowSelector);
|
||||
assert.ok($firstRowSelector.is(':checked'), "first row should be selected");
|
||||
assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '10',
|
||||
"total should be 10 (first record selected)");
|
||||
|
||||
@@ -1279,6 +1349,7 @@ QUnit.module('Views', {
|
||||
$firstRowSelector = list.$('tbody .o_list_record_selector input').first();
|
||||
assert.notOk($firstRowSelector.is(':checked'),
|
||||
"first row should no longer be selected");
|
||||
assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '32',
|
||||
"total should be 32 (no more record selected)");
|
||||
|
||||
@@ -1286,7 +1357,7 @@ QUnit.module('Views', {
|
||||
});
|
||||
|
||||
QUnit.test('selection is kept on render without reload', async function (assert) {
|
||||
assert.expect(6);
|
||||
assert.expect(10);
|
||||
|
||||
var list = await createView({
|
||||
View: ListView,
|
||||
@@ -1301,17 +1372,20 @@ QUnit.module('Views', {
|
||||
});
|
||||
|
||||
assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus');
|
||||
assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
|
||||
// open blip grouping and check all lines
|
||||
await testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")'));
|
||||
await testUtils.dom.click(list.$('.o_data_row:first input'));
|
||||
assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus');
|
||||
assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
|
||||
// open yop grouping and verify blip are still checked
|
||||
await testUtils.dom.click(list.$('.o_group_header:contains("yop (1)")'));
|
||||
assert.containsOnce(list, '.o_data_row input:checked',
|
||||
"opening a grouping does not uncheck others");
|
||||
assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus');
|
||||
assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
|
||||
// close and open blip grouping and verify blip are unchecked
|
||||
await testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")'));
|
||||
@@ -1319,6 +1393,7 @@ QUnit.module('Views', {
|
||||
assert.containsNone(list, '.o_data_row input:checked',
|
||||
"opening and closing a grouping uncheck its elements");
|
||||
assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus');
|
||||
assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
@@ -2865,7 +2940,7 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('list without import button', async function (assert) {
|
||||
QUnit.test('list with group_by_no_leaf flag in context', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var list = await createView({
|
||||
@@ -2878,7 +2953,7 @@ QUnit.module('Views', {
|
||||
}
|
||||
});
|
||||
|
||||
assert.ok(!list.$buttons, "should not have any buttons");
|
||||
assert.containsNone(list, '.o_list_buttons', "should not have any buttons");
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
@@ -4260,7 +4335,7 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('execute ActionMenus actions with correct params', async function (assert) {
|
||||
QUnit.test('execute ActionMenus actions with correct params (single page)', async function (assert) {
|
||||
assert.expect(12);
|
||||
|
||||
const list = await createView({
|
||||
@@ -4320,9 +4395,78 @@ QUnit.module('Views', {
|
||||
await cpHelpers.toggleMenuItem(list, "Custom Action");
|
||||
|
||||
assert.verifySteps([
|
||||
'{"action_id":44,"context":{"active_id":1,"active_ids":[1,2,3,4],"active_model":"foo","select_all":true,"active_domain":[]}}',
|
||||
'{"action_id":44,"context":{"active_id":2,"active_ids":[2,3,4],"active_model":"foo","select_all":false,"active_domain":[]}}',
|
||||
'{"action_id":44,"context":{"active_id":1,"active_ids":[1,2],"active_model":"foo","select_all":false,"active_domain":[["bar","=",true]]}}',
|
||||
'{"action_id":44,"context":{"active_id":1,"active_ids":[1,2,3,4],"active_model":"foo","active_domain":[]}}',
|
||||
'{"action_id":44,"context":{"active_id":2,"active_ids":[2,3,4],"active_model":"foo","active_domain":[]}}',
|
||||
'{"action_id":44,"context":{"active_id":1,"active_ids":[1,2],"active_model":"foo","active_domain":[["bar","=",true]]}}',
|
||||
]);
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('execute ActionMenus actions with correct params (multi pages)', async function (assert) {
|
||||
assert.expect(13);
|
||||
|
||||
const list = await createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree limit="2"><field name="foo"/></tree>',
|
||||
toolbar: {
|
||||
action: [{
|
||||
id: 44,
|
||||
name: 'Custom Action',
|
||||
type: 'ir.actions.server',
|
||||
}],
|
||||
print: [],
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/action/load') {
|
||||
assert.step(JSON.stringify(args));
|
||||
return Promise.resolve({});
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
viewOptions: {
|
||||
hasActionMenus: true,
|
||||
},
|
||||
});
|
||||
|
||||
assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus');
|
||||
assert.containsN(list, '.o_data_row', 2);
|
||||
|
||||
// select all records
|
||||
await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
|
||||
assert.containsN(list, '.o_list_record_selector input:checked', 3);
|
||||
assert.containsOnce(list, '.o_list_selection_box .o_list_select_domain');
|
||||
assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus');
|
||||
|
||||
await cpHelpers.toggleActionMenu(list);
|
||||
await cpHelpers.toggleMenuItem(list, "Custom Action");
|
||||
|
||||
// select all domain
|
||||
await testUtils.dom.click(list.$('.o_list_selection_box .o_list_select_domain'));
|
||||
assert.containsN(list, '.o_list_record_selector input:checked', 3);
|
||||
|
||||
await cpHelpers.toggleActionMenu(list);
|
||||
await cpHelpers.toggleMenuItem(list, "Custom Action");
|
||||
|
||||
// add a domain
|
||||
await list.reload({ domain: [['bar', '=', true]] });
|
||||
assert.containsNone(list, '.o_list_selection_box .o_list_select_domain');
|
||||
|
||||
// select all domain
|
||||
await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
|
||||
await testUtils.dom.click(list.$('.o_list_selection_box .o_list_select_domain'));
|
||||
assert.containsN(list, '.o_list_record_selector input:checked', 3);
|
||||
assert.containsNone(list, '.o_list_selection_box .o_list_select_domain');
|
||||
|
||||
await cpHelpers.toggleActionMenu(list);
|
||||
await cpHelpers.toggleMenuItem(list, "Custom Action");
|
||||
|
||||
assert.verifySteps([
|
||||
'{"action_id":44,"context":{"active_id":1,"active_ids":[1,2],"active_model":"foo","active_domain":[]}}',
|
||||
'{"action_id":44,"context":{"active_id":1,"active_ids":[1,2,3,4],"active_model":"foo","active_domain":[]}}',
|
||||
'{"action_id":44,"context":{"active_id":1,"active_ids":[1,2,3],"active_model":"foo","active_domain":[["bar","=",true]]}}',
|
||||
]);
|
||||
|
||||
list.destroy();
|
||||
|
||||
Reference in New Issue
Block a user