From 60f143c8e7b7ea2387031c968dfa0f31a288afb2 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Fri, 31 Aug 2018 08:54:06 +0000 Subject: [PATCH] [FIX] board: handle actions with no view_mode The view_mode attribute is automatically set to the 'action' nodes when the action is added to the dashboard using the 'Add to dashboard' button in the searchview. However, other dashboard views can be written by hand (see openacademy tutorial), and in this case, we don't want to hardcode action's params (like context or domain), as the dashboard can directly retrieve them from the action. Same applies for the view_type, as the first view of the action can be used, by default. Before this rev., the second usecase wasn't handled, and it crashed when no view_mode was specified. This rev. also ensure that the context and domain are correctly retrieved from the action. Closes #24088 closes odoo/odoo#27519 --- addons/board/static/src/js/board_view.js | 17 +++--- addons/board/static/tests/dashboard_tests.js | 55 ++++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/addons/board/static/src/js/board_view.js b/addons/board/static/src/js/board_view.js index b2d57903a3d..126214cedf1 100644 --- a/addons/board/static/src/js/board_view.js +++ b/addons/board/static/src/js/board_view.js @@ -9,6 +9,7 @@ var Domain = require('web.Domain'); var FormController = require('web.FormController'); var FormRenderer = require('web.FormRenderer'); var FormView = require('web.FormView'); +var pyUtils = require('web.py_utils'); var viewRegistry = require('web.view_registry'); var _t = core._t; @@ -236,7 +237,6 @@ var BoardRenderer = FormRenderer.extend({ */ _createController: function (params) { var self = this; - var context = params.context.eval(); return this._rpc({ route: '/web/action/load', params: {action_id: params.actionID} @@ -246,18 +246,21 @@ var BoardRenderer = FormRenderer.extend({ // the action does not exist anymore return $.when(); } + var context = pyUtils.eval('context', new Context(params.context, action.context)); + var domain = params.domain || pyUtils.eval('domain', action.domain || '[]', action.context); + var viewType = params.viewType || action.views[0][1]; var view = _.find(action.views, function (descr) { - return descr[1] === params.viewType; - }) || [false, params.viewType]; + return descr[1] === viewType; + }) || [false, viewType]; return self.loadViews(action.res_model, context, [view]) .then(function (viewsInfo) { - var viewInfo = viewsInfo[params.viewType]; - var View = viewRegistry.get(params.viewType); + var viewInfo = viewsInfo[viewType]; + var View = viewRegistry.get(viewType); var view = new View(viewInfo, { action: action, context: context, - domain: params.domain, - groupBy: context.group_by, + domain: domain, + groupBy: context.group_by || [], modelName: action.res_model, hasSelectors: false, }); diff --git a/addons/board/static/tests/dashboard_tests.js b/addons/board/static/tests/dashboard_tests.js index e777b7b36b7..8b148c3ebb6 100644 --- a/addons/board/static/tests/dashboard_tests.js +++ b/addons/board/static/tests/dashboard_tests.js @@ -191,6 +191,61 @@ QUnit.test('basic functionality, with one sub action', function (assert) { form.destroy(); }); +QUnit.test('can render an action without view_mode attribute', function (assert) { + // The view_mode attribute is automatically set to the 'action' nodes when + // the action is added to the dashboard using the 'Add to dashboard' button + // in the searchview. However, other dashboard views can be written by hand + // (see openacademy tutorial), and in this case, we don't want hardcode + // action's params (like context or domain), as the dashboard can directly + // retrieve them from the action. Same applies for the view_type, as the + // first view of the action can be used, by default. + assert.expect(3); + + var form = createView({ + View: BoardView, + model: 'board', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '
', + archs: { + 'partner,4,list': + '', + }, + mockRPC: function (route, args) { + if (route === '/board/static/src/img/layout_1-1-1.png') { + return $.when(); + } + if (route === '/web/action/load') { + return $.when({ + context: '{"b": 2}', + domain: '[["foo", "=", "yop"]]', + res_model: 'partner', + views: [[4, 'list'], [false, 'form']], + }); + } + if (args.method === 'load_views') { + assert.deepEqual(args.kwargs.context, {a: 1, b: 2}, + "should have mixed both contexts"); + } + if (route === '/web/dataset/search_read') { + assert.deepEqual(args.domain, [['foo', '=', 'yop']], + "should use the domain of the action"); + } + return this._super.apply(this, arguments); + }, + }); + + assert.strictEqual(form.$('.oe_action:contains(ABC) .o_list_view').length, 1, + "the list view (first view of action) should have been rendered correctly"); + + form.destroy(); +}); + QUnit.test('can sort a sub list', function (assert) { assert.expect(2);