[REF] web: specialize useModel for sample data
Before this commit, there was a hook, named useModel, which eases the use of a model in views. The main (and almost only) role of the hook was to deal with sample data (determine whether or not they can be enabled, fallback on the sample orm when necessary, leave sample mode at reload...). This hook is used by all views except form and activity as they do not implement sample data. This commit renames that hook into "useModelWithSampleData" and introduces a new hook "useModel", which is a lot simpler that the other one, as it's only goal is to do the plumbing between the component using the hook and the model (i.e. spawning required services and loading the data on willStart and willUpdateProps). This new hook is used in form and activity views. Note that useModel doesn't trigger deep renderings, as it is only used on the RelationalModel which is based on fine-grained reactivity. Part-of: odoo/odoo#114024
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useMessaging } from "@mail/core/common/messaging_hook";
|
||||
|
||||
import { Component, onWillStart, onWillUpdateProps, useState } from "@odoo/owl";
|
||||
import { Component, useState } from "@odoo/owl";
|
||||
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { sprintf } from "@web/core/utils/strings";
|
||||
@@ -34,14 +34,7 @@ export class ActivityController extends Component {
|
||||
fields,
|
||||
},
|
||||
};
|
||||
const modelServices = Object.fromEntries(
|
||||
this.props.Model.services.map((servName) => {
|
||||
return [servName, useService(servName)];
|
||||
})
|
||||
);
|
||||
this.model = useState(new this.props.Model(this.env, modelParams, modelServices));
|
||||
onWillStart(() => this.model.load(this.props));
|
||||
onWillUpdateProps((nextProps) => this.model.root.load(nextProps));
|
||||
this.model = useState(useModel(this.props.Model, modelParams));
|
||||
|
||||
this.dialog = useService("dialog");
|
||||
this.action = useService("action");
|
||||
|
||||
@@ -5,7 +5,7 @@ import { _t, _lt } from "@web/core/l10n/translation";
|
||||
import { useOwnedDialogs, useService } from "@web/core/utils/hooks";
|
||||
import { sprintf } from "@web/core/utils/strings";
|
||||
import { Layout } from "@web/search/layout";
|
||||
import { useModel } from "@web/model/model";
|
||||
import { useModelWithSampleData } from "@web/model/model";
|
||||
import { FormViewDialog } from "@web/views/view_dialogs/form_view_dialog";
|
||||
import { useSetupView } from "@web/views/view_hook";
|
||||
import { CalendarDatePicker } from "./date_picker/calendar_date_picker";
|
||||
@@ -43,7 +43,7 @@ export class CalendarController extends Component {
|
||||
this.orm = useService("orm");
|
||||
this.displayDialog = useUniqueDialog();
|
||||
|
||||
this.model = useModel(this.props.Model, {
|
||||
this.model = useModelWithSampleData(this.props.Model, {
|
||||
...this.props.archInfo,
|
||||
resModel: this.props.resModel,
|
||||
domain: this.props.domain,
|
||||
|
||||
@@ -18,6 +18,7 @@ import { useViewButtons } from "@web/views/view_button/view_button_hook";
|
||||
import { useSetupView } from "@web/views/view_hook";
|
||||
import { ViewButton } from "@web/views/view_button/view_button";
|
||||
import { Field } from "@web/views/fields/field";
|
||||
import { useModel } from "@web/model/model";
|
||||
import { addFieldDependencies, extractFieldsFromArchInfo } from "@web/model/relational_model/utils";
|
||||
import { useViewCompiler } from "@web/views/view_compiler";
|
||||
import { CogMenu } from "@web/search/cog_menu/cog_menu";
|
||||
@@ -28,15 +29,7 @@ import { FormCompiler } from "./form_compiler";
|
||||
import { FormErrorDialog } from "./form_error_dialog/form_error_dialog";
|
||||
import { FormStatusIndicator } from "./form_status_indicator/form_status_indicator";
|
||||
|
||||
import {
|
||||
Component,
|
||||
onRendered,
|
||||
onWillStart,
|
||||
onWillUpdateProps,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "@odoo/owl";
|
||||
import { Component, onRendered, useEffect, useRef, useState } from "@odoo/owl";
|
||||
|
||||
const viewRegistry = registry.category("views");
|
||||
|
||||
@@ -129,19 +122,12 @@ export class FormController extends Component {
|
||||
this.canCreate = create && !this.props.preventCreate;
|
||||
this.canEdit = edit && !this.props.preventEdit;
|
||||
|
||||
const modelServices = Object.fromEntries(
|
||||
this.props.Model.services.map((servName) => {
|
||||
return [servName, useService(servName)];
|
||||
})
|
||||
);
|
||||
this.model = useState(new this.props.Model(this.env, this.modelParams, modelServices));
|
||||
|
||||
this.display = { ...this.props.display };
|
||||
if (this.env.inDialog) {
|
||||
this.display.controlPanel = false;
|
||||
}
|
||||
|
||||
onWillStart(async () => {
|
||||
const beforeFirstLoad = async () => {
|
||||
await loadSubViews(
|
||||
this.archInfo.fieldNodes,
|
||||
this.props.fields,
|
||||
@@ -162,13 +148,8 @@ export class FormController extends Component {
|
||||
}
|
||||
this.model.config.activeFields = activeFields;
|
||||
this.model.config.fields = fields;
|
||||
return this.model.load();
|
||||
});
|
||||
onWillUpdateProps((nextProps) => {
|
||||
if (nextProps.resId !== this.model.root.resId) {
|
||||
return this.model.root.load(nextProps.resId);
|
||||
}
|
||||
});
|
||||
};
|
||||
this.model = useState(useModel(this.props.Model, this.modelParams, { beforeFirstLoad }));
|
||||
|
||||
this.cpButtonsRef = useRef("cpButtons");
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Layout } from "@web/search/layout";
|
||||
import { useModel } from "@web/model/model";
|
||||
import { useModelWithSampleData } from "@web/model/model";
|
||||
import { standardViewProps } from "@web/views/standard_view_props";
|
||||
import { useSetupView } from "@web/views/view_hook";
|
||||
import { SearchBar } from "@web/search/search_bar/search_bar";
|
||||
@@ -12,7 +12,7 @@ import { Component, useRef } from "@odoo/owl";
|
||||
|
||||
export class GraphController extends Component {
|
||||
setup() {
|
||||
this.model = useModel(this.props.Model, this.props.modelParams);
|
||||
this.model = useModelWithSampleData(this.props.Model, this.props.modelParams);
|
||||
|
||||
useSetupView({
|
||||
rootRef: useRef("root"),
|
||||
|
||||
@@ -10,7 +10,7 @@ import { SearchBar } from "@web/search/search_bar/search_bar";
|
||||
import { useSearchBarToggler } from "@web/search/search_bar/search_bar_toggler";
|
||||
import { session } from "@web/session";
|
||||
import { useSetupView } from "@web/views/view_hook";
|
||||
import { useModel } from "@web/model/model";
|
||||
import { useModelWithSampleData } from "@web/model/model";
|
||||
import { standardViewProps } from "@web/views/standard_view_props";
|
||||
import { MultiRecordViewButton } from "@web/views/view_button/multi_record_view_button";
|
||||
import { useViewButtons } from "@web/views/view_button/view_button_hook";
|
||||
@@ -81,7 +81,9 @@ export class KanbanController extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
this.model = useState(useModel(KanbanSampleModel, this.modelParams, this.modelOptions));
|
||||
this.model = useState(
|
||||
useModelWithSampleData(KanbanSampleModel, this.modelParams, this.modelOptions)
|
||||
);
|
||||
if (archInfo.progressAttributes) {
|
||||
const { activeBars } = this.props.state || {};
|
||||
this.progressBarState = useProgressBar(
|
||||
|
||||
@@ -9,7 +9,7 @@ import { omit } from "@web/core/utils/objects";
|
||||
import { ActionMenus, STATIC_ACTIONS_GROUP_NUMBER } from "@web/search/action_menus/action_menus";
|
||||
import { Layout } from "@web/search/layout";
|
||||
import { usePager } from "@web/search/pager_hook";
|
||||
import { useModel } from "@web/model/model";
|
||||
import { useModelWithSampleData } from "@web/model/model";
|
||||
import { DynamicRecordList } from "@web/model/relational_model/dynamic_record_list";
|
||||
import { extractFieldsFromArchInfo } from "@web/model/relational_model/utils";
|
||||
import { standardViewProps } from "@web/views/standard_view_props";
|
||||
@@ -49,7 +49,7 @@ export class ListController extends Component {
|
||||
this.activeActions = this.archInfo.activeActions;
|
||||
this.editable =
|
||||
this.activeActions.edit && this.props.editable ? this.archInfo.editable : false;
|
||||
this.model = useState(useModel(this.props.Model, this.modelParams));
|
||||
this.model = useState(useModelWithSampleData(this.props.Model, this.modelParams));
|
||||
|
||||
// In multi edition, we save or notify invalidity directly when a field is updated, which
|
||||
// occurs on the change event for input fields. But we don't want to do it when clicking on
|
||||
@@ -80,7 +80,7 @@ export class ListController extends Component {
|
||||
: "x_active" in this.props.fields
|
||||
? !this.props.fields.x_active.readonly
|
||||
: false;
|
||||
useSubEnv({ model: this.model }); // do this in useModel?
|
||||
useSubEnv({ model: this.model }); // do this in useModelWithSampleData?
|
||||
useViewButtons(this.model, this.rootRef, {
|
||||
beforeExecuteAction: this.beforeExecuteActionButton.bind(this),
|
||||
afterExecuteAction: this.afterExecuteActionButton.bind(this),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Layout } from "@web/search/layout";
|
||||
import { useModel } from "@web/model/model";
|
||||
import { useModelWithSampleData } from "@web/model/model";
|
||||
import { standardViewProps } from "@web/views/standard_view_props";
|
||||
import { useSetupView } from "@web/views/view_hook";
|
||||
import { SearchBar } from "@web/search/search_bar/search_bar";
|
||||
@@ -12,7 +12,7 @@ import { Component, useRef } from "@odoo/owl";
|
||||
|
||||
export class PivotController extends Component {
|
||||
setup() {
|
||||
this.model = useModel(this.props.Model, this.props.modelParams);
|
||||
this.model = useModelWithSampleData(this.props.Model, this.props.modelParams);
|
||||
|
||||
useSetupView({
|
||||
rootRef: useRef("root"),
|
||||
|
||||
@@ -154,7 +154,7 @@ QUnit.test("nameGet method", async (assert) => {
|
||||
await env.services.orm.nameGet("sale.order", [2, 5], { context });
|
||||
assert.strictEqual(query.route, "/web/dataset/call_kw/sale.order/read");
|
||||
assert.deepEqual(query.params, {
|
||||
args: [[2, 5], ['display_name']],
|
||||
args: [[2, 5], ["display_name"]],
|
||||
kwargs: {
|
||||
context: {
|
||||
complete: true,
|
||||
@@ -361,7 +361,7 @@ QUnit.test("webSearchRead method", async (assert) => {
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("useModel is specialized for component", async (assert) => {
|
||||
QUnit.test("orm is specialized for component", async (assert) => {
|
||||
const [, /* query */ rpc] = makeFakeRPC();
|
||||
serviceRegistry.add("rpc", rpc);
|
||||
const env = await makeTestEnv();
|
||||
|
||||
Reference in New Issue
Block a user