[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:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user