From 37db3903588026dc6ed73de8090dba59a7c473a6 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Fri, 15 Jun 2018 09:00:39 +0200 Subject: [PATCH] [FIX] web: enable button at end of action When clicking on an action button, the following steps are performed: 1. Buttons are disabled 2. The button call is performed 3. At the end of the call, the buttons are enabled 4. Extra RPC are performed (`read`, `name_get`) 5. When the RPC calls are finished, the form is reloaded In the case of a validation of a SO, it means that the 'Confirm' button is enabled at step 3, but hidden at step 5. On a slow network (or an overloaded server), it means that the user has enough time (step 4) to click again on the 'Confirm' button and trigger the action more than once. The root cause is that we don't retrieve the promise of the `reload` mechanism (defined in `_callButtonAction`) when executing `on_close` (triggered after the button call). We return a promise which is resolved and enable the buttons too early. We make sure to retrieve the promise of the `reload` and return it, so that the promise of `saveAndExecuteAction` (defined in `_onButtonClicked`) is correctly linked to it. This way, `_enableButtons` is called when the reload is performed. Co-authored-by: Aaron Bohy (well, actually he did most of it) opw-1859027 --- .../static/src/js/chrome/action_manager.js | 5 ++- .../tests/chrome/action_manager_tests.js | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/chrome/action_manager.js b/addons/web/static/src/js/chrome/action_manager.js index 36c94a95c0e..ecd1d89ea9c 100644 --- a/addons/web/static/src/js/chrome/action_manager.js +++ b/addons/web/static/src/js/chrome/action_manager.js @@ -485,8 +485,9 @@ var ActionManager = Widget.extend({ * @returns {Deferred} resolved immediately */ _executeCloseAction: function (action, options) { + var result; if (!this.currentDialogController) { - options.on_close(); + result = options.on_close(); } this._closeDialog(); @@ -496,7 +497,7 @@ var ActionManager = Widget.extend({ this.trigger_up('show_effect', action.effect); } - return $.when(); + return $.when(result); }, /** * Executes actions of type 'ir.actions.server'. diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index 09e7550b524..84e939de6da 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -2301,6 +2301,51 @@ QUnit.module('ActionManager', { actionManager.destroy(); }); + QUnit.test('requests for execute_action of type object: disable buttons', function (assert) { + assert.expect(2); + + var self = this; + var def; + var actionManager = createActionManager({ + actions: this.actions, + archs: this.archs, + data: this.data, + mockRPC: function (route, args) { + if (route === '/web/dataset/call_button') { + return $.when(false); + } else if (args.method === 'read') { + // Block the 'read' call + var result = this._super.apply(this, arguments); + return $.when(def).then(_.constant(result)); + } + return this._super.apply(this, arguments); + }, + }); + actionManager.doAction(3); + + // open a record in form view + actionManager.$('.o_list_view .o_data_row:first').click(); + + // click on 'Call method' button (should call an Object method) + def = $.Deferred(); + actionManager.$('.o_form_view button:contains(Call method)').click(); + + // Buttons should be disabled + assert.strictEqual( + actionManager.$('.o_form_view button:contains(Call method)').attr('disabled'), + 'disabled', 'buttons should be disabled') + + // Release the 'read' call + def.resolve(); + + // Buttons should be enabled after the reload + assert.strictEqual( + actionManager.$('.o_form_view button:contains(Call method)').attr('disabled'), + undefined, 'buttons should be disabled') + + actionManager.destroy(); + }); + QUnit.test('can open different records from a multi record view', function (assert) { assert.expect(11);