diff --git a/addons/mail/__manifest__.py b/addons/mail/__manifest__.py index 90420e4e42d..ca90aaf7903 100644 --- a/addons/mail/__manifest__.py +++ b/addons/mail/__manifest__.py @@ -179,9 +179,7 @@ For more specific needs, you may also assign custom-defined actions 'web/static/src/legacy/js/core/misc.js', 'web/static/src/legacy/js/env.js', 'web/static/src/legacy/js/owl_compatibility.js', - 'web/static/src/legacy/js/services/data_manager.js', 'web/static/src/legacy/js/services/session.js', - 'web/static/src/legacy/legacy_load_views.js', 'web/static/src/legacy/utils.js', 'mail/static/src/core/common/**/*', diff --git a/addons/mrp_subcontracting/__manifest__.py b/addons/mrp_subcontracting/__manifest__.py index 444f8864b86..c8b1d42b070 100644 --- a/addons/mrp_subcontracting/__manifest__.py +++ b/addons/mrp_subcontracting/__manifest__.py @@ -91,7 +91,6 @@ 'web/static/src/legacy/legacy_service_provider.js', 'web/static/src/legacy/legacy_dialog.js', - 'web/static/src/legacy/legacy_load_views.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', @@ -109,7 +108,6 @@ 'web/static/src/legacy/js/fields/relational_fields.js', 'web/static/src/legacy/js/fields/field_registry.js', 'web/static/src/legacy/js/fields/field_utils.js', - 'web/static/src/legacy/js/services/data_manager.js', 'web/static/src/legacy/js/services/session.js', 'web/static/src/legacy/js/widgets/date_picker.js', 'web/static/src/legacy/js/env.js', diff --git a/addons/point_of_sale/__manifest__.py b/addons/point_of_sale/__manifest__.py index a312ffe5508..351ca106e87 100644 --- a/addons/point_of_sale/__manifest__.py +++ b/addons/point_of_sale/__manifest__.py @@ -157,7 +157,6 @@ ('remove', 'web/static/src/legacy/js/libs/**/*'), ('remove', 'web/static/src/legacy/js/public/**/*'), 'web/static/src/legacy/backend_utils.js', - 'web/static/src/legacy/legacy_load_views.js', 'web/static/src/legacy/legacy_service_provider.js', 'web/static/src/legacy/utils.js', 'web/static/src/search/**/*', diff --git a/addons/project/__manifest__.py b/addons/project/__manifest__.py index 7821814560d..143f9204470 100644 --- a/addons/project/__manifest__.py +++ b/addons/project/__manifest__.py @@ -142,7 +142,6 @@ 'web/static/src/legacy/legacy_service_provider.js', 'web/static/src/legacy/legacy_dialog.js', - 'web/static/src/legacy/legacy_load_views.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', @@ -161,7 +160,6 @@ 'web/static/src/legacy/js/fields/field_registry.js', 'web/static/src/legacy/js/fields/field_registration.js', 'web/static/src/legacy/js/fields/field_utils.js', - 'web/static/src/legacy/js/services/data_manager.js', 'web/static/src/legacy/js/services/session.js', 'web/static/src/legacy/js/widgets/date_picker.js', 'web/static/src/legacy/js/env.js', diff --git a/addons/web/__manifest__.py b/addons/web/__manifest__.py index 1fcd4710252..44e237e6d07 100644 --- a/addons/web/__manifest__.py +++ b/addons/web/__manifest__.py @@ -218,7 +218,6 @@ This module provides the core of the Odoo Web Client. 'web/static/src/legacy/legacy_service_provider.js', 'web/static/src/legacy/legacy_dialog.js', - 'web/static/src/legacy/legacy_load_views.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', @@ -229,7 +228,6 @@ This module provides the core of the Odoo Web Client. 'web/static/src/legacy/js/core/context.js', 'web/static/src/legacy/js/core/misc.js', 'web/static/src/legacy/js/fields/*', - 'web/static/src/legacy/js/services/data_manager.js', 'web/static/src/legacy/js/services/session.js', 'web/static/src/legacy/js/widgets/date_picker.js', 'web/static/src/legacy/js/env.js', diff --git a/addons/web/static/src/legacy/js/env.js b/addons/web/static/src/legacy/js/env.js index 1852735d27b..c4118acb3c3 100644 --- a/addons/web/static/src/legacy/js/env.js +++ b/addons/web/static/src/legacy/js/env.js @@ -5,10 +5,9 @@ */ import commonEnv from 'web.commonEnv'; -import dataManager from 'web.data_manager'; import { blockUI, unblockUI } from "web.framework"; -const env = Object.assign(commonEnv, { dataManager }); +const env = commonEnv; env.services = Object.assign(env.services, { blockUI, unblockUI }); export default env; diff --git a/addons/web/static/src/legacy/js/owl_compatibility.js b/addons/web/static/src/legacy/js/owl_compatibility.js index 96a1754a125..a5b64fcccdd 100644 --- a/addons/web/static/src/legacy/js/owl_compatibility.js +++ b/addons/web/static/src/legacy/js/owl_compatibility.js @@ -262,19 +262,6 @@ if (payload.callback) { payload.callback(this.env.session); } - } else if (evType === 'load_views') { - const params = { - model: payload.modelName, - context: payload.context, - views_descr: payload.views, - }; - this.env.dataManager - .load_views(params, payload.options || {}) - .then(payload.on_success); - } else if (evType === 'load_filters') { - return this.env.dataManager - .load_filters(payload) - .then(payload.on_success); } else { payload.__targetWidget = ev.target; this.trigger(evType.replace(/_/g, '-'), payload); diff --git a/addons/web/static/src/legacy/js/services/data_manager.js b/addons/web/static/src/legacy/js/services/data_manager.js deleted file mode 100644 index 2a07b3f16b2..00000000000 --- a/addons/web/static/src/legacy/js/services/data_manager.js +++ /dev/null @@ -1,226 +0,0 @@ -/** @odoo-module alias=web.data_manager **/ - -import config from "web.config"; -import core from "web.core"; -import rpc from "web.rpc"; -import session from "web.session"; -import { generateLegacyLoadViewsResult } from "@web/legacy/legacy_load_views"; - -const DataManager = core.Class.extend({ - init: function () { - this._init_cache(); - core.bus.on('clear_cache', this, this.invalidate.bind(this)); - }, - - _init_cache: function () { - this._cache = { - actions: {}, - filters: {}, - views: {}, - }; - }, - - /** - * Invalidates the whole cache. Only works when not triggered by itself. - * Suggestion: could be refined to invalidate some part of the cache - * - * @param {Object} [dataManager] - */ - invalidate: function (dataManager) { - if (dataManager === this) { - return; - } - session.invalidateCacheKey('load_menus'); - this._init_cache(); - }, - - /** - * Loads an action from its id or xmlid. - * - * @param {int|string} [action_id] the action id or xmlid - * @param {Object} [additional_context] used to load the action - * @return {Promise} resolved with the action whose id or xmlid is action_id - */ - load_action: function (action_id, additional_context) { - var self = this; - var key = this._gen_key(action_id, additional_context || {}); - - if (config.isDebug('assets') || !this._cache.actions[key]) { - this._cache.actions[key] = rpc.query({ - route: "/web/action/load", - params: { - action_id: action_id, - additional_context: additional_context, - }, - }).then(function (action) { - self._cache.actions[key] = action.no_cache ? null : self._cache.actions[key]; - return action; - }).guardedCatch(() => this._invalidate('actions', key)); - } - - return this._cache.actions[key].then(function (action) { - return $.extend(true, {}, action); - }); - }, - - /** - * Loads various information concerning views: fields_view for each view, - * the fields of the corresponding model, and optionally the filters. - * - * @param {Object} params - * @param {String} params.model - * @param {Object} params.context - * @param {Array} params.views_descr array of [view_id, view_type] - * @param {Object} [options={}] dictionary of various options: - * - options.load_filters: whether or not to load the filters, - * - options.action_id: the action_id (required to load filters), - * - options.toolbar: whether or not a toolbar will be displayed, - * @return {Promise} resolved with the requested views information - */ - load_views: async function ({ model, context, views_descr } , options = {}) { - const viewsKey = this._gen_key(model, views_descr, options, context); - const filtersKey = this._gen_key(model, options.action_id); - const withFilters = Boolean(options.load_filters); - const shouldLoadViews = config.isDebug('assets') || !this._cache.views[viewsKey]; - const shouldLoadFilters = config.isDebug('assets') || ( - withFilters && !this._cache.filters[filtersKey] - ); - if (shouldLoadViews) { - // Views info should be loaded - options.load_filters = shouldLoadFilters; - if (config.device.isMobile) { - options.mobile = config.device.isMobile; - } - this._cache.views[viewsKey] = rpc.query({ - args: [], - kwargs: { context, options, views: views_descr }, - model, - method: 'get_views', - }).then(result => { - const { models, views } = result; - result = generateLegacyLoadViewsResult(model, views, models); - // Freeze the fields dict as it will be shared between views and - // no one should edit it - // utils.deepFreeze(result.fields); // OWL issue regarding proxies and frozen objects https://github.com/odoo/owl/issues/1158 - for (const [ /* viewId */ , viewType] of views_descr) { - const fvg = result.fields_views[viewType]; - fvg.viewFields = fvg.fields; - fvg.fields = result.fields; - } - - // Insert filters, if any, into the filters cache - if (shouldLoadFilters) { - this._cache.filters[filtersKey] = Promise.resolve(result.filters); - } - return result.fields_views; - }).guardedCatch(() => this._invalidate('views', viewsKey)); - } - const result = await this._cache.views[viewsKey]; - if (withFilters && result.search) { - if (shouldLoadFilters) { - await this.load_filters({ - actionId: options.action_id, - context, - forceReload: false, - modelName: model, - }); - } - result.search.favoriteFilters = await this._cache.filters[filtersKey]; - } - return result; - }, - - /** - * Loads the filters of a given model and optional action id. - * - * @param {Object} params - * @param {number} params.actionId - * @param {Object} params.context - * @param {boolean} [params.forceReload=true] can be set to false to prevent forceReload - * @param {string} params.modelName - * @return {Promise} resolved with the requested filters - */ - load_filters: function (params) { - const key = this._gen_key(params.modelName, params.actionId); - const forceReload = params.forceReload !== false && config.isDebug('assets'); - if (forceReload || !this._cache.filters[key]) { - this._cache.filters[key] = rpc.query({ - args: [params.modelName, params.actionId], - kwargs: { - context: params.context || {}, - // get_context() de dataset - }, - model: 'ir.filters', - method: 'get_filters', - }).guardedCatch(() => this._invalidate('filters', key)); - } - return this._cache.filters[key]; - }, - - /** - * Calls 'create_or_replace' on 'ir_filters'. - * - * @param {Object} [filter] the filter description - * @return {Promise} resolved with the id of the created or replaced filter - */ - create_filter: function (filter) { - return rpc.query({ - args: [filter], - model: 'ir.filters', - method: 'create_or_replace', - }) - .then(filterId => { - const filtersKey = this._gen_key(filter.model_id, filter.action_id); - this._invalidate('filters', filtersKey); - return filterId; - }); - }, - - /** - * Calls 'unlink' on 'ir_filters'. - * - * @param {integer} filterId Id of the filter to remove - * @return {Promise} - */ - delete_filter: function (filterId) { - return rpc.query({ - args: [filterId], - model: 'ir.filters', - method: 'unlink', - }) - // Invalidate the whole cache since we have no idea where the filter came from. - .then(() => this._invalidate('filters')); - }, - - /** - * Private function that generates a cache key from its arguments - */ - _gen_key: function () { - return Array.prototype.slice.call(arguments).map((arg) => { - if (!arg) { - return false; - } - return typeof arg === "object" ? JSON.stringify(arg) : arg; - }).join(","); - }, - - /** - * Invalidate a cache entry or a whole cache section. - * - * @private - * @param {string} section - * @param {string} key - */ - _invalidate(section, key) { - core.bus.trigger("clear_cache", this); - if (key) { - delete this._cache[section][key]; - } else { - this._cache[section] = {}; - } - }, -}); - -var data_manager = new DataManager(); - -export default data_manager; diff --git a/addons/web/static/src/legacy/legacy_load_views.js b/addons/web/static/src/legacy/legacy_load_views.js deleted file mode 100644 index 10ad14784cc..00000000000 --- a/addons/web/static/src/legacy/legacy_load_views.js +++ /dev/null @@ -1,126 +0,0 @@ -/** @odoo-module **/ - -const xmlSerializer = new XMLSerializer(); -const domParser = new DOMParser(); - -function traverse(tree, f) { - if (f(tree)) { - Object.values(tree.children || {}).forEach((c) => { - traverse(c, f); - }); - } -} - -/** - * Given the result of a get_views, produces the equivalent of what was previously - * returned, such that legacy views continue working as before without any adaptations. - * - * @param {string} resModel - * @param {Object} views "views" key of the result of a get_views - * @param {Object} models maps of model name -> fields_get - * @returns {Object} similar to what was previously returned by load_views - */ -export function generateLegacyLoadViewsResult(resModel, views, models) { - const legacyFieldViews = { - fields: models[resModel], - fields_views: {}, - }; - if (views.search && views.search.filters) { - legacyFieldViews.filters = views.search.filters; - } - for (const viewType in views) { - const { arch, toolbar, id } = views[viewType]; - const { arch: processedArch, viewFields } = processArch(arch, viewType, resModel, models); - legacyFieldViews.fields_views[viewType] = { - arch: processedArch, - fields: viewFields, - model: resModel, - toolbar, - view_id: id, - }; - } - return legacyFieldViews; -} - -/** - * Given an arch with inline x2many subviews, generates the object of fields - * appearing in the arch, with a "views" key that contains the descriptions of - * their subviews (whose archs are removed from the main arch). - * - * @param {string} arch - * @param {string} viewType - * @param {string} resModel - * @param {Object} models - * @returns {Object} the processed arch and the (view) fields description - */ -export function processArch(arch, viewType, resModel, models) { - const viewFields = {}; - const archDoc = domParser.parseFromString(arch, "text/xml").documentElement; - traverse(archDoc, function (node) { - if (node.nodeType === 3) { - return false; - } - if (node.tagName === "field") { - const fieldName = node.getAttribute("name"); - if (viewFields[fieldName] === undefined) { - const viewFieldsInfo = models[resModel][fieldName]; - const nodeString = node.getAttribute("string"); - if (nodeString === null && viewFieldsInfo === undefined) { - throw new Error( - `Missing field string information for the field '${fieldName}' from the '${resModel}' model` - ); - } - viewFields[fieldName] = { - ...viewFieldsInfo, - string: nodeString || viewFieldsInfo.string, - views: {}, - }; - } - // extract subviews - // note: this should only be done for form views, because x2many subviews doesn't make - // any sense in any other view type, but sometimes in the codebase, people inline - // subviews in list views (e.g. sale.order.form.inherit.sale.product.configurator) so - // we remove them from the main arch anyway, to mock the previous behavior - if (viewType === "form" || viewType === "list") { - const coModel = models[resModel][fieldName].relation; - const views = {}; - for (const childNode of [...node.children]) { - const viewType = childNode.tagName === "tree" ? "list" : childNode.tagName; - const { arch: subViewArch, viewFields: subViewFields } = processArch( - xmlSerializer.serializeToString(childNode), - viewType, - coModel, - models - ); - views[viewType] = { arch: subViewArch, fields: subViewFields }; - node.removeChild(childNode); - } - viewFields[fieldName].views = views; - } - return false; - } - // list: extract groupby informations - if (viewType === "list" && node.tagName === "groupby" && node !== archDoc) { - const fieldName = node.getAttribute("name"); - const coModel = models[resModel][fieldName].relation; - const { arch: subViewArch, viewFields: subViewFields } = processArch( - xmlSerializer.serializeToString(node), - "groupby", - coModel, - models - ); - const groupbyView = { arch: subViewArch, fields: subViewFields }; - viewFields[fieldName] = viewFields[fieldName] || { - ...models[resModel][fieldName], - views: {}, - }; - viewFields[fieldName].views.groupby = groupbyView; - for (const child of [...node.children]) { - node.removeChild(child); - } - return false; - } - return true; - }); - return { arch: xmlSerializer.serializeToString(archDoc), viewFields }; -} diff --git a/addons/web/static/src/views/view_service.js b/addons/web/static/src/views/view_service.js index 3d36c9a5e6d..7a681c54e59 100644 --- a/addons/web/static/src/views/view_service.js +++ b/addons/web/static/src/views/view_service.js @@ -1,8 +1,6 @@ /** @odoo-module **/ -import { deepCopy } from "@web/core/utils/objects"; import { registry } from "@web/core/registry"; -import { generateLegacyLoadViewsResult } from "@web/legacy/legacy_load_views"; import { UPDATE_METHODS } from "@web/core/orm_service"; /** @@ -90,9 +88,7 @@ export const viewService = { .call(resModel, "get_views", [], { context, views, options: loadViewsOptions }) .then((result) => { const { models, views } = result; - const modelsCopy = deepCopy(models); // for legacy views const viewDescriptions = { - __legacy__: generateLegacyLoadViewsResult(resModel, views, modelsCopy), fields: models[resModel], relatedModels: models, views: {}, diff --git a/addons/web/static/tests/legacy/helpers/test_utils_mock.js b/addons/web/static/tests/legacy/helpers/test_utils_mock.js index fa2c0faa9cf..2059ec43286 100644 --- a/addons/web/static/tests/legacy/helpers/test_utils_mock.js +++ b/addons/web/static/tests/legacy/helpers/test_utils_mock.js @@ -42,7 +42,6 @@ const DebouncedField = basic_fields.DebouncedField; * @param {Bus} [params.bus] * @param {Object} [params.env] * @param {Bus} [params.env.bus] - * @param {Object} [params.env.dataManager] * @param {Object} [params.env.services] * @param {Object} [params.services] * @param {Object} [params.session] @@ -62,40 +61,6 @@ async function _getMockedOwlEnv(params, mockServer) { fetch: (resource, init) => mockServer.performFetch(resource, init), }, params.env.browser), bus: params.bus || params.env.bus || new Bus(), - dataManager: Object.assign({ - load_action: (actionID, context) => { - return mockServer.performRpc('/web/action/load', { - action_id: actionID, - additional_context: context, - }); - }, - load_views: (params, options) => { - return mockServer.performRpc('/web/dataset/call_kw/' + params.model, { - args: [], - kwargs: { - context: params.context, - options: options, - views: params.views_descr, - }, - method: 'get_views', - model: params.model, - }).then(function (views) { - views = Object.values(views).map((viewParams) => { - return getView(mockServer, viewParams); - }); - if (favoriteFilters && 'search' in views) { - views.search.favoriteFilters = favoriteFilters; - } - return views; - }); - }, - load_filters: params => { - if (debug) { - console.log('[mock] load_filters', params); - } - return Promise.resolve([]); - }, - }, params.env.dataManager), services: Object.assign(services, params.env.services), session: params.env.session || params.session || {}, }); @@ -495,30 +460,9 @@ async function addMockEnvironment(widget, params) { ev.data.callback(result); } }); - intercept(widget, 'load_action', async ev => { - const action = await env.dataManager.load_action(ev.data.actionID, ev.data.context); - ev.data.on_success(action); - }); - intercept(widget, "load_views", async ev => { - const params = { - model: ev.data.modelName, - context: ev.data.context, - views_descr: ev.data.views, - }; - const views = await env.dataManager.load_views(params, ev.data.options); - if ('search' in views && params.favoriteFilters) { - views.search.favoriteFilters = params.favoriteFilters; - } - ev.data.on_success(views); - }); intercept(widget, "get_session", ev => { ev.data.callback(session); }); - intercept(widget, "load_filters", async ev => { - const filters = await env.dataManager.load_filters(ev.data); - ev.data.on_success(filters); - }); - // make sure all other Odoo events bubbling up are intercepted Object.keys(params.intercepts || {}).forEach(function (name) { intercept(widget, name, params.intercepts[name]); diff --git a/addons/web/static/tests/webclient/helpers.js b/addons/web/static/tests/webclient/helpers.js index a5e7a84e5a0..5c3e3891aa5 100644 --- a/addons/web/static/tests/webclient/helpers.js +++ b/addons/web/static/tests/webclient/helpers.js @@ -12,7 +12,6 @@ import { makeLegacySessionService, } from "@web/legacy/utils"; import { makeLegacyActionManagerService } from "@web/legacy/backend_utils"; -import { generateLegacyLoadViewsResult } from "@web/legacy/legacy_load_views"; import { viewService } from "@web/views/view_service"; import { actionService } from "@web/webclient/actions/action_service"; import { effectService } from "@web/core/effects/effect_service"; @@ -112,48 +111,6 @@ export function setupWebClientRegistries() { */ export async function addLegacyMockEnvironment(env, legacyParams = {}) { // setup a legacy env - const dataManager = Object.assign( - { - load_action: (actionID, context) => { - return env.services.rpc("/web/action/load", { - action_id: actionID, - additional_context: context, - }); - }, - load_views: async (params, options) => { - let result = await env.services.rpc(`/web/dataset/call_kw/${params.model}`, { - args: [], - kwargs: { - context: params.context, - options: options, - views: params.views_descr, - }, - method: "get_views", - model: params.model, - }); - const { models, views: _views } = result; - result = generateLegacyLoadViewsResult(params.model, _views, models); - const views = result.fields_views; - for (const [, viewType] of params.views_descr) { - const fvg = views[viewType]; - fvg.viewFields = fvg.fields; - fvg.fields = result.fields; - } - if (params.favoriteFilters && "search" in views) { - views.search.favoriteFilters = params.favoriteFilters; - } - return views; - }, - load_filters: (params) => { - if (QUnit.config.debug) { - console.log("[mock] load_filters", params); - } - return Promise.resolve([]); - }, - }, - legacyParams.dataManager - ); - let localSession; if (legacyParams && legacyParams.getTZOffset) { patchWithCleanup(session, { @@ -162,7 +119,7 @@ export async function addLegacyMockEnvironment(env, legacyParams = {}) { localSession = { getTZOffset: legacyParams.getTZOffset }; } - const baseEnv = { dataManager, bus: core.bus, session: localSession }; + const baseEnv = { bus: core.bus, session: localSession }; const legacyEnv = makeTestEnvironment(Object.assign(baseEnv, legacyParams.env)); if (legacyParams.serviceRegistry) { diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js index f252714cedd..0a28de84d1d 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js @@ -2976,19 +2976,6 @@ export class Wysiwyg extends Component { if (payload.callback) { payload.callback(this.env.session); } - } else if (evType === 'load_views') { - const params = { - model: payload.modelName, - context: payload.context, - views_descr: payload.views, - }; - this.env.dataManager - .load_views(params, payload.options || {}) - .then(payload.on_success); - } else if (evType === 'load_filters') { - return this.env.dataManager - .load_filters(payload) - .then(payload.on_success); } } _callService(payload) {