Skip to content

Commit

Permalink
[FIX] web: Regroup and order date groupby options
Browse files Browse the repository at this point in the history
A previous commit makes the graph view render only the finer interval
option for each date/datetime field.
The fact is that in the control panel, different options can be selected
in any order along with other groupbys. This can lead to situations like

'Foo > Date: Day > Bar > Date: Month'

and becomes unreadable.
For that reason we choose to regroup and order options. For the previous
situation, this leads to the following global groupby

'Foo > Date: Month > Date: Day > Bar'.

Our choice also make more sense in a list view for instance.

Task ID: 2198846

closes #46269

X-original-commit: 59afc86
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
  • Loading branch information
Polymorphe57 committed Feb 25, 2020
1 parent c7851ad commit 743d551
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 6 deletions.
Expand Up @@ -16,6 +16,7 @@ let TIME_RANGE_OPTIONS = controlPanelViewParameters.TIME_RANGE_OPTIONS;
let COMPARISON_TIME_RANGE_OPTIONS = controlPanelViewParameters.COMPARISON_TIME_RANGE_OPTIONS;
const OPTION_GENERATORS = controlPanelViewParameters.OPTION_GENERATORS;
const YEAR_OPTIONS = controlPanelViewParameters.YEAR_OPTIONS;
const { rank } = controlPanelViewParameters;

// Returns a predicate used to test if two arrays (of maximal length 2) have the same basic content.
function isEqualTo (array1) {
Expand Down Expand Up @@ -497,8 +498,9 @@ var ControlPanelModel = mvc.Model.extend({
const combinationId = [filterId, optionId];
const initiaLength = group.activeFilterIds.length;
const index = group.activeFilterIds.findIndex(isEqualTo(combinationId));

if (index === -1) {
group.activeFilterIds.push(combinationId);
group.activeFilterIds = this._insert(group.activeFilterIds, combinationId);
filter.currentOptionIds.add(optionId);
if (initiaLength === 0) {
this.query.push(group.id);
Expand Down Expand Up @@ -1018,6 +1020,49 @@ var ControlPanelModel = mvc.Model.extend({
}
return context;
},
/**
* Insert a combination of type [filterId, optionId] in activeFilterIds for
* a corresponding filter of type 'groupBy' with options.
* The array activeFilterIds is by construction of the form
*
* A1 'concat' A2 'concat' A3
*
* where filterId does not occur in the arrays A1 and A3 (possibly empty) and
* A2 = [[filterId, optionId_1], ..., [filterId, optionId_n]] (possibly empty).
*
* The idea of the function below is to insert [filterId, optionId] at the end
* of activeFilterIds if A2 is empty and inside A2 otherwise while keeping A2 ordered
* for the natural order on option ids: 'year' < 'quarter' < ... < 'day'.
*
* @private
* @param {Array[]} activeFilterIds
* @param {Array} combinationId
* @returns {Array[]}
*/
_insert(activeFilterIds, combinationId) {
const filterId = combinationId[0];
let firstIndex = -1;
let lastIndex = -1;
activeFilterIds.forEach((cId, i) => {
if (cId[0] === filterId) {
firstIndex = firstIndex === -1 ? i : firstIndex;
lastIndex = i;
}
});
if (firstIndex === -1) { // case A2 empty
activeFilterIds.push(combinationId);
} else { // case A2 non empty
const a1 = activeFilterIds.slice(0, firstIndex);
const a2 = activeFilterIds.slice(firstIndex, lastIndex + 1);
const a3 = activeFilterIds.slice(lastIndex + 1);

a2.push(combinationId);
a2.sort((c1, c2) => rank(c1[1]) - rank(c2[1]));

activeFilterIds = [].concat(a1, a2, a3);
}
return activeFilterIds;
},
/**
* Load custom filters in db, then create a group of type 'favorite' and a
* filter of type 'favorite' for each loaded custom filters.
Expand Down
Expand Up @@ -51,6 +51,9 @@ const INTERVAL_OPTIONS = [
{ description: _lt('Week'), optionId: 'week', groupId: 1 },
{ description: _lt('Day'), optionId: 'day', groupId: 1 },
];
function rank(oId) {
return INTERVAL_OPTIONS.findIndex(o => o.optionId === oId);
}

// for TimeRangeMenu
const DEFAULT_TIMERANGE = DEFAULT_PERIOD;
Expand All @@ -71,6 +74,7 @@ return {
PERIOD_OPTIONS: PERIOD_OPTIONS,
TIME_RANGE_OPTIONS: TIME_RANGE_OPTIONS,
YEAR_OPTIONS: YEAR_OPTIONS,
rank: rank,
};

});
6 changes: 1 addition & 5 deletions addons/web/static/src/js/views/graph/graph_model.js
Expand Up @@ -2,14 +2,10 @@ odoo.define('web.GraphModel', function (require) {
"use strict";

var core = require('web.core');
const { DEFAULT_INTERVAL, INTERVAL_OPTIONS } = require('web.controlPanelViewParameters');
const { DEFAULT_INTERVAL, rank } = require('web.controlPanelViewParameters');

var _t = core._t;

function rank(oId) {
return INTERVAL_OPTIONS.findIndex(o => o.optionId === oId);
}

/**
* The graph model is responsible for fetching and processing data from the
* server. It basically just do a(some) read_group(s) and format/normalize data.
Expand Down
65 changes: 65 additions & 0 deletions addons/web/static/tests/views/search_view_tests.js
Expand Up @@ -2,6 +2,7 @@ odoo.define('web.search_view_tests', function (require) {
"use strict";

var FormView = require('web.FormView');
var GraphView = require('web.GraphView');
var testUtils = require('web.test_utils');

var createActionManager = testUtils.createActionManager;
Expand Down Expand Up @@ -590,9 +591,73 @@ QUnit.module('Search View', {
// data should be grouped by the field 'Birthday' using the interval 'year'
assert.strictEqual($('div.o_facet_values span').text().trim(),'Birthday: Year');
assert.strictEqual($('.o_content tr.o_group_header').length, 4);

actionManager.destroy();
});

QUnit.test('group by a date field using interval works', async function (assert) {
assert.expect(8);

var pivot = await createView({
View: GraphView,
model: "partner",
groupBy:['bar'],
data: this.data,
arch: '<graph/>',
archs: {
'partner,false,search': `<search>
<filter string="Bar" name="superName" context="{'group_by': 'bar'}"/>
<filter string="Date" name="coolName" context="{'group_by': 'date_field'}"/>
<filter string="Foo" name="superName" context="{'group_by': 'foo'}"/>
</search>`
},
});

function getFacetTexts() {
return [...pivot.el.querySelectorAll('div.o_facet_values span')].map(
e => e.innerText
).join(' ');
};

// open menu 'Group By'
await testUtils.dom.click(pivot.el.querySelector('.o_search_options .fa-bars'));
// select 'Bar'
await testUtils.dom.click(pivot.el.querySelectorAll('.o_group_by_menu .o_menu_item')[0]);
assert.strictEqual(getFacetTexts(), 'Bar');

// Open the groupby 'Date'
await testUtils.dom.click(pivot.el.querySelectorAll('.o_group_by_menu .o_menu_item')[1]);
// select option 'week'
await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="week"]'));
assert.strictEqual(getFacetTexts(), 'Bar > Date: Week');

// select option 'day'
await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="day"]'));
assert.strictEqual(getFacetTexts(), 'Bar > Date: Week > Date: Day');

// select option 'year'
await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="year"]'));
assert.strictEqual(getFacetTexts(), 'Bar > Date: Year > Date: Week > Date: Day');

// select 'Foo'
await testUtils.dom.click(pivot.el.querySelectorAll('.o_group_by_menu .o_menu_item')[2]);
assert.strictEqual(getFacetTexts(), 'Bar > Date: Year > Date: Week > Date: Day > Foo');

// select option 'quarter'
await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="quarter"]'));
assert.strictEqual(getFacetTexts(), 'Bar > Date: Year > Date: Quarter > Date: Week > Date: Day > Foo');

// unselect 'Bar'
await testUtils.dom.click(pivot.el.querySelectorAll('.o_group_by_menu .o_menu_item')[0]);
assert.strictEqual(getFacetTexts(), 'Date: Year > Date: Quarter > Date: Week > Date: Day > Foo');

// unselect option 'week'
await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="week"]'));
assert.strictEqual(getFacetTexts(), 'Date: Year > Date: Quarter > Date: Day > Foo');

pivot.destroy();
});

QUnit.test('a separator in groupbys does not cause problems', async function (assert) {
assert.expect(6);

Expand Down

0 comments on commit 743d551

Please sign in to comment.