From 2a6ff8f8e47874151c45352f31b8206b3fab9456 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Mon, 19 Mar 2018 15:14:42 +0100 Subject: [PATCH] [IMP] web: ActionManager: load window actions without id Actions can be loaded from the state of the url (e.g. when pressing F5). For window actions, it was working properly if the action id or a record id (i.e. for form views) was given. In other words, states like 'model=res.partner&view_type=kanban' couldn't be loaded. This can be explained by the fact that without an action id, the context and domain of the action couldn't be obtained. This rev. solves this problem by storing the current action into the sessionStorage, so that important information like context, domain and name can be retrieved if this action has to be restored (i.e. if the user refreshes the page). --- .../static/src/js/chrome/action_manager.js | 6 ++ .../js/chrome/action_manager_act_window.js | 9 +++ .../tests/chrome/action_manager_tests.js | 60 +++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/addons/web/static/src/js/chrome/action_manager.js b/addons/web/static/src/js/chrome/action_manager.js index c4d3f591545..bed9673d44c 100644 --- a/addons/web/static/src/js/chrome/action_manager.js +++ b/addons/web/static/src/js/chrome/action_manager.js @@ -358,6 +358,10 @@ var ActionManager = Widget.extend({ // toggle the fullscreen mode for actions in target='fullscreen' self._toggleFullscreen(); + // store the action into the sessionStorage so that it can be + // fully restored on F5 + self.call('session_storage', 'setItem', 'current_action', action._originalAction); + return action; }) .fail(function () { @@ -763,6 +767,8 @@ var ActionManager = Widget.extend({ * @param {Object} options see @doAction options */ _preprocessAction: function (action, options) { + action._originalAction = JSON.stringify(action); + action.jsID = _.uniqueId('action_'); action.pushState = options.pushState; diff --git a/addons/web/static/src/js/chrome/action_manager_act_window.js b/addons/web/static/src/js/chrome/action_manager_act_window.js index 4e636de6355..be6ac5e2230 100644 --- a/addons/web/static/src/js/chrome/action_manager_act_window.js +++ b/addons/web/static/src/js/chrome/action_manager_act_window.js @@ -91,6 +91,15 @@ ActionManager.include({ type: 'ir.actions.act_window', views: [[state.view_id || false, 'form']], }; + } else if (state.model && state.view_type) { + // this is a window action on a multi-record view, so restore it + // from the session storage + var storedAction = this.call('session_storage', 'getItem', 'current_action'); + var lastAction = JSON.parse(storedAction || '{}'); + if (lastAction.res_model === state.model) { + action = lastAction; + options.viewType = state.view_type; + } } if (action) { return this.doAction(action, options); diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index c805da4e67c..9d15e729094 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -4,9 +4,11 @@ odoo.define('web.action_manager_tests', function (require) { var ReportClientAction = require('report.client_action'); var AbstractAction = require('web.AbstractAction'); +var AbstractStorageService = require('web.AbstractStorageService'); var ControlPanelMixin = require('web.ControlPanelMixin'); var core = require('web.core'); var ListController = require('web.ListController'); +var RamStorage = require('web.RamStorage'); var ReportService = require('web.ReportService'); var testUtils = require('web.test_utils'); var Widget = require('web.Widget'); @@ -1030,6 +1032,64 @@ QUnit.module('ActionManager', { delete core.action_registry.map.ClientAction; }); + QUnit.test('load a window action without id (in a multi-record view)', function (assert) { + assert.expect(14); + + var RamStorageService = AbstractStorageService.extend({ + name: 'session_storage', + storage: new RamStorage(), + }); + + var actionManager = createActionManager({ + actions: this.actions, + archs: this.archs, + data: this.data, + services: [RamStorageService], + mockRPC: function (route, args) { + assert.step(args.method || route); + return this._super.apply(this, arguments); + }, + }); + + testUtils.intercept(actionManager, 'call_service', function (ev) { + if (ev.data.service === 'session_storage') { + assert.step(ev.data.method); + } + }, true); + + actionManager.doAction(4); + + assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + "should display a kanban view"); + assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners Action 4', + "breadcrumbs should display the display_name of the action"); + + actionManager.loadState({ + model: 'partner', + view_type: 'list', + }); + + assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners Action 4', + "should still be in the same action"); + assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, + "should no longer display a kanban view"); + assert.strictEqual(actionManager.$('.o_list_view').length, 1, + "should display a list view"); + + assert.verifySteps([ + '/web/action/load', // action 3 + 'load_views', // action 3 + '/web/dataset/search_read', // action 3 + 'setItem', // action 3 + 'getItem', // loadState + 'load_views', // loaded action + '/web/dataset/search_read', // loaded action + 'setItem', // loaded action + ]); + + actionManager.destroy(); + }); + QUnit.module('Concurrency management'); QUnit.test('drop previous actions if possible', function (assert) {