diff --git a/addons/web/static/src/js/control_panel/control_panel_model_extension.js b/addons/web/static/src/js/control_panel/control_panel_model_extension.js
index 2b12ca90802..c04205ecccb 100644
--- a/addons/web/static/src/js/control_panel/control_panel_model_extension.js
+++ b/addons/web/static/src/js/control_panel/control_panel_model_extension.js
@@ -163,7 +163,7 @@ odoo.define("web/static/src/js/control_panel/control_panel_model_extension.js",
this.searchMenuTypes = this.config.searchMenuTypes || [];
this.favoriteFilters = this.config.favoriteFilters || [];
this.fields = this.config.fields || {};
- this.searchDefaults = [];
+ this.searchDefaults = {};
for (const key in this.actionContext) {
const match = /^search_default_(.*)$/.exec(key);
if (match) {
@@ -747,6 +747,21 @@ odoo.define("web/static/src/js/control_panel/control_panel_model_extension.js",
// and others are passive (require input(s) to become determined)
// What is the right place to process the attrs?
};
+ if (preFilter.attrs && JSON.parse(preFilter.attrs.modifiers || '{}').invisible) {
+ filter.invisible = true;
+ let preFilterFieldName = null;
+ if (preFilter.tag === 'filter' && preFilter.attrs.date) {
+ preFilterFieldName = preFilter.attrs.date;
+ } else if (preFilter.tag === 'groupBy') {
+ preFilterFieldName = preFilter.attrs.fieldName;
+ }
+ if (preFilterFieldName && !this.fields[preFilterFieldName]) {
+ // In some case when a field is limited to specific groups
+ // on the model, we need to ensure to discard related filter
+ // as it may still be present in the view (in 'invisible' state)
+ return;
+ }
+ }
if (filter.type === 'filter' || filter.type === 'groupBy') {
filter.groupNumber = groupNumber;
}
@@ -838,14 +853,11 @@ odoo.define("web/static/src/js/control_panel/control_panel_model_extension.js",
}
} catch (e) { }
}
- if (this.searchDefaults.hasOwnProperty(child.attrs.name)) {
+ if (child.attrs.name in this.searchDefaults) {
child.attrs.isDefault = true;
let value = this.searchDefaults[child.attrs.name];
if (child.tag === 'field') {
- if (value instanceof Array) {
- value = value[0];
- }
- child.attrs.defaultAutocompleteValue = { value, operator: '=' };
+ child.attrs.defaultValue = Array.isArray(value) ? value[0] : value;
} else if (child.tag === 'groupBy') {
child.attrs.defaultRank = typeof value === 'number' ? value : 100;
}
@@ -865,9 +877,6 @@ odoo.define("web/static/src/js/control_panel/control_panel_model_extension.js",
filter.isDefault = attrs.isDefault;
}
filter.description = attrs.string || attrs.help || attrs.name || attrs.domain || 'Ω';
- if (JSON.parse(attrs.modifiers || '{}').invisible) {
- filter.invisible = true;
- }
switch (filter.type) {
case 'filter':
if (attrs.context) {
@@ -913,8 +922,23 @@ odoo.define("web/static/src/js/control_panel/control_panel_model_extension.js",
filter.context = attrs.context;
}
if (filter.isDefault) {
+ let operator = filter.operator;
+ if (!operator) {
+ const type = attrs.widget || filter.fieldType;
+ // Note: many2one as a default filter will have a
+ // numeric value instead of a string => we want "="
+ // instead of "ilike".
+ if (["char", "html", "many2many", "one2many", "text"].includes(type)) {
+ operator = "ilike";
+ } else {
+ operator = "=";
+ }
+ }
filter.defaultRank = -10;
- filter.defaultAutocompleteValue = attrs.defaultAutocompleteValue;
+ filter.defaultAutocompleteValue = {
+ operator,
+ value: attrs.defaultValue,
+ };
}
break;
}
diff --git a/addons/web/static/tests/control_panel/control_panel_tests.js b/addons/web/static/tests/control_panel/control_panel_tests.js
index 24744291cc9..c9e89387505 100644
--- a/addons/web/static/tests/control_panel/control_panel_tests.js
+++ b/addons/web/static/tests/control_panel/control_panel_tests.js
@@ -18,6 +18,75 @@ odoo.define('web.control_panel_tests', function (require) {
}
}, function () {
+ QUnit.test('default field operator', async function (assert) {
+ assert.expect(2);
+
+ const fields = {
+ foo_op: { string: "Foo Op", type: "char", store: true, sortable: true, searchable: true },
+ foo: { string: "Foo", type: "char", store: true, sortable: true, searchable: true },
+ bar_op: { string: "Bar Op", type: "many2one", relation: 'partner', searchable: true },
+ bar: { string: "Bar", type: "many2one", relation: 'partner', searchable: true },
+ selec: { string: "Selec", type: "selection", selection: [['red', "Red"], ['black', "Black"]] },
+ };
+ const arch = `
+
+
+
+
+
+
+ `;
+ const searchMenuTypes = [];
+ const params = {
+ cpModelConfig: {
+ arch,
+ fields,
+ context: {
+ show_filterC: true,
+ search_default_bar: 10,
+ search_default_bar_op: 10,
+ search_default_foo: "foo",
+ search_default_foo_op: "foo_op",
+ search_default_selec: 'red',
+ },
+ searchMenuTypes,
+ },
+ cpProps: { fields, searchMenuTypes },
+ env: {
+ session: {
+ async rpc() {
+ return [[10, "Deco Addict"]];
+ },
+ },
+ },
+ };
+ const controlPanel = await createControlPanel(params);
+
+ assert.deepEqual(
+ cpHelpers.getFacetTexts(controlPanel).map(t => t.replace(/\s/g, "")),
+ [
+ "BarDecoAddict",
+ "BarOpDecoAddict",
+ "Foofoo",
+ "FooOpfoo_op",
+ "SelecRed"
+ ]
+ );
+ assert.deepEqual(
+ controlPanel.getQuery().domain,
+ [
+ "&", "&", "&", "&",
+ ["bar", "=", 10],
+ ["bar_op", "child_of", 10],
+ ["foo", "ilike", "foo"],
+ ["foo_op", "=", "foo_op"],
+ ["selec", "=", "red"],
+ ]
+ );
+
+ controlPanel.destroy();
+ });
+
QUnit.module('Keyboard navigation');
QUnit.test('remove a facet with backspace', async function (assert) {
@@ -146,21 +215,11 @@ odoo.define('web.control_panel_tests', function (require) {
// view to emulate the behavior of fields_view_get()
// [see ir.ui.view `_apply_group()`]
- delete this.fields['bar'];
- delete this.fields['date_field'];
+ delete this.fields.bar;
+ delete this.fields.date_field;
- const arch = `
-
-
-
-
- `;
const searchMenuTypes = [];
const params = {
- cpStoreConfig: {
- viewInfo: { arch, fields: this.fields },
- searchMenuTypes
- },
cpProps: { fields: this.fields, searchMenuTypes },
};
const controlPanel = await createControlPanel(params);
@@ -176,7 +235,7 @@ odoo.define('web.control_panel_tests', function (require) {
QUnit.test('groupby menu is not rendered if searchMenuTypes does not have groupBy', async function (assert) {
assert.expect(2);
- const arch = ``;
+ const arch = ``;
const searchMenuTypes = ['filter'];
const params = {
cpModelConfig: {
@@ -193,7 +252,5 @@ odoo.define('web.control_panel_tests', function (require) {
controlPanel.destroy();
});
-
-
});
});
diff --git a/addons/web/static/tests/control_panel/favorite_menu_tests.js b/addons/web/static/tests/control_panel/favorite_menu_tests.js
index d01afdfb063..bf2ec76d564 100644
--- a/addons/web/static/tests/control_panel/favorite_menu_tests.js
+++ b/addons/web/static/tests/control_panel/favorite_menu_tests.js
@@ -371,7 +371,7 @@ odoo.define('web.favorite_menu_tests', function (require) {
search: function (searchQuery) {
const { domain, groupBy, timeRanges } = searchQuery;
if (firstSearch) {
- assert.deepEqual(domain, [['foo', '=', 'a']]);
+ assert.deepEqual(domain, [['foo', 'ilike', 'a']]);
assert.deepEqual(groupBy, ['date_field:month']);
assert.deepEqual(timeRanges, {
comparisonId: "previous_period",
@@ -399,7 +399,7 @@ odoo.define('web.favorite_menu_tests', function (require) {
const { domain, groupBy, timeRanges } = controlPanel.getQuery();
assert.deepEqual(domain, [
"&",
- ["foo", "=", "a"],
+ ["foo", "ilike", "a"],
"&",
["date_field", ">=", "2019-01-01"],
["date_field", "<=", "2019-12-31"]