diff --git a/addons/web/static/lib/owl/owl.js b/addons/web/static/lib/owl/owl.js index 3f2c7825867..f23bdf2383a 100644 --- a/addons/web/static/lib/owl/owl.js +++ b/addons/web/static/lib/owl/owl.js @@ -5132,8 +5132,9 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration if (this.dev && !config.test) { console.info(DEV_MSG()); } - const descrs = Object.getOwnPropertyDescriptors(config.env || {}); - this.env = Object.freeze(Object.defineProperties({}, descrs)); + const env = config.env || {}; + const descrs = Object.getOwnPropertyDescriptors(env); + this.env = Object.freeze(Object.create(Object.getPrototypeOf(env), descrs)); this.props = config.props || {}; } mount(target, options) { diff --git a/addons/web/static/src/legacy/utils.js b/addons/web/static/src/legacy/utils.js index 4f888affb44..0f52fde1505 100644 --- a/addons/web/static/src/legacy/utils.js +++ b/addons/web/static/src/legacy/utils.js @@ -9,6 +9,11 @@ import { ConnectionLostError, } from "../core/network/rpc_service"; import { ErrorDialog } from "../core/errors/error_dialogs"; +import { useService } from "@web/core/utils/hooks"; + +const { useComponent } = owl; + +const wowlServicesSymbol = Symbol("wowlServices"); export function makeLegacyRpcService(legacyEnv) { return { @@ -136,6 +141,9 @@ export function makeLegacySessionService(legacyEnv, session) { } export function mapLegacyEnvToWowlEnv(legacyEnv, wowlEnv) { + // store wowl services on the legacy env (used by the 'useWowlService' hook) + legacyEnv[wowlServicesSymbol] = wowlEnv.services; + // rpc legacyEnv.session.rpc = (...args) => { let rejection; @@ -332,3 +340,17 @@ export function useLegacyRefs() { return legacyRefs; } + +/** + * This hook allows legacy owl Components to use services coming from the wowl env. + * @param {string} serviceName + * @returns {any} + */ +export function useWowlService(serviceName) { + const component = useComponent(); + const env = component.env; + component.env = { services: env[wowlServicesSymbol] }; + const service = useService(serviceName); + component.env = env; + return service; +} diff --git a/addons/web/static/tests/legacy/owl_compatibility_tests.js b/addons/web/static/tests/legacy/owl_compatibility_tests.js index ca45449b7e0..bf986ff212e 100644 --- a/addons/web/static/tests/legacy/owl_compatibility_tests.js +++ b/addons/web/static/tests/legacy/owl_compatibility_tests.js @@ -12,15 +12,20 @@ odoo.define('web.OwlCompatibilityTests', function (require) { } = require('web.OwlCompatibility'); const testUtils = require('web.test_utils'); const Widget = require('web.Widget'); + const { registry } = require("@web/core/registry"); const { LegacyComponent } = require("@web/legacy/legacy_component"); + const { mapLegacyEnvToWowlEnv, useWowlService } = require("@web/legacy/utils"); + + const makeTestEnvironment = require("web.test_env"); + const { makeTestEnv } = require("@web/../tests/helpers/mock_env"); + const { getFixture, mount, useLogLifeCycle, destroy } = require("@web/../tests/helpers/utils"); const makeTestPromise = testUtils.makeTestPromise; const nextTick = testUtils.nextTick; const addMockEnvironmentOwl = testUtils.mock.addMockEnvironmentOwl; - const { mount, useLogLifeCycle, destroy } = require("@web/../tests/helpers/utils"); - const { + Component, onError, onMounted, onWillDestroy, @@ -1658,5 +1663,29 @@ odoo.define('web.OwlCompatibilityTests', function (require) { delete fieldRegistry.map.pad_like; delete widgetRegistry.map.widget_comp; }); + + QUnit.module("useWowlService"); + + QUnit.test("simple use case of useWowlService", async function (assert) { + assert.expect(1); + + registry.category("services").add("test", { + start() { + return "I'm a wowl service"; + }, + }); + const wowlEnv = await makeTestEnv(); + const legacyEnv = makeTestEnvironment(); + mapLegacyEnvToWowlEnv(legacyEnv, wowlEnv); + + class MyComponent extends Component { + setup() { + assert.strictEqual(useWowlService("test"), "I'm a wowl service"); + } + } + MyComponent.template = xml`
`; + + await mount(MyComponent, getFixture(), { env: legacyEnv }); + }); }); });