[REF] web: basicRelationalModel: factorize legacyUtilities

The mapping operations between the new RelationalModel API and the
BasicModel is now done in its own file

X-original-commit: 1202610ce6946ee4b2878e19e6ee6038edc9a71e
Part-of: odoo/odoo#102153
This commit is contained in:
Lucas Perais
2022-10-04 20:57:58 +02:00
parent 5cee846bb2
commit a02af5b259
2 changed files with 156 additions and 152 deletions
@@ -3,171 +3,25 @@
import { makeContext } from "@web/core/context";
import { Domain } from "@web/core/domain";
import { WarningDialog } from "@web/core/errors/error_dialogs";
import {
deserializeDate,
deserializeDateTime,
serializeDate,
serializeDateTime,
} from "@web/core/l10n/dates";
import { deserializeDate, deserializeDateTime } from "@web/core/l10n/dates";
import { KeepLast } from "@web/core/utils/concurrency";
import { escape } from "@web/core/utils/strings";
import { mapDoActionOptionAPI } from "@web/legacy/backend_utils";
import { Model } from "@web/views/model";
import { evalDomain } from "@web/views/utils";
import {
mapWowlValueToLegacy,
mapViews,
mapActiveFieldsToFieldsInfo,
} from "@web/views/legacy_utils";
import { localization } from "@web/core/l10n/localization";
import BasicModel from "web.BasicModel";
import Context from "web.Context";
import fieldRegistry from "web.field_registry";
import { parse } from "web.field_utils";
import { traverse } from "web.utils";
import { parseArch } from "web.viewUtils";
const { date: parseDate, datetime: parseDateTime } = parse;
const { markup, toRaw } = owl;
const DEFAULT_HANDLE_FIELD = "sequence";
function mapWowlValueToLegacy(value, type) {
switch (type) {
case "date":
// from luxon to moment
return value ? parseDate(serializeDate(value), null, { isUTC: true }) : false;
case "datetime":
// from luxon to moment
return value ? parseDateTime(serializeDateTime(value), null, { isUTC: true }) : false;
case "many2one":
return value ? { id: value[0], display_name: value[1] } : false;
case "reference":
return value
? { id: value.resId, display_name: value.displayName, model: value.resModel }
: false;
case "one2many":
case "many2many":
if (value.operation === "REPLACE_WITH") {
return { operation: "REPLACE_WITH", ids: value.resIds };
}
return value;
default:
return value;
}
}
function mapViews(views, env) {
const res = {};
for (const [viewType, viewDescr] of Object.entries(views || {})) {
const arch = parseArch(viewDescr.__rawArch);
traverse(arch, function (node) {
if (typeof node === "string") {
return false;
}
node.attrs.modifiers = node.attrs.modifiers ? JSON.parse(node.attrs.modifiers) : {};
return true;
});
// the basic model expects the former shape of load_views result, where we don't know
// all co-model fields, only those in the subview, so we filter the fields here
const fields = {};
for (const f in viewDescr.activeFields) {
fields[f] = viewDescr.fields[f];
}
res[viewType] = {
arch,
fields,
type: viewType,
fieldsInfo: mapActiveFieldsToFieldsInfo(viewDescr.activeFields, fields, viewType, env),
};
for (const fieldName in res[viewType].fieldsInfo[viewType]) {
if (!res[viewType].fields[fieldName]) {
res[viewType].fields[fieldName] = {
name: fieldName,
type: res[viewType].fieldsInfo[viewType][fieldName].type,
};
}
}
}
return res;
}
function mapActiveFieldsToFieldsInfo(activeFields, fields, viewType, env) {
const fieldsInfo = {};
fieldsInfo[viewType] = {};
for (const [fieldName, fieldDescr] of Object.entries(activeFields)) {
const views = mapViews(fieldDescr.views, env);
const field = fields[fieldName];
let Widget;
if (fieldDescr.widget) {
Widget = fieldRegistry.getAny([`${viewType}.${fieldDescr.widget}`, fieldDescr.widget]);
} else {
Widget = fieldRegistry.getAny([`${viewType}.${field.type}`, field.type]);
}
Widget = Widget || fieldRegistry.get("abstract");
let domain;
if (fieldDescr.domain) {
domain = fieldDescr.domain.toString();
}
let mode = fieldDescr.viewMode;
if (mode && mode.split(",").length !== 1) {
mode = env.isSmall ? "kanban" : "list";
}
const FieldComponent = fieldDescr.FieldComponent;
const fieldInfo = {
Widget, // remove this when we no longer support legacy fields inside wowl views
specialData: FieldComponent && FieldComponent.legacySpecialData,
domain,
context: fieldDescr.context,
fieldDependencies: {}, // ??
force_save: fieldDescr.forceSave,
mode,
modifiers: fieldDescr.modifiers,
name: fieldName,
options: fieldDescr.options,
views,
widget: fieldDescr.widget,
__WOWL_FIELD_DESCR__: fieldDescr,
};
if (FieldComponent && FieldComponent.limit) {
fieldInfo.limit = FieldComponent.limit;
}
if (fieldDescr.modifiers && fieldDescr.modifiers.invisible === true) {
fieldInfo.__no_fetch = true;
}
if (!fieldInfo.__no_fetch && FieldComponent && FieldComponent.fieldsToFetch) {
fieldInfo.relatedFields = { ...FieldComponent.fieldsToFetch };
fieldInfo.viewType = "default";
const defaultView = {};
for (const fieldName of Object.keys(FieldComponent.fieldsToFetch)) {
defaultView[fieldName] = {};
if (fieldDescr.fieldsToFetch[fieldName]) {
defaultView[fieldName].__WOWL_FIELD_DESCR__ =
fieldDescr.fieldsToFetch[fieldName];
}
}
fieldInfo.fieldsInfo = { default: defaultView };
const colorField = fieldInfo.options && fieldInfo.options.color_field;
if (colorField) {
fieldInfo.relatedFields[colorField] = { type: "integer" };
fieldInfo.fieldsInfo.default[colorField] = {};
if (fieldDescr.fieldsToFetch[colorField]) {
fieldInfo.fieldsInfo.default[colorField].__WOWL_FIELD_DESCR__ =
fieldDescr.fieldsToFetch[colorField];
}
}
}
if (fieldDescr.views && fieldDescr.views[fieldDescr.viewMode]) {
fieldInfo.limit = fieldDescr.views[fieldDescr.viewMode].limit || 40;
fieldInfo.orderedBy = fieldDescr.views[fieldDescr.viewMode].defaultOrder;
}
if (fieldDescr.onChange && !fields[fieldName].onChange) {
fields[fieldName].onChange = "1";
}
// FIXME? FieldWidget in kanban undefined
fieldsInfo[viewType][fieldName] = fieldInfo;
}
return fieldsInfo;
}
let nextId = 0;
class DataPoint {
/**
+150
View File
@@ -0,0 +1,150 @@
/** @odoo-module **/
import fieldRegistry from "web.field_registry";
import { parseArch } from "web.viewUtils";
import { parse } from "web.field_utils";
import { traverse } from "web.utils";
import { serializeDate, serializeDateTime } from "@web/core/l10n/dates";
const { date: parseDate, datetime: parseDateTime } = parse;
export function mapWowlValueToLegacy(value, type) {
switch (type) {
case "date":
// from luxon to moment
return value ? parseDate(serializeDate(value), null, { isUTC: true }) : false;
case "datetime":
// from luxon to moment
return value ? parseDateTime(serializeDateTime(value), null, { isUTC: true }) : false;
case "many2one":
return value ? { id: value[0], display_name: value[1] } : false;
case "reference":
return value
? { id: value.resId, display_name: value.displayName, model: value.resModel }
: false;
case "one2many":
case "many2many":
if (value.operation === "REPLACE_WITH") {
return { operation: "REPLACE_WITH", ids: value.resIds };
}
return value;
default:
return value;
}
}
export function mapViews(views, env) {
const res = {};
for (const [viewType, viewDescr] of Object.entries(views || {})) {
const arch = parseArch(viewDescr.__rawArch);
traverse(arch, function (node) {
if (typeof node === "string") {
return false;
}
node.attrs.modifiers = node.attrs.modifiers ? JSON.parse(node.attrs.modifiers) : {};
return true;
});
// the basic model expects the former shape of load_views result, where we don't know
// all co-model fields, only those in the subview, so we filter the fields here
const fields = {};
for (const f in viewDescr.activeFields) {
fields[f] = viewDescr.fields[f];
}
res[viewType] = {
arch,
fields,
type: viewType,
fieldsInfo: mapActiveFieldsToFieldsInfo(viewDescr.activeFields, fields, viewType, env),
};
for (const fieldName in res[viewType].fieldsInfo[viewType]) {
if (!res[viewType].fields[fieldName]) {
res[viewType].fields[fieldName] = {
name: fieldName,
type: res[viewType].fieldsInfo[viewType][fieldName].type,
};
}
}
}
return res;
}
export function mapActiveFieldsToFieldsInfo(activeFields, fields, viewType, env) {
const fieldsInfo = {};
fieldsInfo[viewType] = {};
for (const [fieldName, fieldDescr] of Object.entries(activeFields)) {
const views = mapViews(fieldDescr.views, env);
const field = fields[fieldName];
let Widget;
if (fieldDescr.widget) {
Widget = fieldRegistry.getAny([`${viewType}.${fieldDescr.widget}`, fieldDescr.widget]);
} else {
Widget = fieldRegistry.getAny([`${viewType}.${field.type}`, field.type]);
}
Widget = Widget || fieldRegistry.get("abstract");
let domain;
if (fieldDescr.domain) {
domain = fieldDescr.domain.toString();
}
let mode = fieldDescr.viewMode;
if (mode && mode.split(",").length !== 1) {
mode = env.isSmall ? "kanban" : "list";
}
const FieldComponent = fieldDescr.FieldComponent;
const fieldInfo = {
Widget, // remove this when we no longer support legacy fields inside wowl views
specialData: FieldComponent && FieldComponent.legacySpecialData,
domain,
context: fieldDescr.context,
fieldDependencies: {}, // ??
force_save: fieldDescr.forceSave,
mode,
modifiers: fieldDescr.modifiers,
name: fieldName,
options: fieldDescr.options,
views,
widget: fieldDescr.widget,
__WOWL_FIELD_DESCR__: fieldDescr,
};
if (FieldComponent && FieldComponent.limit) {
fieldInfo.limit = FieldComponent.limit;
}
if (fieldDescr.modifiers && fieldDescr.modifiers.invisible === true) {
fieldInfo.__no_fetch = true;
}
if (!fieldInfo.__no_fetch && FieldComponent && FieldComponent.fieldsToFetch) {
fieldInfo.relatedFields = { ...FieldComponent.fieldsToFetch };
fieldInfo.viewType = "default";
const defaultView = {};
for (const fieldName of Object.keys(FieldComponent.fieldsToFetch)) {
defaultView[fieldName] = {};
if (fieldDescr.fieldsToFetch[fieldName]) {
defaultView[fieldName].__WOWL_FIELD_DESCR__ =
fieldDescr.fieldsToFetch[fieldName];
}
}
fieldInfo.fieldsInfo = { default: defaultView };
const colorField = fieldInfo.options && fieldInfo.options.color_field;
if (colorField) {
fieldInfo.relatedFields[colorField] = { type: "integer" };
fieldInfo.fieldsInfo.default[colorField] = {};
if (fieldDescr.fieldsToFetch[colorField]) {
fieldInfo.fieldsInfo.default[colorField].__WOWL_FIELD_DESCR__ =
fieldDescr.fieldsToFetch[colorField];
}
}
}
if (fieldDescr.views && fieldDescr.views[fieldDescr.viewMode]) {
fieldInfo.limit = fieldDescr.views[fieldDescr.viewMode].limit || 40;
fieldInfo.orderedBy = fieldDescr.views[fieldDescr.viewMode].defaultOrder;
}
if (fieldDescr.onChange && !fields[fieldName].onChange) {
fields[fieldName].onChange = "1";
}
// FIXME? FieldWidget in kanban undefined
fieldsInfo[viewType][fieldName] = fieldInfo;
}
return fieldsInfo;
}