From e3a54289ac8ff3b4234771c6c8fccd65cb6ab7e1 Mon Sep 17 00:00:00 2001 From: Lucas Perais Date: Tue, 12 Jul 2022 09:01:55 +0000 Subject: [PATCH] [FIX] web: useViewButtons: add beforeExecute param This rev allows the function built by the useViewButtons hook to take a beforeExecute callback at call time, in addition to the existing beforeExecuteAction callback that we can pass to the hook, at the function's build time. The rationale for this is to allow any caller to prevent the execution of the action represented by the clickParams at the call level. It is useful to check if a user is allowed business-wise to execute an action. Part-of: odoo/odoo#78221 --- .../src/views/view_button/view_button_hook.js | 15 +++- .../tests/views/view_button_hook_tests.js | 79 +++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 addons/web/static/tests/views/view_button_hook_tests.js diff --git a/addons/web/static/src/views/view_button/view_button_hook.js b/addons/web/static/src/views/view_button/view_button_hook.js index 5e3fb5cb9ed..330f760e008 100644 --- a/addons/web/static/src/views/view_button/view_button_hook.js +++ b/addons/web/static/src/views/view_button/view_button_hook.js @@ -22,6 +22,10 @@ function enableButtons(el, manuallyDisabledButtons) { } } } + +function undefinedAsTrue(val) { + return typeof val === "undefined" || val; +} export function useViewButtons(model, ref, options = {}) { const action = useService("action"); const dialog = useService("dialog"); @@ -33,12 +37,17 @@ export function useViewButtons(model, ref, options = {}) { return true; }); useSubEnv({ - async onClickViewButton({ clickParams, record }) { + async onClickViewButton({ clickParams, record, beforeExecute }) { const manuallyDisabledButtons = disableButtons(getEl()); async function execute() { - const _continue = await beforeExecuteAction(clickParams); - if (typeof _continue !== "undefined" && !_continue) { + let _continue = true; + if (beforeExecute) { + _continue = undefinedAsTrue(await beforeExecute()); + } + + _continue = _continue && undefinedAsTrue(await beforeExecuteAction(clickParams)); + if (!_continue) { enableButtons(getEl(), manuallyDisabledButtons); return; } diff --git a/addons/web/static/tests/views/view_button_hook_tests.js b/addons/web/static/tests/views/view_button_hook_tests.js new file mode 100644 index 00000000000..efd7d38926c --- /dev/null +++ b/addons/web/static/tests/views/view_button_hook_tests.js @@ -0,0 +1,79 @@ +/** @odoo-module */ +import { useViewButtons } from "@web/views/view_button/view_button_hook"; +import { setupViewRegistries } from "./helpers"; +import { click, getFixture } from "../helpers/utils"; +import { makeTestEnv } from "../helpers/mock_env"; +import { registry } from "@web/core/registry"; + +const { useRef, mount, Component, xml } = owl; + +QUnit.module("UseViewButton tests", (hooks) => { + let target; + hooks.beforeEach(() => { + target = getFixture(); + setupViewRegistries(); + }); + + QUnit.test("action can be prevented", async (assert) => { + registry.category("services").add( + "action", + { + start() { + return { + doActionButton() { + assert.step("doActionButton"); + }, + }; + }, + }, + { force: true } + ); + + let executeInHook; + let executeInHandler; + class MyComponent extends Component { + setup() { + const rootRef = useRef("root"); + useViewButtons({}, rootRef, { + beforeExecuteAction: () => { + assert.step("beforeExecuteAction in hook"); + return executeInHook; + }, + }); + } + + onClick() { + const record = { + resIds: [3], + resId: 3, + load: () => {}, + }; + const clickParams = {}; + const beforeExecute = () => { + assert.step("beforeExecuteAction on handler"); + return executeInHandler; + }; + this.env.onClickViewButton({ beforeExecute, record, clickParams }); + } + } + MyComponent.template = xml`
Some text
`; + + const env = await makeTestEnv(); + await mount(MyComponent, target, { env, props: {} }); + + await click(target, ".myComponent"); + assert.verifySteps([ + "beforeExecuteAction on handler", + "beforeExecuteAction in hook", + "doActionButton", + ]); + + executeInHook = false; + await click(target, ".myComponent"); + assert.verifySteps(["beforeExecuteAction on handler", "beforeExecuteAction in hook"]); + + executeInHandler = false; + await click(target, ".myComponent"); + assert.verifySteps(["beforeExecuteAction on handler"]); + }); +});