[FIX] web: graph,pivot: favorite groupbys

Problem:

Have a pivot view in some state. Toggle a favorite with a context in
which a key "pivot_row_groupby" is defined. The pivot view should be
grouped (on rows) by that pivot_row_groupby but it is not always the
case. The basic problem is that the key "pivot_row_groupby" is never
considered after the first load (see method load in pivot_model.js).

Solution:

We make the search model used by the pivot view send as groupby for the
favorite its pivot_row_groupby instead of its groupBy (which can be
different). We do something similar for the graph view that presents a
similar problem.

closes odoo/odoo#95688

Opw: 2837428
X-original-commit: ea9f66f99caaa6136912c467e5b80fe605586845
Signed-off-by: Mathieu Duckerts-Antoine <dam@odoo.com>
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Mathieu Duckerts-Antoine
2022-07-11 07:58:55 +02:00
parent 1741b1552e
commit f76205322e
6 changed files with 249 additions and 0 deletions
@@ -0,0 +1,21 @@
/** @odoo-module **/
import { SearchModel } from "@web/search/search_model";
export class GraphSearchModel extends SearchModel {
_getIrFilterDescription() {
this.preparingIrFilterDescription = true;
const result = super._getIrFilterDescription(...arguments);
this.preparingIrFilterDescription = false;
return result;
}
_getSearchItemGroupBys(activeItem) {
const { searchItemId } = activeItem;
const { context, type } = this.searchItems[searchItemId];
if (!this.preparingIrFilterDescription && type === "favorite" && context.graph_groupbys) {
return context.graph_groupbys;
}
return super._getSearchItemGroupBys(...arguments);
}
}
@@ -6,6 +6,7 @@ import { GraphArchParser } from "./graph_arch_parser";
import { GraphModel } from "./graph_model";
import { GraphController } from "./graph_controller";
import { GraphRenderer } from "./graph_renderer";
import { GraphSearchModel } from "./graph_search_model";
const viewRegistry = registry.category("views");
@@ -18,6 +19,7 @@ export const graphView = {
Renderer: GraphRenderer,
Model: GraphModel,
ArchParser: GraphArchParser,
SearchModel: GraphSearchModel,
searchMenuTypes: ["filter", "groupBy", "comparison", "favorite"],
buttonTemplate: "web.GraphView.Buttons",
@@ -0,0 +1,25 @@
/** @odoo-module **/
import { SearchModel } from "@web/search/search_model";
export class PivotSearchModel extends SearchModel {
_getIrFilterDescription() {
this.preparingIrFilterDescription = true;
const result = super._getIrFilterDescription(...arguments);
this.preparingIrFilterDescription = false;
return result;
}
_getSearchItemGroupBys(activeItem) {
const { searchItemId } = activeItem;
const { context, type } = this.searchItems[searchItemId];
if (
!this.preparingIrFilterDescription &&
type === "favorite" &&
context.pivot_row_groupby
) {
return context.pivot_row_groupby;
}
return super._getSearchItemGroupBys(...arguments);
}
}
@@ -6,6 +6,7 @@ import { PivotArchParser } from "@web/views/pivot/pivot_arch_parser";
import { PivotController } from "./pivot_controller";
import { PivotModel } from "@web/views/pivot/pivot_model";
import { PivotRenderer } from "@web/views/pivot/pivot_renderer";
import { PivotSearchModel } from "./pivot_search_model";
const viewRegistry = registry.category("views");
@@ -18,6 +19,7 @@ export const pivotView = {
Renderer: PivotRenderer,
Model: PivotModel,
ArchParser: PivotArchParser,
SearchModel: PivotSearchModel,
searchMenuTypes: ["filter", "groupBy", "comparison", "favorite"],
buttonTemplate: "web.PivotView.Buttons",
@@ -3676,4 +3676,43 @@ QUnit.module("Views", (hooks) => {
});
checkLabels(assert, graph, ["January 2016", "March 2016", "May 2016", "April 2016"]);
});
QUnit.test("graph_groupbys should be also used after first load", async function (assert) {
const graph = await makeView({
serverData,
type: "graph",
resModel: "foo",
groupBy: ["date:quarter"],
arch: `<graph/>`,
irFilters: [
{
user_id: [2, "Mitchell Admin"],
name: "Favorite",
id: 1,
context: `{
"group_by": [],
"graph_measure": "revenue",
"graph_mode": "bar",
"graph_groupbys": ["color_id"],
}`,
sort: "[]",
domain: "",
is_default: false,
model_id: "foo",
action_id: false,
},
],
});
checkModeIs(assert, graph, "bar");
checkLabels(assert, graph, ["Q1 2016", "Q2 2016", "Undefined"]);
checkLegend(assert, graph, "Count");
await toggleFavoriteMenu(target);
await toggleMenuItem(target, "Favorite");
checkModeIs(assert, graph, "bar");
checkLabels(assert, graph, ["Undefined", "red"]);
checkLegend(assert, graph, "Revenue");
});
});
@@ -5383,4 +5383,164 @@ QUnit.module("Views", (hooks) => {
assert.strictEqual(getCurrentValues(target), values.join());
}
);
QUnit.test("pivot_row_groupby should be also used after first load", async function (assert) {
const ids = [1, 2];
const expectedContexts = [
{
group_by: ["bar"],
pivot_column_groupby: [],
pivot_measures: ["__count"],
pivot_row_groupby: ["product_id"],
},
{
group_by: ["bar", "customer"],
pivot_column_groupby: [],
pivot_measures: ["__count"],
pivot_row_groupby: ["customer"],
},
];
await makeView({
type: "pivot",
resModel: "partner",
serverData,
arch: `<pivot/>`,
searchViewArch: `
<search>
<filter name='product_id' string="Product" context="{'group_by':'product_id'}"/>
<filter name='customer' string="Customer" context="{'group_by':'customer'}"/>
</search>
`,
groupBy: ["bar"],
mockRPC(route, args) {
if (args.method === "create_or_replace") {
assert.deepEqual(args.args[0].context, expectedContexts.shift());
return ids.shift();
}
},
});
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "No", "Yes"],
"The row headers should be as expected"
);
await click(target.querySelector("tbody th")); // click on row header "Total"
await click(target.querySelector("tbody th")); // click on row header "Total"
await click(target.querySelector("tbody .o_group_by_menu .o_menu_item")); // select "Product"
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "xphone", "xpad"],
"The row headers should be as expected"
);
await toggleFavoriteMenu(target);
await toggleSaveFavorite(target);
await editFavoriteName(target, "Favorite");
await saveFavorite(target);
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "xphone", "xpad"],
"The row headers should be as expected"
);
await removeFacet(target);
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "No", "Yes"],
"The row headers should be as expected"
);
await toggleFavoriteMenu(target);
await toggleMenuItem(target, "Favorite");
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "xphone", "xpad"],
"The row headers should be as expected"
);
await toggleGroupByMenu(target);
await toggleMenuItem(target, "Customer");
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "xphone", "First", "xpad", "First", "Second"],
"The row headers should be as expected"
);
await click(target.querySelector("tbody th")); // click on row header "Total"
await click(target.querySelector("tbody th")); // click on row header "Total"
await click(target.querySelectorAll("tbody .o_group_by_menu .o_menu_item")[1]); // select "Customer"
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "First", "Second"],
"The row headers should be as expected"
);
await toggleFavoriteMenu(target);
await toggleSaveFavorite(target);
await editFavoriteName(target, "Favorite 2");
await saveFavorite(target);
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "First", "Second"],
"The row headers should be as expected"
);
});
QUnit.test(
"pivot_row_groupby should be also used after first load (2)",
async function (assert) {
await makeView({
serverData,
type: "pivot",
resModel: "partner",
groupBy: ["product_id"],
arch: `<pivot/>`,
irFilters: [
{
user_id: [2, "Mitchell Admin"],
name: "Favorite",
id: 1,
context: `
{
"group_by": [],
"pivot_row_groupby": ["customer"],
"pivot_col_groupby": [],
"pivot_measures": ["foo"],
}
`,
sort: "[]",
domain: "",
is_default: false,
model_id: "foo",
action_id: false,
},
],
});
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "xphone", "xpad"],
"The row headers should be as expected"
);
await toggleFavoriteMenu(target);
await toggleMenuItem(target, "Favorite");
assert.deepEqual(
[...target.querySelectorAll("th")].slice(3).map((el) => el.innerText),
["Total", "First", "Second"],
"The row headers should be as expected"
);
}
);
});