From 9b7ed7ed0bf6e6bae6bd1acbc19341af9d7b012f Mon Sep 17 00:00:00 2001 From: fdardenne Date: Wed, 9 Nov 2022 09:32:40 +0000 Subject: [PATCH] [IMP] web: `Layout`: make it friendly for client action Before, the `Layout` component was not friendly enough for client action. There was no default component for `ControlPanel` and `SearchPanel` in `Layout`, resulting in the fact that it had to be defined manually in the client action environment: ```js useSubEnv({ config: { ...getDefaultConfig(), ...this.env.config, }, }); } ``` Now, the `Layout` component defines default component for `ControlPanel` and `SearchPanel`. Making it easier to use for generic usage. closes odoo/odoo#105413 Signed-off-by: Aaron Bohy (aab) --- addons/web/static/src/search/layout.js | 13 ++++-- addons/web/static/src/views/view.js | 16 ++++---- addons/web/static/tests/views/layout_tests.js | 41 ++++++++++++++++++- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/addons/web/static/src/search/layout.js b/addons/web/static/src/search/layout.js index 7a8dc8e363e..53db5b820c1 100644 --- a/addons/web/static/src/search/layout.js +++ b/addons/web/static/src/search/layout.js @@ -1,15 +1,22 @@ /** @odoo-module **/ -import { pick } from "@web/core/utils/objects"; - import { Component, useRef } from "@odoo/owl"; +import { ControlPanel } from "@web/search/control_panel/control_panel"; +import { SearchPanel } from "@web/search/search_panel/search_panel"; /** * @param {Object} params * @returns {Object} */ export function extractLayoutComponents(params) { - return pick(params, "ControlPanel", "SearchPanel", "Banner"); + const layoutComponents = { + ControlPanel: params.ControlPanel || ControlPanel, + SearchPanel: params.SearchPanel || SearchPanel, + }; + if (params.Banner) { + layoutComponents.Banner = params.Banner; + } + return layoutComponents; } export class Layout extends Component { diff --git a/addons/web/static/src/views/view.js b/addons/web/static/src/views/view.js index 2d17ddc9d76..c52ff016ea9 100644 --- a/addons/web/static/src/views/view.js +++ b/addons/web/static/src/views/view.js @@ -5,14 +5,20 @@ import { registry } from "@web/core/registry"; import { KeepLast } from "@web/core/utils/concurrency"; import { useService } from "@web/core/utils/hooks"; import { deepCopy, pick } from "@web/core/utils/objects"; -import { ControlPanel } from "@web/search/control_panel/control_panel"; import { extractLayoutComponents } from "@web/search/layout"; -import { SearchPanel } from "@web/search/search_panel/search_panel"; import { WithSearch } from "@web/search/with_search/with_search"; import { OnboardingBanner } from "@web/views/onboarding_banner"; import { useActionLinks } from "@web/views/view_hook"; -import { Component, markRaw, onWillUpdateProps, onWillStart, toRaw, useSubEnv, reactive } from "@odoo/owl"; +import { + Component, + markRaw, + onWillUpdateProps, + onWillStart, + toRaw, + useSubEnv, + reactive, +} from "@odoo/owl"; const viewRegistry = registry.category("views"); /** @typedef {Object} Config @@ -25,8 +31,6 @@ const viewRegistry = registry.category("views"); * @property {() => Object} getPagerProps * @property {Object[]} viewSwitcherEntry * @property {Object[]} viewSwitcherEntry - * @property {Component} ControlPanel - * @property {Component} SearchPanel * @property {Component} Banner */ @@ -60,8 +64,6 @@ export function getDefaultConfig() { }, viewSwitcherEntries: [], views: [], - ControlPanel: ControlPanel, - SearchPanel: SearchPanel, Banner: OnboardingBanner, }; return config; diff --git a/addons/web/static/tests/views/layout_tests.js b/addons/web/static/tests/views/layout_tests.js index 05dfc2c6ede..dbfaac83b16 100644 --- a/addons/web/static/tests/views/layout_tests.js +++ b/addons/web/static/tests/views/layout_tests.js @@ -7,8 +7,10 @@ import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { getDefaultConfig } from "@web/views/view"; import { makeTestEnv } from "@web/../tests/helpers/mock_env"; +import { SearchModel } from "@web/search/search_model"; -import { Component, xml, useChildSubEnv } from "@odoo/owl"; +import { Component, xml, onWillStart, useChildSubEnv, useSubEnv } from "@odoo/owl"; +import { useService } from "@web/core/utils/hooks"; const serviceRegistry = registry.category("services"); @@ -93,6 +95,43 @@ QUnit.module("Views", (hooks) => { assert.containsOnce(target, ".o_content > .toy_content"); }); + QUnit.test("Rendering with default ControlPanel and SearchPanel", async (assert) => { + class ToyComponent extends Component { + setup() { + this.searchModel = new SearchModel(this.env, { + user: useService("user"), + orm: useService("orm"), + view: useService("view"), + }); + useSubEnv({ searchModel: this.searchModel }); + onWillStart(async () => { + await this.searchModel.load({ resModel: "foo" }); + }); + } + } + ToyComponent.template = xml` + +
+ `; + ToyComponent.components = { Layout }; + + const env = await makeTestEnv(); + const toyEnv = Object.assign(Object.create(env), { + config: { breadcrumbs: getDefaultConfig().breadcrumbs }, + }); + + await mount(ToyComponent, getFixture(), { env: toyEnv }); + + assert.containsOnce(target, ".o_search_panel"); + assert.containsOnce(target, ".o_control_panel"); + assert.containsOnce(target, ".breadcrumb"); + assert.containsOnce(target, ".o_component_with_search_panel"); + assert.containsOnce(target, ".o_content > .toy_content"); + }); + QUnit.test("Nested layouts", async (assert) => { // Component C: bottom (no control panel) class ToyC extends Component {