[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) <aab@odoo.com>
This commit is contained in:
fdardenne
2022-11-10 16:05:56 +01:00
parent bbca93a811
commit 9b7ed7ed0b
3 changed files with 59 additions and 11 deletions
+10 -3
View File
@@ -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 {
+9 -7
View File
@@ -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;
+40 -1
View File
@@ -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`
<Layout className="'o_view_sample_data'" display="{
controlPanel: { 'top-right': false, 'bottom-right': false, 'bottom-left': false },
searchPanel: true,
}">
<div class="toy_content" />
</Layout>`;
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 {