[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
This commit is contained in:
Lucas Perais (lpe)
2018-11-20 13:53:52 +00:00
parent 48dafd5b20
commit e713ed2a69
4 changed files with 125 additions and 3 deletions
@@ -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; }
},
@@ -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;
@@ -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);
},
@@ -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);