diff --git a/addons/web/__manifest__.py b/addons/web/__manifest__.py
index 7cdcf22df13..1f766f18fbb 100644
--- a/addons/web/__manifest__.py
+++ b/addons/web/__manifest__.py
@@ -187,7 +187,6 @@ This module provides the core of the Odoo Web Client.
'web/static/src/core/utils/transitions.scss',
'web/static/src/core/**/*',
- 'web/static/src/legacy/legacy_fields.scss',
'web/static/src/search/**/*',
'web/static/src/webclient/icons.scss', # variables required in list_controller.scss
'web/static/src/views/**/*',
@@ -244,8 +243,6 @@ This module provides the core of the Odoo Web Client.
'web/static/src/legacy/legacy_dialog.js',
'web/static/src/legacy/legacy_load_views.js',
'web/static/src/legacy/legacy_views.js',
- 'web/static/src/legacy/legacy_fields.js',
- 'web/static/src/legacy/legacy_view_widgets.js',
'web/static/src/legacy/legacy_promise_error_handler.js',
'web/static/src/legacy/legacy_rpc_error_handler.js',
'web/static/src/legacy/root_widget.js',
diff --git a/addons/web/static/src/legacy/legacy_fields.js b/addons/web/static/src/legacy/legacy_fields.js
deleted file mode 100644
index c3633f766b6..00000000000
--- a/addons/web/static/src/legacy/legacy_fields.js
+++ /dev/null
@@ -1,377 +0,0 @@
-/** @odoo-module **/
-
-import { registry } from "@web/core/registry";
-import { sprintf } from "@web/core/utils/strings";
-import { Domain } from "web.Domain";
-import legacyFieldRegistry from "web.field_registry";
-import { ComponentAdapter } from "web.OwlCompatibility";
-import { useWowlService } from "@web/legacy/utils";
-import { RPCError } from "@web/core/network/rpc_service";
-import { useTranslationDialog } from "@web/views/fields/translation_button";
-
-const { Component, useEffect, xml } = owl;
-const fieldRegistry = registry.category("fields");
-
-const legacyFieldTemplate = xml`
- `;
-
-// -----------------------------------------------------------------------------
-// FieldAdapter
-// -----------------------------------------------------------------------------
-
-class FieldAdapter extends ComponentAdapter {
- setup() {
- super.setup();
- this.translationDialog = useTranslationDialog();
- this.wowlEnv = this.env;
- this.env = Component.env;
- this.orm = useWowlService("orm");
- useEffect(() => {
- if (!this.widgetEl || !this.widgetEl.parentElement) {
- return;
- }
-
- const fieldId = this.props.id;
- if (!this.widgetEl.querySelector(`#${fieldId}`)) {
- const $el = this.widget.getFocusableElement();
- if ($el && $el[0]) {
- $el[0].setAttribute("id", fieldId);
- }
- }
-
- // if classNames are given to the field, we only want
- // to add those classes to the legacy field without
- // the parent element affecting the style of the field
- const fieldClassnames =
- this.props.fieldParams.options &&
- this.props.fieldParams.options.attrs &&
- this.props.fieldParams.options.attrs.class;
- if (fieldClassnames) {
- for (const className of fieldClassnames.split(" ")) {
- this.widgetEl.parentElement.classList.remove(className);
- this.widgetEl.classList.add(className);
- }
- this.widgetEl.parentElement.style.display = "contents";
- }
- this.widgetEl.parentElement.classList.remove("o_text_overflow");
- this.widgetEl.classList.add("o_legacy_field_widget");
- });
- this.lastFieldChangedEvent = null;
- }
-
- /**
- * @override
- */
- get widgetArgs() {
- const { name, record, options } = this.props.fieldParams;
- return [name, record, options];
- }
-
- async updateWidget(nextProps) {
- const { name, record, options } = nextProps.fieldParams;
- if (this.widget.mode !== options.mode) {
- // the mode changed, we need to instantiate a new FieldWidget
- if (this.oldWidget) {
- this.widget.destroy(); // we were already updating -> abort, and start over
- } else {
- this.oldWidget = this.widget;
- }
- this.widget = new this.props.Component(this, name, record, options);
- this.widgetProm = this.widget._widgetRenderAndInsert(() => {});
- return this.widgetProm;
- } else {
- // the mode is the same, simply reset the FieldWidget with the new record
- await this.widgetProm;
- return this.widget.reset(record, this.lastFieldChangedEvent, true);
- }
- }
-
- renderWidget() {
- if (this.oldWidget) {
- const parentEl = this.oldWidget.el.parentElement;
- parentEl.replaceChild(this.widget.el, this.oldWidget.el);
- this.widgetEl = this.widget.el;
- if (this.widget.on_attach_callback) {
- this.widget.on_attach_callback();
- }
- this.oldWidget.destroy();
- this.oldWidget = null;
- }
- }
-
- async _trigger_up(ev) {
- const evType = ev.name;
- const payload = ev.data;
- if (evType === "set_dirty") {
- // TODO (not yet handled in the Record datapoint)
- } else if (evType === "field_changed") {
- const { name, record } = this.props.fieldParams;
- const proms = [];
- for (const fieldName in payload.changes) {
- let value = payload.changes[fieldName];
- const fieldType = record.fields[fieldName].type;
- if (fieldType === "many2one" && value) {
- value = [value.id, value.display_name];
- } else if (fieldType === "one2many" || fieldType === "many2many") {
- // TODO map all operations
- if (value.operation === "ADD_M2M") {
- const valueIds = value.ids; // can be a lot of stuff
- let newIds = [];
- if (Array.isArray(valueIds)) {
- if (typeof valueIds[0] === "number") {
- newIds = valueIds; // not sure if it is a real case: a list of ids
- } else if (valueIds.length && "id" in valueIds[0]) {
- newIds = valueIds.map((r) => r.id);
- }
- } else if ("id" in valueIds && valueIds.id) {
- newIds = [valueIds.id];
- } else if ("id" in valueIds) {
- const fieldName = this.props.fieldParams.name;
- let newId;
- try {
- [newId] = await this.orm.call(
- this.props.record.fields[fieldName].relation,
- "name_create",
- [valueIds.display_name],
- {
- context: this.props.record.getFieldContext(fieldName),
- }
- );
- } catch (e) {
- if (!(e instanceof RPCError)) {
- throw e;
- }
- if (payload.onFailure) {
- // wrap error for guardedCatch compatibility in legacy code
- payload.onFailure({
- message: e,
- event: $.Event(),
- legacy: true,
- });
- }
- return;
- }
- newIds = [newId];
- }
- value = {
- resIds: [...record.data[name].res_ids, ...newIds],
- operation: "REPLACE_WITH",
- };
- }
- } else if (fieldType === "date" || fieldType === "datetime") {
- // from moment to luxon
- value = value ? luxon.DateTime.fromISO(value.toISOString()) : false;
- }
- proms.push(this.props.update(fieldName, value));
- }
- this.lastFieldChangedEvent = ev;
- await Promise.all(proms);
- if (payload.onSuccess) {
- payload.onSuccess();
- }
- // TODO: handle onFailure?
- } else if (evType === "reload") {
- const record = this.props.record;
- if (payload.db_id === record.id) {
- await record.model.reloadRecords(record);
- } else {
- await record.model.root.load();
- record.model.notify();
- }
- if (payload.onSuccess) {
- payload.onSuccess();
- }
- } else if (evType === "history_back") {
- return this.wowlEnv.config.historyBack();
- } else if (evType === "translate") {
- const { fieldParams, record, update } = this.props;
- return this.translationDialog({
- fieldName: fieldParams.name,
- record,
- updateField: update,
- });
- }
- super._trigger_up(...arguments);
- }
-}
-
-// -----------------------------------------------------------------------------
-// Helpers to map wowl datapoints to basic model datapoints
-// -----------------------------------------------------------------------------
-
-let nextId = 1;
-function createMany2OneDatapoint([resId, displayName]) {
- return {
- id: `m2o_${nextId++}`,
- data: { id: resId, display_name: displayName },
- fields: {
- display_name: { type: "char" },
- id: { type: "integer" },
- },
- res_id: resId,
- ref: resId,
- };
-}
-
-function mapDatapoint(datapoint) {
- return {
- id: datapoint.id,
- model: datapoint.resModel,
- fields: datapoint.fields,
- fieldsInfo: {
- default: datapoint.activeFields, // TODO: how to handle viewTypes?
- },
- getContext: () => [], // TODO: not yet handled in wowl
- getDomain: () => [], // TODO: not yet handled in wowl
- getFieldNames: () => datapoint.fieldNames,
- };
-}
-
-function mapStaticListDatapoint(staticList) {
- return {
- ...mapDatapoint(staticList),
- res_ids: staticList.currentIds,
- data: staticList.records.map(mapRecordDatapoint),
- groupedBy: [],
- orderedBy: staticList.orderBy,
- count: staticList.count,
- };
-}
-
-export function mapRecordDatapoint(record) {
- const data = Object.assign({}, record.data);
- for (const fieldName of record.fieldNames) {
- const fieldType = record.fields[fieldName].type;
- switch (fieldType) {
- case "one2many":
- case "many2many":
- data[fieldName] = mapStaticListDatapoint(data[fieldName]);
- break;
- case "many2one":
- data[fieldName] = data[fieldName] && createMany2OneDatapoint(data[fieldName]);
- break;
- case "date":
- case "datetime":
- // from luxon to moment
- data[fieldName] = data[fieldName] ? moment(data[fieldName].toISO()) : false;
- }
- }
- data.id = record.resId;
- const basicModelRecord = {
- ...mapDatapoint(record),
- res_id: record.resId,
- data,
- };
- Object.defineProperty(basicModelRecord, "evalContext", {
- get: () => record.evalContext,
- });
- Object.defineProperty(basicModelRecord, "isDirty", {
- get: () => record.isDirty,
- });
- Object.defineProperty(basicModelRecord, "isNew", {
- get: () => record.isDirty,
- });
- basicModelRecord.evalModifiers = (modifiers) => {
- let evalContext = null;
- const evaluated = {};
- for (const k of ["invisible", "column_invisible", "readonly", "required"]) {
- const mod = modifiers[k];
- if (mod === undefined || mod === false || mod === true) {
- if (k in modifiers) {
- evaluated[k] = !!mod;
- }
- continue;
- }
- try {
- evalContext = evalContext || basicModelRecord.evalContext;
- evaluated[k] = new Domain(mod, evalContext).compute(evalContext);
- } catch (e) {
- throw new Error(sprintf('for modifier "%s": %s', k, e.message));
- }
- }
- return evaluated;
- };
- return basicModelRecord;
-}
-
-// -----------------------------------------------------------------------------
-// Register legacy field widgets to the wowl field registry (wrapped in a Component)
-// -----------------------------------------------------------------------------
-
-function registerField(name, LegacyFieldWidget) {
- class LegacyField extends Component {
- setup() {
- this.FieldWidget = LegacyFieldWidget;
- }
-
- get fieldParams() {
- const { name, record } = this.props;
- let legacyRecord;
- const fieldInfo = record.activeFields[name];
- let views = {};
- const modifiers = JSON.parse(fieldInfo.rawAttrs.modifiers || "{}");
- const hasReadonlyModifier = record.isReadonly(name);
- if (record.model.__bm__) {
- legacyRecord = record.model.__bm__.get(record.__bm_handle__);
- const form = legacyRecord.fieldsInfo.form;
- views = form && form[name].views;
- } else {
- legacyRecord = mapRecordDatapoint(record);
- }
- const options = {
- attrs: {
- ...fieldInfo.rawAttrs,
- modifiers,
- options: fieldInfo.options,
- widget: fieldInfo.widget,
- views,
- mode: fieldInfo.viewMode,
- },
- viewType: legacyRecord.viewType,
- mode: this.props.readonly || hasReadonlyModifier ? "readonly" : record.mode,
- hasReadonlyModifier,
- };
- return { name, record: legacyRecord, options };
- }
-
- update(fieldName, value) {
- if (fieldName === this.props.name) {
- const record = this.props.record;
- const fieldType = record.fields[fieldName].type;
- if (["one2many", "many2many"].includes(fieldType) && !record.model.__bm__) {
- const staticList = this.props.value;
- switch (value.operation) {
- case "REPLACE_WITH": {
- return staticList.replaceWith(value.resIds);
- }
- case "FORGET": {
- return staticList.delete(value.ids);
- }
- }
- }
- return this.props.update(value);
- } else {
- return this.props.record.update({ [fieldName]: value });
- }
- }
- }
- LegacyField.template = legacyFieldTemplate;
- LegacyField.components = { FieldAdapter };
- LegacyField.legacySpecialData = LegacyFieldWidget.prototype.specialData;
- LegacyField.fieldsToFetch = LegacyFieldWidget.prototype.fieldsToFetch || {};
- LegacyField.fieldDependencies = LegacyFieldWidget.prototype.fieldDependencies || {};
- LegacyField.useSubView = LegacyFieldWidget.prototype.useSubview;
- LegacyField.noLabel = LegacyFieldWidget.prototype.noLabel || false;
- if (!fieldRegistry.contains(name)) {
- if (odoo.debug) {
- console.log(`Fields: using legacy ${name} FieldWidget`);
- }
- fieldRegistry.add(name, LegacyField);
- }
-}
-
-// register fields already in the legacy registry, and listens to future registrations
-for (const [name, FieldWidget] of Object.entries(legacyFieldRegistry.entries())) {
- registerField(name, FieldWidget);
-}
-legacyFieldRegistry.onAdd(registerField);
diff --git a/addons/web/static/src/legacy/legacy_fields.scss b/addons/web/static/src/legacy/legacy_fields.scss
deleted file mode 100644
index ccf7e5f80f9..00000000000
--- a/addons/web/static/src/legacy/legacy_fields.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.o_debug {
- .o_form_view, .o_list_view, .o_kanban_view {
- .o_legacy_field_widget > * {
- background-color: rgba(255, 0, 0, 0.1);
- }
- }
-}
diff --git a/addons/web/static/src/legacy/legacy_view_widgets.js b/addons/web/static/src/legacy/legacy_view_widgets.js
deleted file mode 100644
index c4f12d7338c..00000000000
--- a/addons/web/static/src/legacy/legacy_view_widgets.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/** @odoo-module **/
-
-import { registry } from "@web/core/registry";
-import { ComponentAdapter } from "web.OwlCompatibility";
-import legacyWidgetRegistry from "web.widget_registry";
-import { mapRecordDatapoint } from "./legacy_fields";
-
-const { Component, useEffect, xml } = owl;
-const viewWidgetRegistry = registry.category("view_widgets");
-
-const legacyWidgetTemplate = xml`
- `;
-
-// ----------------------------------------------------------------------------
-// ViewWidgetAdapter
-// ----------------------------------------------------------------------------
-
-class ViewWidgetAdapter extends ComponentAdapter {
- setup() {
- super.setup();
- this.wowlEnv = this.env;
- this.env = Component.env;
- useEffect(() => {
- this.widgetEl.parentElement.classList.remove("o_text_overflow");
- this.widgetEl.classList.add("o_legacy_widget");
- });
- }
-
- /**
- * @override
- */
- get widgetArgs() {
- return this.getParams(this.props);
- }
-
- getParams(props) {
- const { record, node, options, readonly } = props.viewWidgetParams;
- return [record, node, { mode: readonly ? "readonly" : "edit", ...options }];
- }
-
- updateWidget(nextProps) {
- if (this.oldWidget) {
- this.widget.destroy(); // we were already updating -> abort, and start over
- } else {
- this.oldWidget = this.widget;
- }
- this.widget = new this.props.Component(this, ...this.getParams(nextProps));
- return this.widget._widgetRenderAndInsert(() => {});
- }
-
- renderWidget() {
- if (this.oldWidget) {
- const parentEl = this.oldWidget.el.parentElement;
- parentEl.replaceChild(this.widget.el, this.oldWidget.el);
- this.widgetEl = this.widget.el;
- if (this.widget.on_attach_callback) {
- this.widget.on_attach_callback();
- }
- this.oldWidget.destroy();
- this.oldWidget = null;
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-// Register legacy widgets to the wowl widget registry (wrapped in a Component)
-// ----------------------------------------------------------------------------
-
-function registerWidget(name, LegacyWidgetWidget) {
- class LegacyViewWidget extends Component {
- setup() {
- this.ViewWidget = LegacyWidgetWidget;
- }
- get viewWidgetParams() {
- const { record } = this.props;
- let legacyRecord;
- if (record.model.__bm__) {
- legacyRecord = record.model.__bm__.get(record.__bm_handle__);
- } else {
- legacyRecord = mapRecordDatapoint(record);
- }
- const options = {
- viewType: legacyRecord.viewType,
- mode: record.mode,
- };
- return { ...this.props, record: legacyRecord, options };
- }
- }
- LegacyViewWidget.template = legacyWidgetTemplate;
- LegacyViewWidget.components = { ViewWidgetAdapter };
- if (!viewWidgetRegistry.contains(name)) {
- if (odoo.debug) {
- console.log(`View widgets: using legacy ${name} Widget`);
- }
- viewWidgetRegistry.add(name, LegacyViewWidget);
- }
-}
-
-// register widgets already in the legacy registry, and listens to future registrations
-for (const [name, Widget] of Object.entries(legacyWidgetRegistry.entries())) {
- registerWidget(name, Widget);
-}
-legacyWidgetRegistry.onAdd(registerWidget);
diff --git a/addons/web/static/src/legacy/scss/views.scss b/addons/web/static/src/legacy/scss/views.scss
index 943f6ed0e70..67a2070ee35 100644
--- a/addons/web/static/src/legacy/scss/views.scss
+++ b/addons/web/static/src/legacy/scss/views.scss
@@ -3,12 +3,6 @@
* all renderers. For field default rules, see the fields.scss file.
*/
-.o_debug .o_legacy_form_view,
-.o_debug .o_legacy_kanban_view,
-.o_debug .o_legacy_list_view {
- border-top: 3px solid red;
-}
-
// Invisible modifier (can be inside the view, the button area, ...)
.o_invisible_modifier {
display: none!important;
diff --git a/addons/web/static/src/views/fields/field_tooltip.js b/addons/web/static/src/views/fields/field_tooltip.js
index 9f62ebe4bba..439b4433ac4 100644
--- a/addons/web/static/src/views/fields/field_tooltip.js
+++ b/addons/web/static/src/views/fields/field_tooltip.js
@@ -1,16 +1,9 @@
/** @odoo-module **/
-import fieldRegistry from "web.field_registry";
-
export function getTooltipInfo(params) {
let widgetDescription = undefined;
if (params.fieldInfo.widget) {
- if (params.fieldInfo.FieldComponent.name === "LegacyField") {
- const widget = fieldRegistry.get(params.fieldInfo.widget);
- widgetDescription = widget.prototype.description;
- } else {
- widgetDescription = params.fieldInfo.FieldComponent.displayName;
- }
+ widgetDescription = params.fieldInfo.FieldComponent.displayName;
}
const info = {
diff --git a/addons/web/static/tests/views/fields/many2many_field_tests.js b/addons/web/static/tests/views/fields/many2many_field_tests.js
index bf30b81c06c..172d32bbe54 100644
--- a/addons/web/static/tests/views/fields/many2many_field_tests.js
+++ b/addons/web/static/tests/views/fields/many2many_field_tests.js
@@ -20,9 +20,6 @@ import { session } from "@web/session";
import { companyService } from "@web/webclient/company_service";
import { registry } from "@web/core/registry";
-import legacyFieldRegistry from "web.field_registry";
-import { FieldMany2ManyTags } from "web.relational_fields";
-
let target;
let serverData;
@@ -2123,40 +2120,4 @@ QUnit.module("Fields", (hooks) => {
);
}
);
-
- QUnit.test("many2many legacy field in list add a record", async (assert) => {
- const myM2M = FieldMany2ManyTags.extend({});
- legacyFieldRegistry.add("many2many_tags_legacy", myM2M);
-
- await makeView({
- type: "list",
- resModel: "partner",
- serverData,
- arch: `
-
-
- `,
- mockRPC(route, args) {
- if (args.method === "write") {
- assert.step(`write: ${JSON.stringify(args.args[1])}`);
- }
- },
- });
-
- assert.containsNone(target, ".o_badge_text");
- await click(target.querySelectorAll(".o_data_cell")[0]);
- await click(target, ".o_legacy_field_widget input");
- await click(document.querySelectorAll(".ui-autocomplete .dropdown-item")[0]);
-
- assert.strictEqual(target.querySelector(".o_badge_text").textContent, "gold");
- await click(target);
- assert.verifySteps([`write: {"timmy":[[6,false,[12]]]}`]);
-
- await click(target.querySelectorAll(".o_data_cell")[0]);
- await click(target.querySelector(".badge .o_delete"));
- await click(target);
- assert.containsNone(target, ".o_badge_text");
- assert.verifySteps([`write: {"timmy":[[6,false,[]]]}`]);
- delete legacyFieldRegistry.map["many2many_tags_legacy"];
- });
});
diff --git a/addons/web/static/tests/views/fields/one2many_field_tests.js b/addons/web/static/tests/views/fields/one2many_field_tests.js
index 28e3a403fa8..3371cc8e7b8 100644
--- a/addons/web/static/tests/views/fields/one2many_field_tests.js
+++ b/addons/web/static/tests/views/fields/one2many_field_tests.js
@@ -1,6 +1,5 @@
/** @odoo-module **/
-import AbstractField from "web.AbstractField";
import {
addRow,
click,
@@ -26,9 +25,7 @@ import {
import BasicModel from "web.BasicModel";
import { browser } from "@web/core/browser/browser";
import { createWebClient, doAction } from "@web/../tests/webclient/helpers";
-import { FieldOne2Many } from "web.relational_fields";
import { getNextTabableElement } from "@web/core/utils/ui";
-import fieldRegistry from "web.field_registry";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
import { registerCleanup } from "@web/../tests/helpers/cleanup";
import { registry } from "@web/core/registry";
@@ -5504,138 +5501,6 @@ QUnit.module("Fields", (hooks) => {
await click(target, ".oe_kanban_action_button");
});
- QUnit.test(
- "one2many kanban with edit type action and widget with specialData",
- async function (assert) {
- assert.expect(3);
-
- patchWithCleanup(BasicModel.prototype, {
- _fetchSpecialDataForMyWidget() {
- assert.step("_fetchSpecialDataForMyWidget");
- return Promise.resolve();
- },
- });
- const MyWidget = AbstractField.extend({
- specialData: "_fetchSpecialDataForMyWidget",
- className: "my_widget",
- });
- fieldRegistry.add("specialWidget", MyWidget);
-
- await makeView({
- type: "form",
- resModel: "partner",
- serverData,
- // turtle_int is displayed without widget in the kanban, and with
- // widget required specialData in the form
- arch: `
-
`,
- resId: 1,
- });
-
- await click(target.querySelector(".oe_kanban_action"));
- assert.containsOnce(target, ".modal .my_widget");
- assert.verifySteps(["_fetchSpecialDataForMyWidget"]);
- }
- );
-
- QUnit.test("one2many list with onchange and widget using SpecialData", async function (assert) {
- patchWithCleanup(BasicModel.prototype, {
- _fetchSpecialDataForMyWidget() {
- assert.step("_fetchSpecialDataForMyWidget");
- return Promise.resolve();
- },
- });
- const MyWidget = AbstractField.extend({
- specialData: "_fetchSpecialDataForMyWidget",
- className: "my_widget",
- });
- fieldRegistry.add("specialWidget", MyWidget);
-
- serverData.models.partner.onchanges = {
- turtles: function (obj) {
- var virtualID = obj.turtles[1][1];
- obj.turtles = [
- [5], // delete all
- [
- 0,
- virtualID,
- {
- display_name: "coucou",
- product_id: [37, "xphone"],
- turtle_bar: false,
- turtle_foo: "has changed",
- turtle_int: 42,
- turtle_qux: 9.8,
- partner_ids: [],
- turtle_ref: "product,37",
- },
- ],
- ];
- },
- };
- await makeView({
- type: "form",
- resModel: "partner",
- serverData,
- // turtle_int is displayed without widget in the list, and with
- // widget required specialData in the form
- arch: `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
`,
- resId: 1,
- });
-
- await addRow(target, ".o_field_one2many");
- assert.containsOnce(target, ".modal");
- await click(target.querySelector(".modal-footer button"));
-
- assert.deepEqual(
- [...target.querySelectorAll(".o_field_one2many tbody tr .o_data_cell")].map(
- (el) => el.innerText
- ),
- ["coucou", "has changed", "42"],
- "the onchange should create one new record and remove the existing"
- );
-
- await click(target.querySelector(".o_field_one2many .o_list_renderer tbody tr td"));
-
- await clickSave(target.querySelector(".modal"));
- assert.verifySteps(["_fetchSpecialDataForMyWidget"], "should only fetch special data once");
- });
-
QUnit.test("one2many without inline tree arch", async function (assert) {
serverData.models.partner.records[0].turtles = [2, 3];
serverData.views = {
@@ -10590,46 +10455,6 @@ QUnit.module("Fields", (hooks) => {
await clickSave(target);
});
- QUnit.test(
- "one2many: internal state is updated after another field changes",
- async function (assert) {
- // The FieldOne2Many is configured such that it is reset at any field change.
- // The MatrixProductConfigurator feature relies on that, and requires that its
- // internal state is correctly updated. This white-box test artificially checks that.
- let o2m;
- // keep using the legacy version considering the above comment
- const MyFieldOne2Many = FieldOne2Many.extend({
- init() {
- this._super(...arguments);
- o2m = this;
- },
- });
- fieldRegistry.add("myone2many", MyFieldOne2Many);
- registerCleanup(() => {
- delete fieldRegistry.map.myone2many;
- });
-
- await makeView({
- type: "form",
- resModel: "partner",
- serverData,
- arch: `
-
-
-
-
-
-
`,
- });
-
- assert.strictEqual(o2m.recordData.display_name, false);
-
- await editInput(target, ".o_field_widget[name=display_name] input", "val");
-
- assert.strictEqual(o2m.recordData.display_name, "val");
- }
- );
-
QUnit.test("nested one2many, onchange, no command value", async function (assert) {
// This test ensures that we always send all values to onchange rpcs for nested
// one2manys, even if some field hasn't changed. In this particular test case,
@@ -10695,84 +10520,6 @@ QUnit.module("Fields", (hooks) => {
await click(target.querySelector(".o_data_row .o_field_boolean input"));
});
- QUnit.test("update a one2many from a custom field widget", async function (assert) {
- // In this test, we define a custom field widget to render/update a one2many
- // field. For the update part, we ensure that updating primitive fields of a sub
- // record works. There is no guarantee that updating a relational field on the sub
- // record would work. Deleting a sub record works as well. However, creating sub
- // records isn't supported. There are obviously a lot of limitations, but the code
- // hasn't been designed to support all this. This test simply encodes what can be
- // done, and this comment explains what can't (and won't be implemented in stable
- // versions).
- serverData.models.partner.records[0].p = [1, 2];
- const MyRelationalField = AbstractField.extend({
- events: {
- "click .update": "_onUpdate",
- "click .delete": "_onDelete",
- },
- async _render() {
- const records = await this._rpc({
- method: "read",
- model: "partner",
- args: [this.value.res_ids],
- });
- this.$el.text(records.map((r) => `${r.display_name}/${r.int_field}`).join(", "));
- this.$el.append($('