From f841fd1bc7f5e287de5edd1e6887f90dd18662d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 16 Jun 2019 15:44:14 +0200 Subject: [PATCH] Allow to search on related field in search box The server adds to the definition of the fields, the definition of relation fields up to specific deep level. The clients use this relation fields definition to extend the domain parser with those fields using a dot notation. But those "dotted fields" are not shown in the search filter to not bloat the popup as it is dedicated to learning. In addition, Dict fields are also filled with relation fields coming from the keys defined in the schema model. As the size can very large, it is possible to deactivate this feature from the configuration. issue8293 review259391005 --- CHANGELOG | 1 + src/common.js | 21 ++++++++++++++---- src/screen.js | 15 +++++-------- tests/sao.js | 61 +++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 83 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1dc1dee51c..87a25501fb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Support relation fields in domain parser * Add view modified * Add Dict widget for tree view diff --git a/src/common.js b/src/common.js index 4a30b6c11e..944265f0a3 100644 --- a/src/common.js +++ b/src/common.js @@ -994,15 +994,28 @@ init: function(fields, context) { this.fields = {}; this.strings = {}; - this.update_fields(fields); this.context = context; + this.update_fields(fields); }, - update_fields: function(fields) { + update_fields: function(fields, prefix, string_prefix) { + prefix = prefix || ''; + string_prefix = string_prefix || ''; for (var name in fields) { var field = fields[name]; - if (field.searchable || (field.searchable === undefined)) { - this.fields[name] = field; + if ((field.searchable || (field.searchable === undefined)) && + (name !== 'rec_name')) { + field = jQuery.extend({}, field); + var fullname = prefix ? prefix + '.' + name : name; + var string = string_prefix ? + string_prefix + '.' + field.string : field.string; + field.string = string; + field.name = fullname; + this.fields[fullname] = field; this.strings[field.string.toLowerCase()] = field; + var rfields = field.relation_fields; + if (rfields) { + this.update_fields(rfields, fullname, string); + } } } }, diff --git a/src/screen.js b/src/screen.js index 3ae9589130..6aab4cf3d1 100644 --- a/src/screen.js +++ b/src/screen.js @@ -441,7 +441,8 @@ var field; for (var f in domain_parser.fields) { field = domain_parser.fields[f]; - if (field.searchable || field.searchable === undefined) { + if ((field.searchable || field.searchable === undefined) && + !field.name.contains('.')) { fields.push(field); } } @@ -1633,14 +1634,10 @@ // Add common fields [ ['id', Sao.i18n.gettext('ID'), 'integer'], - ['create_uid', Sao.i18n.gettext('Creation User'), - 'many2one'], - ['create_date', Sao.i18n.gettext('Creation Date'), - 'datetime'], - ['write_uid', Sao.i18n.gettext('Modification User'), - 'many2one'], - ['write_date', Sao.i18n.gettext('Modification Date'), - 'datetime'] + ['create_uid', Sao.i18n.gettext('Created by'), 'many2one'], + ['create_date', Sao.i18n.gettext('Created at'), 'datetime'], + ['write_uid', Sao.i18n.gettext('Modified by'), 'many2one'], + ['write_date', Sao.i18n.gettext('Modified at'), 'datetime'] ] .forEach(function(e) { var name = e[0]; var string = e[1]; diff --git a/tests/sao.js b/tests/sao.js index a7279da1b7..1944ccc26c 100644 --- a/tests/sao.js +++ b/tests/sao.js @@ -1077,7 +1077,16 @@ }, 'surname': { 'string': '(Sur)Name' - } + }, + 'relation': { + 'string': "Relation", + 'relation': 'relation', + 'relation_fields': { + 'name': { + 'string': "Name", + }, + }, + }, }); var udlex = function(input) { var lex = new Sao.common.udlex(input); @@ -1156,7 +1165,10 @@ ]], ['Name: "" <', [ c(['Name', '', '<']) - ]] + ]], + ['Relation.Name: Test', [ + c(['Relation.Name', null, 'Test']), + ]], ].forEach(function(test) { var value = test[0]; var result = test[1]; @@ -1457,6 +1469,18 @@ 'name': 'many2one', 'type': 'many2one', }, + 'relation': { + 'string': "Relation", + 'relation': 'relation', + 'name': 'relation', + 'relation_fields': { + 'name': { + 'string': "Name", + 'name': 'name', + 'type': 'char', + }, + }, + }, }); var c = function(value) { value.clause = true; @@ -1501,6 +1525,8 @@ [[c(['Many2One', null, ['John', 'Jane']])], [['many2one.rec_name', 'in', ['John', 'Jane']]]], [[[c(['John'])]], [[['rec_name', 'ilike', '%John%']]]], + [[c(['Relation.Name', null, "Test"])], + [['relation.name', 'ilike', "%Test%"]]], ].forEach(function(test) { var value = test[0]; var result = test[1]; @@ -1646,6 +1672,12 @@ 'relation': { 'string': 'Relation', 'type': 'many2one', + 'relation_fields': { + 'name': { + 'string': "Name", + 'type': 'char', + }, + }, }, 'relations': { 'string': 'Relations', @@ -1667,6 +1699,7 @@ QUnit.ok(parser.stringable([['relations', '=', 'Foo']])); QUnit.ok(parser.stringable([['relations', 'in', ['Foo']]])); QUnit.ok(!parser.stringable([['relations', 'in', [42]]])); + QUnit.ok(parser.stringable([['relation.name', '=', "Foo"]])); }); QUnit.test('DomainParser.string', function() { @@ -1703,6 +1736,12 @@ 'string': "Many2One", 'name': 'many2one', 'type': 'many2one', + 'relation_fields': { + 'name': { + 'string': "Name", + 'type': 'char', + }, + }, }, }); @@ -1751,6 +1790,7 @@ [[['reference', 'in', ['foo', 'bar']]], 'Reference: foo;bar'], [[['many2one', 'ilike', '%John%']], 'Many2One: John'], [[['many2one.rec_name', 'in', ['John', 'Jane']]], 'Many2One: John;Jane'], + [[['many2one.name', 'ilike', '%Foo%']], 'Many2One.Name: Foo'], ].forEach(function(test) { var value = test[0]; var result = test[1]; @@ -2478,6 +2518,23 @@ QUnit.ok(compare(parser.completion(value), expected), 'completion(' + value + ')'); }); + + parser = new Sao.common.DomainParser({ + 'relation': { + 'name': 'relation', + 'string': "Relation", + 'type': 'many2one', + 'relation_fields': { + 'name': { + 'name': 'name', + 'string': "Name", + 'type': 'char', + }, + }, + }, + }); + QUnit.ok(compare(parser.completion('Relatio'), + ["Relation: ", "Relation.Name: "])); }); /*