[FIX] board: replace include on ActionManager with override on view

When opening the dashboard in form view, some of the view options should
always have a certain value (in particular, the target should be inline,
and the form view should not have action menus or a control panel).

Previously, this was done through an override on the action manager when
executing a window action. In wowl, the action manager has been replaced
with an action service and its methods cannot be overriden.

This commit solves the same problem with a different approach, by
overwriting these options before trying to extract the view params from
the action.
This commit is contained in:
Samuel Degueldre
2021-06-18 21:31:27 +02:00
committed by Aaron Bohy
parent 3a4f1c31de
commit a3c69db9ef
4 changed files with 199 additions and 194 deletions
-1
View File
@@ -22,7 +22,6 @@ Allows users to create custom dashboard.
'assets': {
'web.assets_backend': [
'board/static/src/scss/dashboard.scss',
'board/static/src/js/action_manager_board_action.js',
'board/static/src/js/board_view.js',
'board/static/src/js/add_to_board_menu.js',
],
@@ -1,33 +0,0 @@
odoo.define('board.ActionManager', function (require) {
"use strict";
/**
* The purpose of this file is to patch the ActionManager to properly generate
* the flags for the 'ir.actions.act_window' of model 'board.board'.
*/
var ActionManager = require('web.ActionManager');
ActionManager.include({
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @override
* @private
*/
_executeWindowAction: function (action) {
if (action.res_model === 'board.board' && action.view_mode === 'form') {
action.target = 'inline';
_.extend(action.flags, {
hasActionMenus: false,
hasSearchView: false,
headless: true,
});
}
return this._super.apply(this, arguments);
},
});
});
+13
View File
@@ -446,6 +446,19 @@ var BoardView = FormView.extend({
this._super.apply(this, arguments);
this.controllerParams.customViewID = viewInfo.custom_view_id;
},
/**
* @override
*/
_extractParamsFromAction(action) {
action.target = "inline";
action.flags = action.flags || {};
Object.assign(action.flags, {
hasActionMenus: false,
hasSearchView: false,
headless: true,
});
return this._super.apply(this, arguments);
},
});
return BoardView;
+186 -160
View File
@@ -9,11 +9,16 @@ var ListRenderer = require('web.ListRenderer');
var pyUtils = require('web.py_utils');
const cpHelpers = testUtils.controlPanel;
var createActionManager = testUtils.createActionManager;
const {
createWebClient,
doAction,
getActionManagerTestConfig,
} = require("@web/../tests/webclient/actions/helpers");
var createView = testUtils.createView;
const patchDate = testUtils.mock.patchDate;
let testConfig;
QUnit.module('Dashboard', {
beforeEach: function () {
this.data = {
@@ -48,6 +53,9 @@ QUnit.module('Dashboard', {
}],
},
};
testConfig = getActionManagerTestConfig();
// map legacy test data
Object.assign(testConfig.serverData, { models: this.data });
},
});
@@ -82,7 +90,7 @@ QUnit.test('dashboard basic rendering', async function (assert) {
"with a dashboard, the renderer should have the proper css class");
assert.containsOnce(form, '.o_dashboard .o_view_nocontent',
"should have a no content helper");
assert.strictEqual(form.$('.o_control_panel .breadcrumb-item').text(), "My Dashboard",
assert.strictEqual(form.getTitle(), "My Dashboard",
"should have the correct title");
form.destroy();
});
@@ -696,143 +704,156 @@ QUnit.test('dashboard intercepts custom events triggered by sub controllers', as
board.destroy();
});
QUnit.test('save actions to dashboard', async function (assert) {
QUnit.test("save actions to dashboard", async function (assert) {
assert.expect(6);
testUtils.patch(ListController, {
getOwnedQueryParams: function () {
var result = this._super.apply(this, arguments);
result.context = {
'fire': 'on the bayou',
fire: "on the bayou",
};
return result;
}
});
this.data['partner'].fields.foo.sortable = true;
var actionManager = await createActionManager({
data: this.data,
archs: {
'partner,false,list': '<list><field name="foo"/></list>',
'partner,false,search': '<search></search>',
},
mockRPC: function (route, args) {
if (route === '/board/add_to_dashboard') {
assert.deepEqual(args.context_to_save.group_by, ['foo'],
'The group_by should have been saved');
assert.deepEqual(args.context_to_save.orderedBy,
[{
name: 'foo',
});
testConfig.serverData.models["partner"].fields.foo.sortable = true;
testConfig.serverData.views = {
"partner,false,list": '<list><field name="foo"/></list>',
"partner,false,search": "<search></search>",
};
const mockRPC = (route, args) => {
if (route === "/board/add_to_dashboard") {
assert.deepEqual(
args.context_to_save.group_by,
["foo"],
"The group_by should have been saved"
);
assert.deepEqual(
args.context_to_save.orderedBy,
[
{
name: "foo",
asc: true,
}],
'The orderedBy should have been saved');
assert.strictEqual(args.context_to_save.fire, 'on the bayou',
'The context of a controller should be passed and flattened');
assert.strictEqual(args.action_id, 1,
"should save the correct action");
assert.strictEqual(args.view_mode, 'list',
"should save the correct view type");
return Promise.resolve(true);
}
return this._super.apply(this, arguments);
},
],
"The orderedBy should have been saved"
);
assert.strictEqual(
args.context_to_save.fire,
"on the bayou",
"The context of a controller should be passed and flattened"
);
assert.strictEqual(args.action_id, 1, "should save the correct action");
assert.strictEqual(args.view_mode, "list", "should save the correct view type");
return Promise.resolve(true);
}
});
};
await actionManager.doAction({
const webClient = await createWebClient({ testConfig, mockRPC });
await doAction(webClient, {
id: 1,
res_model: 'partner',
type: 'ir.actions.act_window',
views: [[false, 'list']],
res_model: "partner",
type: "ir.actions.act_window",
views: [[false, "list"]],
});
assert.containsOnce(actionManager, '.o_list_view',
"should display the list view");
assert.containsOnce(webClient, ".o_list_view", "should display the list view");
// Sort the list
await testUtils.dom.click($('.o_column_sortable'));
await testUtils.dom.click($(".o_column_sortable"));
// Group It
await cpHelpers.toggleGroupByMenu(actionManager);
await cpHelpers.toggleAddCustomGroup(actionManager);
await cpHelpers.applyGroup(actionManager);
await cpHelpers.toggleGroupByMenu(webClient);
await cpHelpers.toggleAddCustomGroup(webClient);
await cpHelpers.applyGroup(webClient);
// add this action to dashboard
await cpHelpers.toggleFavoriteMenu(actionManager);
await cpHelpers.toggleFavoriteMenu(webClient);
await testUtils.dom.click($('.o_add_to_board > button'));
await testUtils.fields.editInput($('.o_add_to_board input'), 'a name');
await testUtils.dom.click($('.o_add_to_board div button'));
await testUtils.dom.click($(".o_add_to_board > button"));
await testUtils.fields.editInput($(".o_add_to_board input"), "a name");
await testUtils.dom.click($(".o_add_to_board div button"));
testUtils.unpatch(ListController);
actionManager.destroy();
});
QUnit.test('save two searches to dashboard', async function (assert) {
QUnit.test("save two searches to dashboard", async function (assert) {
// the second search saved should not be influenced by the first
assert.expect(2);
var actionManager = await createActionManager({
data: this.data,
archs: {
'partner,false,list': '<list><field name="foo"/></list>',
'partner,false,search': '<search></search>',
},
mockRPC: function (route, args) {
if (route === '/board/add_to_dashboard') {
if (filter_count === 0) {
assert.deepEqual(args.domain, [["display_name", "ilike", "a"]],
"the correct domain should be sent");
}
if (filter_count === 1) {
assert.deepEqual(args.domain, [["display_name", "ilike", "b"]],
"the correct domain should be sent");
}
testConfig.serverData.views = {
"partner,false,list": '<list><field name="foo"/></list>',
"partner,false,search": "<search></search>",
};
filter_count += 1;
return Promise.resolve(true);
const mockRPC = (route, args) => {
if (route === "/board/add_to_dashboard") {
if (filter_count === 0) {
assert.deepEqual(
args.domain,
[["display_name", "ilike", "a"]],
"the correct domain should be sent"
);
}
if (filter_count === 1) {
assert.deepEqual(
args.domain,
[["display_name", "ilike", "b"]],
"the correct domain should be sent"
);
}
return this._super.apply(this, arguments);
},
});
await actionManager.doAction({
filter_count += 1;
return Promise.resolve(true);
}
};
const webClient = await createWebClient({ testConfig, mockRPC });
await doAction(webClient, {
id: 1,
res_model: 'partner',
type: 'ir.actions.act_window',
views: [[false, 'list']],
res_model: "partner",
type: "ir.actions.act_window",
views: [[false, "list"]],
});
var filter_count = 0;
// Add a first filter
await cpHelpers.toggleFilterMenu(actionManager);
await cpHelpers.toggleAddCustomFilter(actionManager);
await testUtils.fields.editInput(actionManager.el.querySelector('.o_generator_menu_value .o_input'), 'a');
await cpHelpers.applyFilter(actionManager);
await cpHelpers.toggleFilterMenu(webClient);
await cpHelpers.toggleAddCustomFilter(webClient);
await testUtils.fields.editInput(
webClient.el.querySelector(".o_generator_menu_value .o_input"),
"a"
);
await cpHelpers.applyFilter(webClient);
// Add it to dashboard
await cpHelpers.toggleFavoriteMenu(actionManager);
await testUtils.dom.click($('.o_add_to_board > button'));
await testUtils.dom.click($('.o_add_to_board div button'));
await cpHelpers.toggleFavoriteMenu(webClient);
await testUtils.dom.click($(".o_add_to_board > button"));
await testUtils.dom.click($(".o_add_to_board div button"));
// Remove it
await testUtils.dom.click(actionManager.el.querySelector('.o_facet_remove'));
await testUtils.dom.click(webClient.el.querySelector(".o_facet_remove"));
// Add the second filter
await cpHelpers.toggleFilterMenu(actionManager);
await cpHelpers.toggleAddCustomFilter(actionManager);
await testUtils.fields.editInput(actionManager.el.querySelector('.o_generator_menu_value .o_input'), "b");
await cpHelpers.applyFilter(actionManager);
await cpHelpers.toggleFilterMenu(webClient);
await cpHelpers.toggleAddCustomFilter(webClient);
await testUtils.fields.editInput(
webClient.el.querySelector(".o_generator_menu_value .o_input"),
"b"
);
await cpHelpers.applyFilter(webClient);
// Add it to dashboard
await cpHelpers.toggleFavoriteMenu(actionManager);
await testUtils.dom.click(actionManager.el.querySelector('.o_add_to_board > button'));
await testUtils.dom.click(actionManager.el.querySelector('.o_add_to_board div button'));
actionManager.destroy();
await cpHelpers.toggleFavoriteMenu(webClient);
await testUtils.dom.click(webClient.el.querySelector(".o_add_to_board > button"));
await testUtils.dom.click(webClient.el.querySelector(".o_add_to_board div button"));
});
QUnit.test('save a action domain to dashboard', async function (assert) {
QUnit.test("save a action domain to dashboard", async function (assert) {
// View domains are to be added to the dashboard domain
assert.expect(1);
@@ -840,47 +861,43 @@ QUnit.test('save a action domain to dashboard', async function (assert) {
var filter_domain = ["display_name", "ilike", "b"];
// The filter domain already contains the view domain, but is always added by dashboard..,
var expected_domain = ['&', view_domain, '&', view_domain, filter_domain];
var expected_domain = ["&", view_domain, "&", view_domain, filter_domain];
var actionManager = await createActionManager({
data: this.data,
archs: {
'partner,false,list': '<list><field name="foo"/></list>',
'partner,false,search': '<search></search>',
},
mockRPC: function (route, args) {
if (route === '/board/add_to_dashboard') {
assert.deepEqual(args.domain, expected_domain,
"the correct domain should be sent");
return Promise.resolve(true);
}
return this._super.apply(this, arguments);
},
});
testConfig.serverData.views = {
"partner,false,list": '<list><field name="foo"/></list>',
"partner,false,search": "<search></search>",
};
await actionManager.doAction({
const mockRPC = (route, args) => {
if (route === "/board/add_to_dashboard") {
assert.deepEqual(args.domain, expected_domain, "the correct domain should be sent");
return Promise.resolve(true);
}
};
const webClient = await createWebClient({ testConfig, mockRPC });
await doAction(webClient, {
id: 1,
res_model: 'partner',
type: 'ir.actions.act_window',
views: [[false, 'list']],
res_model: "partner",
type: "ir.actions.act_window",
views: [[false, "list"]],
domain: [view_domain],
});
// Add a filter
await cpHelpers.toggleFilterMenu(actionManager);
await cpHelpers.toggleAddCustomFilter(actionManager);
await cpHelpers.toggleFilterMenu(webClient);
await cpHelpers.toggleAddCustomFilter(webClient);
await testUtils.fields.editInput(
actionManager.el.querySelector('.o_generator_menu_value .o_input'),
webClient.el.querySelector(".o_generator_menu_value .o_input"),
"b"
);
await cpHelpers.applyFilter(actionManager);
await cpHelpers.applyFilter(webClient);
// Add it to dashboard
await cpHelpers.toggleFavoriteMenu(actionManager);
await testUtils.dom.click(actionManager.el.querySelector('.o_add_to_board > button'));
await cpHelpers.toggleFavoriteMenu(webClient);
await testUtils.dom.click(webClient.el.querySelector(".o_add_to_board > button"));
// add
await testUtils.dom.click(actionManager.el.querySelector('.o_add_to_board div button'));
actionManager.destroy();
await testUtils.dom.click(webClient.el.querySelector(".o_add_to_board div button"));
});
QUnit.test("Views should be loaded in the user's language", async function (assert) {
@@ -1041,62 +1058,71 @@ QUnit.test('click on a cell of pivot view inside dashboard', async function (ass
form.destroy();
});
QUnit.test('correctly save the time ranges of a reporting view in comparison mode', async function (assert) {
assert.expect(1);
QUnit.test(
"correctly save the time ranges of a reporting view in comparison mode",
async function (assert) {
assert.expect(1);
const unpatchDate = patchDate(2020, 6, 1, 11, 0, 0);
const unpatchDate = patchDate(2020, 6, 1, 11, 0, 0);
this.data.partner.fields.date = { string: 'Date', type: 'date', sortable: true };
testConfig.serverData.models.partner.fields.date = {
string: "Date",
type: "date",
sortable: true,
};
const actionManager = await createActionManager({
data: this.data,
archs: {
'partner,false,pivot': '<pivot><field name="foo"/></pivot>',
'partner,false,search': '<search><filter name="Date" date="date"/></search>',
},
mockRPC: function (route, args) {
if (route === '/board/add_to_dashboard') {
testConfig.serverData.views = {
"partner,false,pivot": '<pivot><field name="foo"/></pivot>',
"partner,false,search": '<search><filter name="Date" date="date"/></search>',
};
const mockRPC = (route, args) => {
if (route === "/board/add_to_dashboard") {
assert.deepEqual(args.context_to_save.comparison, {
comparisonId: "previous_period",
fieldName: "date",
fieldDescription: "Date",
rangeDescription: "July 2020",
range: ["&",["date", ">=", "2020-07-01"], ["date", "<=", "2020-07-31"]],
comparisonRange: ["&", ["date", ">=", "2020-06-01"], ["date", "<=", "2020-06-30"]],
range: ["&", ["date", ">=", "2020-07-01"], ["date", "<=", "2020-07-31"]],
comparisonRange: [
"&",
["date", ">=", "2020-06-01"],
["date", "<=", "2020-06-30"],
],
comparisonRangeDescription: "June 2020",
});
return Promise.resolve(true);
}
return this._super.apply(this, arguments);
},
});
};
await actionManager.doAction({
id: 1,
res_model: 'partner',
type: 'ir.actions.act_window',
views: [[false, 'pivot']],
});
const webClient = await createWebClient({ testConfig, mockRPC });
// filter on July 2020
await cpHelpers.toggleFilterMenu(actionManager);
await cpHelpers.toggleMenuItem(actionManager, 'Date');
await cpHelpers.toggleMenuItemOption(actionManager, 'Date', 'July');
await doAction(webClient, {
id: 1,
res_model: "partner",
type: "ir.actions.act_window",
views: [[false, "pivot"]],
});
// compare July 2020 to June 2020
await cpHelpers.toggleComparisonMenu(actionManager);
await cpHelpers.toggleMenuItem(actionManager, 0);
// filter on July 2020
await cpHelpers.toggleFilterMenu(webClient);
await cpHelpers.toggleMenuItem(webClient, "Date");
await cpHelpers.toggleMenuItemOption(webClient, "Date", "July");
// add the view to the dashboard
await cpHelpers.toggleFavoriteMenu(actionManager);
// compare July 2020 to June 2020
await cpHelpers.toggleComparisonMenu(webClient);
await cpHelpers.toggleMenuItem(webClient, 0);
await testUtils.dom.click($('.o_add_to_board > button'));
await testUtils.fields.editInput($('.o_add_to_board input'), 'a name');
await testUtils.dom.click($('.o_add_to_board div button'));
// add the view to the dashboard
await cpHelpers.toggleFavoriteMenu(webClient);
unpatchDate();
actionManager.destroy();
});
await testUtils.dom.click($(".o_add_to_board > button"));
await testUtils.fields.editInput($(".o_add_to_board input"), "a name");
await testUtils.dom.click($(".o_add_to_board div button"));
unpatchDate();
}
);
QUnit.test('correctly display the time range descriptions of a reporting view in comparison mode', async function (assert) {
assert.expect(1);