[IMP] web: SearchPanel: default filter values in context
Before this rev., it was possible to specify default values for categories (fields with attribute select="one") in the context (e.g. searchpanel_default_fieldname: 5). It is now possible to specify default values for filters (select="multi") as well (e.g. searchpanel_default_fieldname: [1,2]). closes odoo/odoo#31107
This commit is contained in:
@@ -143,16 +143,16 @@ var KanbanView = BasicView.extend({
|
||||
*/
|
||||
_createSearchPanel: function (parent) {
|
||||
var self = this;
|
||||
var defaultCategoryValues = {};
|
||||
var defaultValues = {};
|
||||
Object.keys(this.loadParams.context).forEach(function (key) {
|
||||
var match = /^searchpanel_default_(.*)$/.exec(key);
|
||||
if (match) {
|
||||
defaultCategoryValues[match[1]] = self.loadParams.context[key];
|
||||
defaultValues[match[1]] = self.loadParams.context[key];
|
||||
}
|
||||
});
|
||||
var controlPanelDomain = this.loadParams.domain;
|
||||
var searchPanel = new this.config.SearchPanel(parent, {
|
||||
defaultCategoryValues: defaultCategoryValues,
|
||||
defaultValues: defaultValues,
|
||||
fields: this.fields,
|
||||
model: this.loadParams.modelName,
|
||||
searchDomain: controlPanelDomain,
|
||||
|
||||
@@ -25,8 +25,8 @@ var SearchPanel = Widget.extend({
|
||||
/**
|
||||
* @override
|
||||
* @param {Object} params
|
||||
* @param {Object} [params.defaultCategoryValues={}] the category value to
|
||||
* activate by default, for each category
|
||||
* @param {Object} [params.defaultValues={}] the value(s) to activate by
|
||||
* default, for each filter and category
|
||||
* @param {Object} params.fields
|
||||
* @param {string} params.model
|
||||
* @param {Object} params.sections
|
||||
@@ -42,7 +42,7 @@ var SearchPanel = Widget.extend({
|
||||
return section.type === 'filter';
|
||||
});
|
||||
|
||||
this.defaultCategoryValues = params.defaultCategoryValues || {};
|
||||
this.defaultValues = params.defaultValues || {};
|
||||
this.fields = params.fields;
|
||||
this.model = params.model;
|
||||
this.searchDomain = params.searchDomain;
|
||||
@@ -53,7 +53,7 @@ var SearchPanel = Widget.extend({
|
||||
willStart: function () {
|
||||
var self = this;
|
||||
var loadProm = this._fetchCategories().then(function () {
|
||||
return self._fetchFilters();
|
||||
return self._fetchFilters().then(self._applyDefaultFilterValues.bind(self));
|
||||
});
|
||||
return $.when(loadProm, this._super.apply(this, arguments));
|
||||
},
|
||||
@@ -100,6 +100,27 @@ var SearchPanel = Widget.extend({
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set active values for each filter (coming from context). This needs to be
|
||||
* done only once, at widget startup.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_applyDefaultFilterValues: function () {
|
||||
var self = this;
|
||||
Object.keys(this.filters).forEach(function (filterId) {
|
||||
var filter = self.filters[filterId];
|
||||
var defaultValues = self.defaultValues[filter.fieldName] || [];
|
||||
defaultValues.forEach(function (value) {
|
||||
if (filter.values[value]) {
|
||||
filter.values[value].checked = true;
|
||||
}
|
||||
});
|
||||
Object.keys(filter.groups || []).forEach(function (groupId) {
|
||||
self._updateFilterGroupState(filter.groups[groupId]);
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {string} categoryId
|
||||
@@ -131,7 +152,7 @@ var SearchPanel = Widget.extend({
|
||||
// set active value
|
||||
var validValues = _.pluck(category.values, 'id').concat([false]);
|
||||
// set active value from context
|
||||
var value = this.defaultCategoryValues[category.fieldName];
|
||||
var value = this.defaultValues[category.fieldName];
|
||||
// if not set in context, or set to an unknown value, set active value
|
||||
// from localStorage
|
||||
if (!_.contains(validValues, value)) {
|
||||
@@ -359,6 +380,22 @@ var SearchPanel = Widget.extend({
|
||||
}
|
||||
return [];
|
||||
},
|
||||
/**
|
||||
* Compute the current searchPanel domain based on categories and filters,
|
||||
* and notify environment of the domain change.
|
||||
*
|
||||
* Note that this assumes that the environment will update the searchPanel.
|
||||
* This is done as such to ensure the coordination between the reloading of
|
||||
* the searchPanel and the reloading of the data.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_notifyDomainUpdated: function () {
|
||||
this.needReload = true;
|
||||
this.trigger_up('search_panel_domain_updated', {
|
||||
domain: this.getDomain(),
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -418,20 +455,23 @@ var SearchPanel = Widget.extend({
|
||||
return $filter;
|
||||
},
|
||||
/**
|
||||
* Compute the current searchPanel domain based on categories and filters,
|
||||
* and notify environment of the domain change.
|
||||
*
|
||||
* Note that this assumes that the environment will update the searchPanel.
|
||||
* This is done as such to ensure the coordination between the reloading of
|
||||
* the searchPanel and the reloading of the data.
|
||||
* Updates the state property of a given filter's group according to the
|
||||
* checked property of its values.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} group
|
||||
*/
|
||||
_notifyDomainUpdated: function () {
|
||||
this.needReload = true;
|
||||
this.trigger_up('search_panel_domain_updated', {
|
||||
domain: this.getDomain(),
|
||||
_updateFilterGroupState: function (group) {
|
||||
var valuePartition = _.partition(Object.keys(group.values), function (valueId) {
|
||||
return group.values[valueId].checked;
|
||||
});
|
||||
if (valuePartition[0].length && valuePartition[1].length) {
|
||||
group.state = 'indeterminate';
|
||||
} else if (valuePartition[0].length) {
|
||||
group.state = 'checked';
|
||||
} else {
|
||||
group.state = 'unchecked';
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -481,16 +521,7 @@ var SearchPanel = Widget.extend({
|
||||
value.checked = !value.checked;
|
||||
var group = filter.groups && filter.groups[value.group_id];
|
||||
if (group) {
|
||||
var valuePartition = _.partition(Object.keys(group.values), function (valueId) {
|
||||
return group.values[valueId].checked;
|
||||
});
|
||||
if (valuePartition[0].length && valuePartition[1].length) {
|
||||
group.state = 'indeterminate';
|
||||
} else if (valuePartition[0].length) {
|
||||
group.state = 'checked';
|
||||
} else {
|
||||
group.state = 'unchecked';
|
||||
}
|
||||
this._updateFilterGroupState(group);
|
||||
}
|
||||
this._notifyDomainUpdated();
|
||||
},
|
||||
|
||||
@@ -1443,6 +1443,121 @@ QUnit.module('Views', {
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('specify active filter values in context', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var expectedDomain = [
|
||||
['company_id', 'in', [5]],
|
||||
['state', 'in', ['abc', 'ghi']],
|
||||
];
|
||||
var kanban = createView({
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: '<kanban>' +
|
||||
'<templates><t t-name="kanban-box">' +
|
||||
'<div>' +
|
||||
'<field name="foo"/>' +
|
||||
'</div>' +
|
||||
'</t></templates>' +
|
||||
'<searchpanel>' +
|
||||
'<field select="multi" name="company_id"/>' +
|
||||
'<field select="multi" name="state"/>' +
|
||||
'</searchpanel>' +
|
||||
'</kanban>',
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/search_read') {
|
||||
assert.deepEqual(args.domain, expectedDomain);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
context: {
|
||||
searchpanel_default_company_id: [5],
|
||||
searchpanel_default_state: ['abc', 'ghi'],
|
||||
},
|
||||
});
|
||||
|
||||
assert.containsN(kanban, '.o_search_panel_filter_value input:checked', 3);
|
||||
|
||||
// manually untick a default value
|
||||
expectedDomain = [['state', 'in', ['abc', 'ghi']]];
|
||||
testUtils.dom.click(kanban.$('.o_search_panel_filter:first .o_search_panel_filter_value:nth(1) input'));
|
||||
|
||||
assert.containsN(kanban, '.o_search_panel_filter_value input:checked', 2);
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('retrieved filter value from context does not exist', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var kanban = createView({
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: '<kanban>' +
|
||||
'<templates><t t-name="kanban-box">' +
|
||||
'<div>' +
|
||||
'<field name="foo"/>' +
|
||||
'</div>' +
|
||||
'</t></templates>' +
|
||||
'<searchpanel>' +
|
||||
'<field select="multi" name="company_id"/>' +
|
||||
'</searchpanel>' +
|
||||
'</kanban>',
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/search_read') {
|
||||
assert.deepEqual(args.domain, [["company_id", "in", [3]]]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
context: {
|
||||
searchpanel_default_company_id: [1, 3],
|
||||
},
|
||||
});
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('filter with groupby and default values in context', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
this.data.company.records.push({id: 11, name: 'camptocamp', category_id: 7});
|
||||
|
||||
var kanban = createView({
|
||||
View: KanbanView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
arch: '<kanban>' +
|
||||
'<templates><t t-name="kanban-box">' +
|
||||
'<div>' +
|
||||
'<field name="foo"/>' +
|
||||
'</div>' +
|
||||
'</t></templates>' +
|
||||
'<searchpanel>' +
|
||||
'<field select="multi" name="company_id" groupby="category_id"/>' +
|
||||
'</searchpanel>' +
|
||||
'</kanban>',
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/search_read') {
|
||||
assert.deepEqual(args.domain, [['company_id', 'in', [5]]]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
context: {
|
||||
searchpanel_default_company_id: [5],
|
||||
},
|
||||
});
|
||||
|
||||
var secondGroupCheckbox = kanban.$('.o_search_panel_filter_group:nth(1) > div > input').get(0);
|
||||
assert.strictEqual(secondGroupCheckbox.indeterminate, true);
|
||||
|
||||
kanban.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user