diff options
| author | Lucas Perais (lpe) <lpe@odoo.com> | 2018-11-20 09:00:43 +0000 |
|---|---|---|
| committer | Lucas Perais (lpe) <lpe@odoo.com> | 2018-11-20 13:53:52 +0000 |
| commit | e713ed2a69af9fe97fbe2d54843adc8f1ce689aa (patch) | |
| tree | 5b2f624fcfd2d57930f3d253fb356153d8dc7321 | |
| parent | 48dafd5b2011cee966920f664a904de2e2715ae8 (diff) | |
[FIX] web: implement filter orderedBy
related to: #28446
On a pure list view, click on a column to sort the records by that field.
Save the filter as favorite
Reload, now apply the filter
Before this commit, there were two issues:
1. The order of the list was never propagated to search view, which couldn't save
the filter with its attribute "sort"
2. There was no mechanism to load the attribute sort from a loading Filter
After this commit, those two issues are corrected
Unfortunately, complex search view flows are not testable in v11.0
OPW 1906968
closes odoo/odoo#28766
| -rw-r--r-- | addons/web/static/src/js/chrome/search_menus.js | 23 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_model.js | 3 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/list/list_controller.js | 9 | ||||
| -rw-r--r-- | addons/web/static/tests/views/list_tests.js | 93 |
4 files changed, 125 insertions, 3 deletions
diff --git a/addons/web/static/src/js/chrome/search_menus.js b/addons/web/static/src/js/chrome/search_menus.js index d41052c882e..99e8bd6e799 100644 --- a/addons/web/static/src/js/chrome/search_menus.js +++ b/addons/web/static/src/js/chrome/search_menus.js @@ -100,9 +100,17 @@ return Widget.extend({ var controllerContext; this.trigger_up('get_controller_context', { callback: function (ctx) { - controllerContext = ctx; + if (ctx && ctx.orderedBy) { + var sort = _.map(ctx.orderedBy, function (obj) { + var order = obj.asc ? 'ASC' : 'DESC'; + return obj.name + ' ' + order; + }); + self.searchview.dataset.set_sort(sort); + } + controllerContext = _.omit(ctx, ['orderedBy']); }, }); + var results = pyeval.eval_domains_and_contexts({ domains: search.domains, contexts: [user_context].concat(search.contexts.concat(controllerContext || [])), @@ -182,7 +190,18 @@ return Widget.extend({ category: _t("Custom Filter"), icon: 'fa-star', field: { - get_context: function () { return filter.context; }, + get_context: function () { + var sortParsed = JSON.parse(filter.sort || "[]"); + var orderedBy = []; + _.each(sortParsed, function (sort) { + orderedBy.push({ + name: sort[0] === '-' ? sort.slice(1) : sort, + asc: sort[0] === '-' ? false : true, + }); + }); + + return _.defaults({}, filter.context, {orderedBy : orderedBy}); + }, get_groupby: function () { return [filter.context]; }, get_domain: function () { return filter.domain; } }, 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 b9832996de5..0372f7cd5e7 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -3332,7 +3332,7 @@ var BasicModel = AbstractModel.extend({ model: params.modelName, offset: params.offset || (type === 'record' ? _.indexOf(res_ids, res_id) : 0), openGroupByDefault: params.openGroupByDefault, - orderedBy: params.orderedBy || [], + orderedBy: params.orderedBy || (params.context && params.context.orderedBy) || [], orderedResIDs: params.orderedResIDs, parentID: params.parentID, rawContext: params.rawContext, @@ -4016,6 +4016,7 @@ var BasicModel = AbstractModel.extend({ if (options.context !== undefined) { element.context = options.context; + element.orderedBy = options.context.orderedBy || element.orderedBy; } if (options.domain !== undefined) { element.domain = options.domain; 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 02ee76bf919..df23fffa54c 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -78,6 +78,14 @@ var ListController = BasicController.extend({ return $.Deferred().resolve(); } }, + /* + * @override + */ + getContext: function () { + var context = this._super.apply(this, arguments); + context.orderedBy = this.model.get(this.handle, {raw: true}).orderedBy || []; + return context; + }, /** * Returns the list of currently selected res_ids (with the check boxes on * the left) @@ -179,6 +187,7 @@ var ListController = BasicController.extend({ } else { this.selectedRecords = []; } + params.selectedRecords = this.selectedRecords; return this._super.apply(this, arguments); }, diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index bd4c8f8e339..fb99828d2fe 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -307,6 +307,99 @@ QUnit.module('Views', { list.destroy(); }); + QUnit.test('ordered list, sort attribute in context', function (assert) { + assert.expect(1); + // Equivalent to saving a custom filter + + this.data.foo.fields.foo.sortable = true; + this.data.foo.fields.date.sortable = true; + + var list = createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '<tree>' + + '<field name="foo"/>' + + '<field name="date"/>' + + '</tree>', + }); + + // Descending order on Foo + list.$('th.o_column_sortable:contains("Foo")').click(); + list.$('th.o_column_sortable:contains("Foo")').click(); + + // Ascending order on Date + list.$('th.o_column_sortable:contains("Date")').click(); + + var listContext = list.getContext(); + assert.deepEqual(listContext, + { + orderedBy: [{ + name: 'date', + asc: true, + }, { + name: 'foo', + asc: false, + }] + }, 'the list should have the right orderedBy in context'); + list.destroy(); + }); + + QUnit.test('Loading a filter with a sort attribute', function (assert) { + assert.expect(2); + + this.data.foo.fields.foo.sortable = true; + this.data.foo.fields.date.sortable = true; + + var searchReads = 0; + var list = createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '<tree>' + + '<field name="foo"/>' + + '<field name="date"/>' + + '</tree>', + context: { + orderedBy: [{ + name: 'date', + asc: true, + }, { + name: 'foo', + asc: false, + }] + }, + mockRPC: function (route, args) { + if (route === '/web/dataset/search_read') { + if (searchReads === 0) { + assert.strictEqual(args.sort, 'date ASC, foo DESC', + 'The sort attribute of the filter should be used by the initial search_read'); + } else if (searchReads === 1) { + assert.strictEqual(args.sort, 'date DESC, foo ASC', + 'The sort attribute of the filter should be used by the next search_read'); + } + searchReads += 1; + } + return this._super.apply(this,arguments); + }, + }); + + // Simulate loading a filter + list.update({ + context: { + orderedBy: [{ + name: 'date', + asc: false, + }, { + name: 'foo', + asc: true, + }] + } + }); + + list.destroy() + }); + QUnit.test('many2one field rendering', function (assert) { assert.expect(1); |
