+
+
+
diff --git a/addons/web/static/src/search/pager_hook.js b/addons/web/static/src/search/pager_hook.js
index b0f25d8ff36..df9c456629b 100644
--- a/addons/web/static/src/search/pager_hook.js
+++ b/addons/web/static/src/search/pager_hook.js
@@ -23,7 +23,7 @@ const { useEnv, useChildSubEnv, useState, onWillRender } = owl;
*/
export function usePager(getProps) {
const env = useEnv();
- const pagerState = useState(getProps());
+ const pagerState = useState({});
useChildSubEnv({
config: {
@@ -32,6 +32,6 @@ export function usePager(getProps) {
},
});
onWillRender(() => {
- Object.assign(pagerState, getProps());
+ Object.assign(pagerState, getProps() || { total: 0 });
});
}
diff --git a/addons/web/static/src/search/search_arch_parser.js b/addons/web/static/src/search/search_arch_parser.js
index 09bdb370079..9883356f40d 100644
--- a/addons/web/static/src/search/search_arch_parser.js
+++ b/addons/web/static/src/search/search_arch_parser.js
@@ -17,13 +17,13 @@ const DEFAULT_VIEWS_WITH_SEARCH_PANEL = ["kanban", "list"];
* @param {string} context
* @returns {string[]}
*/
-const getContextGroubBy = (context) => {
+function getContextGroubBy(context) {
try {
return makeContext([context]).group_by.split(":");
} catch (_err) {
return [];
}
-};
+}
function reduceType(type) {
if (type === "dateFilter") {
diff --git a/addons/web/static/src/search/search_bar/search_bar.js b/addons/web/static/src/search/search_bar/search_bar.js
index 30c81eba892..3437678b45c 100644
--- a/addons/web/static/src/search/search_bar/search_bar.js
+++ b/addons/web/static/src/search/search_bar/search_bar.js
@@ -37,7 +37,7 @@ export class SearchBar extends Component {
this.inputRef = useAutofocus();
- useBus(this.env.bus, "FOCUS-SEARCH-BAR", () => {
+ useBus(this.env.searchModel, "focus-search", () => {
this.inputRef.el.focus();
});
@@ -345,7 +345,7 @@ export class SearchBar extends Component {
focusedIndex = this.state.focusedIndex + 1;
}
} else {
- this.env.bus.trigger("FOCUS-VIEW");
+ this.env.searchModel.trigger("focus-view");
}
break;
case "ArrowUp":
diff --git a/addons/web/static/src/search/search_model.js b/addons/web/static/src/search/search_model.js
index 9ca0506e4c4..72e1704ca0a 100644
--- a/addons/web/static/src/search/search_model.js
+++ b/addons/web/static/src/search/search_model.js
@@ -266,8 +266,10 @@ export class SearchModel extends EventBus {
this.__legacyParseSearchPanelArchAnyway(searchViewDescription, searchViewFields);
this.domainParts = {};
this.display = this._getDisplay(config.display);
-
- return this._reloadSections();
+ if (!this.searchPanelInfo.loaded) {
+ return this._reloadSections();
+ }
+ return;
}
this.blockNotification = true;
@@ -310,7 +312,7 @@ export class SearchModel extends EventBus {
);
const { labels, preSearchItems, searchPanelInfo, sections } = parser.parse();
- this.searchPanelInfo = { ...searchPanelInfo, shouldReload: false };
+ this.searchPanelInfo = { ...searchPanelInfo, loaded: false, shouldReload: false };
await Promise.all(labels.map((cb) => cb(this.orm)));
@@ -1284,6 +1286,7 @@ export class SearchModel extends EventBus {
async _fetchSections(categoriesToLoad, filtersToLoad) {
await this._fetchCategories(categoriesToLoad);
await this._fetchFilters(filtersToLoad);
+ this.searchPanelInfo.loaded = true;
}
_getActiveComparison() {
@@ -1423,9 +1426,9 @@ export class SearchModel extends EventBus {
let domain;
try {
domain = Domain.and(domains);
- return params.raw ? domain : domain.toList(
- Object.assign({}, this.globalContext, this.userService.context)
- );
+ return params.raw
+ ? domain
+ : domain.toList(Object.assign({}, this.globalContext, this.userService.context));
} catch (error) {
throw new Error(
`${this.env._t("Failed to evaluate the domain")} ${domain.toString()}.\n${
@@ -2094,6 +2097,6 @@ export class SearchModel extends EventBus {
const parser = new SearchArchParser(searchViewDescription, searchViewFields);
const { searchPanelInfo } = parser.parse();
- this.searchPanelInfo = { ...searchPanelInfo, shouldReload: false };
+ this.searchPanelInfo = { ...searchPanelInfo, loaded: false, shouldReload: false };
}
}
diff --git a/addons/web/static/src/search/utils/misc.js b/addons/web/static/src/search/utils/misc.js
index 4a537462e19..73441e06e4b 100644
--- a/addons/web/static/src/search/utils/misc.js
+++ b/addons/web/static/src/search/utils/misc.js
@@ -14,5 +14,6 @@ export const GROUPABLE_TYPES = [
"datetime",
"integer",
"many2one",
+ "many2many",
"selection",
];
diff --git a/addons/web/static/src/search/with_search/with_search.js b/addons/web/static/src/search/with_search/with_search.js
index 1bf1c0732b0..b371ff93a51 100644
--- a/addons/web/static/src/search/with_search/with_search.js
+++ b/addons/web/static/src/search/with_search/with_search.js
@@ -7,12 +7,9 @@ import { CallbackRecorder, useSetupAction } from "@web/webclient/actions/action_
const { Component, onWillStart, onWillUpdateProps, toRaw, useSubEnv } = owl;
export const SEARCH_KEYS = ["comparison", "context", "domain", "groupBy", "orderBy"];
-const OTHER_SEARCH_KEYS = ["irFilters", "searchViewArch", "searchViewFields", "searchViewId"];
export class WithSearch extends Component {
setup() {
- this.Component = this.props.Component;
-
if (!this.env.__getContext__) {
useSubEnv({ __getContext__: new CallbackRecorder() });
}
@@ -54,31 +51,12 @@ export class WithSearch extends Component {
await this.searchModel.reload(config);
});
}
-
- //-------------------------------------------------------------------------
- // Getters
- //-------------------------------------------------------------------------
-
- get componentProps() {
- const componentProps = { ...this.props.componentProps };
- for (const key of SEARCH_KEYS) {
- componentProps[key] = this.searchModel[key];
- }
- componentProps.info = componentProps.info || {};
- for (const key of OTHER_SEARCH_KEYS) {
- componentProps.info[key] = this.searchModel[key];
- }
- return componentProps;
- }
}
-WithSearch.defaultProps = {
- componentProps: {},
-};
+WithSearch.template = "web.WithSearch";
WithSearch.props = {
- Component: Function,
+ slots: Object,
SearchModel: { type: Function, optional: true },
- componentProps: { type: Object, optional: true },
resModel: String,
@@ -107,4 +85,3 @@ WithSearch.props = {
dynamicFilters: { type: Array, element: Object, optional: true },
searchMenuTypes: { type: Array, element: String, optional: true },
};
-WithSearch.template = "web.WithSearch";
diff --git a/addons/web/static/src/search/with_search/with_search.xml b/addons/web/static/src/search/with_search/with_search.xml
index ec650abaf5c..cfae1dfb112 100644
--- a/addons/web/static/src/search/with_search/with_search.xml
+++ b/addons/web/static/src/search/with_search/with_search.xml
@@ -2,7 +2,12 @@
-
+
diff --git a/addons/web/static/tests/search/with_search_tests.js b/addons/web/static/tests/search/with_search_tests.js
index a881ee97b7e..2cb8f966ce9 100644
--- a/addons/web/static/tests/search/with_search_tests.js
+++ b/addons/web/static/tests/search/with_search_tests.js
@@ -322,18 +322,23 @@ QUnit.module("Search", (hooks) => {
class Parent extends Component {
setup() {
- this.state = useState({
+ this.searchState = useState({
resModel: "animal",
- Component: TestComponent,
domain: [["type", "=", "carnivorous"]],
});
}
}
- Parent.template = xml``;
- Parent.components = { WithSearch };
+ Parent.template = xml`
+
+
+
+ `;
+ Parent.components = { WithSearch, TestComponent };
const parent = await mount(Parent, target, { env });
- parent.state.domain = [["type", "=", "herbivorous"]];
+ parent.searchState.domain = [["type", "=", "herbivorous"]];
await nextTick();
});