From 3967dab0ce80d31c69902ea1a0a95c06d9376cb3 Mon Sep 17 00:00:00 2001 From: Jorge Pinna Puissant Date: Mon, 24 Jul 2023 10:30:21 +0000 Subject: [PATCH] [REF] web: RelationalModel: do not change resId in Record With this commit, we ensure that the resId of a Record datapoint never changes. The only exception is for new records: their resId can go from `false` to their actual id when they are created. When we want to load another record, we must use the `load` function of the model, which now accepts `resId` (and `resIds`) as param, when the root is a "mono record". As a consequence, the instance of record datapoint now changes when using the pager. This required some changes in the AceField, to make it properly react in that case. We took the opportunity to simplify its implementation (several keys in the state were useless). Part of task~3179751 Part-of: odoo/odoo#114024 --- .../src/model/relational_model/record.js | 37 +++++++++++-------- .../relational_model/relational_model.js | 8 +++- .../static/src/views/fields/ace/ace_field.js | 25 ++++--------- .../static/src/views/fields/ace/ace_field.xml | 4 +- .../static/src/views/form/form_controller.js | 4 +- .../kanban/kanban_record_quick_create.js | 2 +- addons/web/static/src/views/record.js | 2 +- .../views/view_dialogs/form_view_dialog.js | 3 +- .../views/fields/ace_editor_field_tests.js | 1 + 9 files changed, 43 insertions(+), 43 deletions(-) diff --git a/addons/web/static/src/model/relational_model/record.js b/addons/web/static/src/model/relational_model/record.js index cab21674422..60541ac85b4 100644 --- a/addons/web/static/src/model/relational_model/record.js +++ b/addons/web/static/src/model/relational_model/record.js @@ -153,7 +153,7 @@ export class Record extends DataPoint { resIds.splice(index, 1); const resId = resIds[Math.min(index, resIds.length - 1)] || false; if (resId) { - await this._load({ resId, resIds }); + await this.model.load({ resId, resIds }); } else { this.model._updateConfig(this.config, { resId: false }, { noReload: true }); this.dirty = false; @@ -177,7 +177,7 @@ export class Record extends DataPoint { const resId = await this.model.orm.call(this.resModel, "copy", [this.resId], kwargs); const resIds = this.resIds.slice(); resIds.splice(index + 1, 0, resId); - await this._load({ resId, resIds, mode: "edit" }); + await this.model.load({ resId, resIds, mode: "edit" }); }); } @@ -201,12 +201,11 @@ export class Record extends DataPoint { return this._invalidFields.has(fieldName); } - load(resId = this.resId, context = this.context) { - let mode = this.config.mode; - if (!resId) { - mode = "edit"; + load() { + if (arguments.length > 0) { + throw new Error("Record.load() does not accept arguments"); } - return this.model.mutex.exec(() => this._load({ resId, mode, context })); + return this.model.mutex.exec(() => this._load()); } openInvalidFieldsNotification() { @@ -540,8 +539,9 @@ export class Record extends DataPoint { } async _load(nextConfig = {}) { - // FIXME: do not allow to change resId? maybe add a new method on model to re-generate a - // new root for the new resId + if ("resId" in nextConfig && this.resId) { + throw new Error("Cannot change resId of a record"); + } await this.model._updateConfig(this.config, nextConfig, { commit: (values) => { if (this.resId) { @@ -767,13 +767,18 @@ export class Record extends DataPoint { return onError(e, { discard: () => this._discard() }); } if (!this.isInEdition) { - await this._load({ resId }); + const nextConfig = {}; + if (creation) { + nextConfig.resId = resId; + } + await this._load(nextConfig); } throw e; } if (!noReload) { - const nextConfig = { resId }; + const nextConfig = {}; if (creation) { + nextConfig.resId = resId; nextConfig.resIds = this.resIds.concat([resId]); } await this._load(nextConfig); @@ -857,13 +862,13 @@ export class Record extends DataPoint { */ async _toggleArchive(state) { const method = state ? "action_archive" : "action_unarchive"; - const context = this.context; - const resId = this.resId; - const action = await this.model.orm.call(this.resModel, method, [[resId]], { context }); + const action = await this.model.orm.call(this.resModel, method, [[this.resId]], { + context: this.context, + }); if (action && Object.keys(action).length) { - this.model.action.doAction(action, { onClose: () => this._load({ resId }) }); + this.model.action.doAction(action, { onClose: () => this._load() }); } else { - return this._load({ resId }); + return this._load(); } } diff --git a/addons/web/static/src/model/relational_model/relational_model.js b/addons/web/static/src/model/relational_model/relational_model.js index bd0bda31369..0c09c49662b 100644 --- a/addons/web/static/src/model/relational_model/relational_model.js +++ b/addons/web/static/src/model/relational_model/relational_model.js @@ -248,7 +248,13 @@ export class RelationalModel extends Model { const config = Object.assign({}, currentConfig); config.context = "context" in params ? params.context : config.context; - if (!currentConfig.isMonoRecord) { + if (currentConfig.isMonoRecord) { + config.resId = "resId" in params ? params.resId : config.resId; + config.resIds = "resIds" in params ? params.resIds : config.resIds; + if (!config.resId && config.mode !== "edit") { + config.mode = "edit"; + } + } else { config.domain = "domain" in params ? params.domain : config.domain; config.comparison = "comparison" in params ? params.comparison : config.comparison; diff --git a/addons/web/static/src/views/fields/ace/ace_field.js b/addons/web/static/src/views/fields/ace/ace_field.js index d7ab0bd52a6..ab532b61823 100644 --- a/addons/web/static/src/views/fields/ace/ace_field.js +++ b/addons/web/static/src/views/fields/ace/ace_field.js @@ -3,11 +3,11 @@ import { _lt } from "@web/core/l10n/translation"; import { registry } from "@web/core/registry"; import { useBus, useService } from "@web/core/utils/hooks"; -import { effect } from "@web/core/utils/reactive"; import { standardFieldProps } from "../standard_field_props"; import { CodeEditor } from "@web/core/code_editor/code_editor"; import { Component, useState } from "@odoo/owl"; +import { useRecordObserver } from "@web/model/relational_model/utils"; import { useDebounced } from "@web/core/utils/timing"; export class AceField extends Component { @@ -25,24 +25,11 @@ export class AceField extends Component { this.cookies = useService("cookie"); this.debouncedCommit = useDebounced(this.commitChanges, 5000); - this.state = useState({ - onChange: (value) => this.handleChange(value), - class: "ace-view-editor", - theme: this.theme, + this.state = useState({}); + useRecordObserver((record) => { + this.state.value = record.data[this.props.name]; }); - this.lastSetValue = false; - effect( - async ({ record, mode, name, readonly }) => { - if (this.lastSetValue !== record.data[name]) { - this.state.value = record.data[name]; - } - this.state.mode = mode === "xml" ? "qweb" : mode; - this.state.readonly = readonly; - }, - [this.props] - ); - const { model } = this.props.record; useBus(model.bus, "WILL_SAVE_URGENTLY", () => this.commitChanges()); useBus(model.bus, "NEED_LOCAL_CHANGES", ({ detail }) => @@ -50,6 +37,9 @@ export class AceField extends Component { ); } + get mode() { + return this.props.mode === "xml" ? "qweb" : this.props.mode; + } get theme() { return this.cookies.current.color_scheme === "dark" ? "monokai" : ""; } @@ -64,7 +54,6 @@ export class AceField extends Component { if (!this.props.readonly) { const value = this.state.value; if (this.props.record.data[this.props.name] !== value) { - this.lastSetValue = value; await this.props.record.update({ [this.props.name]: value }); } } diff --git a/addons/web/static/src/views/fields/ace/ace_field.xml b/addons/web/static/src/views/fields/ace/ace_field.xml index f86d50c153b..ab8920630b8 100644 --- a/addons/web/static/src/views/fields/ace/ace_field.xml +++ b/addons/web/static/src/views/fields/ace/ace_field.xml @@ -6,8 +6,8 @@
{ await pagerNext(target); await nextTick(); + await nextTick(); assert.ok(target.querySelector(".o_field_code").textContent.includes("blip")); });