[IMP] openerp,web: cache of actions, fields(_views) and filters

Introduction of 'data_manager' service which handles meta-data related to
actions and views (fields_views, fields and filters). Ideally, all RPCs to
get that kind of information should go through data_manager, as it holds an
internal cache.
This commit is contained in:
Aaron Bohy
2016-03-18 10:44:52 +01:00
parent bda451ab31
commit 6c57935443
18 changed files with 334 additions and 154 deletions
+2 -1
View File
@@ -5,6 +5,7 @@ var ControlPanel = require('web.ControlPanel');
var core = require('web.core');
var crash_manager = require('web.crash_manager');
var data = require('web.data');
var data_manager = require('web.data_manager');
var Dialog = require('web.Dialog');
var framework = require('web.framework');
var pyeval = require('web.pyeval');
@@ -564,7 +565,7 @@ var ActionManager = Widget.extend({
active_ids : options.additional_context.active_ids,
active_model : options.additional_context.active_model
};
return self.rpc("/web/action/load", { action_id: action, additional_context : additional_context }).then(function(result) {
return data_manager.load_action(action, additional_context).then(function(result) {
return self.do_action(result, options);
});
}
@@ -0,0 +1,226 @@
odoo.define('web.DataManager', function (require) {
"use strict";
var core = require('web.core');
var Model = require('web.DataModel');
var session = require('web.session');
var utils = require('web.utils');
return core.Class.extend({
init: function () {
this.Filters = new Model('ir.filters');
this._cache = {
actions: {},
fields_views: {},
fields: {},
filters: {},
views: {},
};
},
/**
* 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 {Deferred} 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 (!this._cache.actions[key]) {
this._cache.actions[key] = session.rpc("/web/action/load", {
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;
});
}
return this._cache.actions[key];
},
/**
* Loads various information concerning views: fields_view for each view,
* and optionally filters and fields.
*
* @param {Object} [dataset] the dataset for which the views are loaded
* @param {Array} [views_descr] array of [view_id, view_type]
* @param {Object} [options] dictionnary of various options:
* - options.load_filters: whether or not to load the filters,
* - options.action_id: the action_id (required to load filters),
* - options.load_fields: whether or not to load the fields,
* - options.toolbar: whether or not a toolbar will be displayed,
* @return {Deferred} resolved with the requested views information
*/
load_views: function (dataset, views_descr, options) {
var self = this;
var model = dataset.model;
var context = dataset.get_context();
var key = this._gen_key(model, views_descr, options || {}, context);
if (!this._cache.views[key]) {
// Don't load fields or filters if already in cache
options.load_fields = options.load_fields && !this._cache.fields[model];
var filters_key;
if (options.load_filters) {
filters_key = this._gen_key(model, options.action_id);
options.load_filters = !this._cache.filters[filters_key];
}
this._cache.views[key] = dataset.call('load_views', {
views: views_descr,
options: options,
context: context,
}).then(function (result) {
// Postprocess fields_views and insert them into the fields_views cache
result.fields_views = _.mapObject(result.fields_views, self._postprocess_fvg.bind(self)); // FIXME: lazy postprocess?
_.each(views_descr, function (view_descr) {
var toolbar = options.toolbar && view_descr[1] !== 'search';
var fv_key = self._gen_key(model, view_descr[0], view_descr[1], toolbar, context);
self._cache.fields_views[fv_key] = $.when(result.fields_views[view_descr[1]]);
});
// Insert filters, if any, into the filters cache
if (result.filters) {
self._cache.filters[filters_key] = $.when(result.filters);
}
// Insert fields, if any, into the fields cache
if (result.fields) {
self._cache.fields[model] = $.when(result.fields);
}
return result.fields_views;
});
}
return this._cache.views[key];
},
/**
* Loads the fields_view of a given model, view_type and optional view_id.
*
* @param {Object} [dataset] the dataset for which the fields_view is loaded
* @param {int} [view_id] the id of the view (optional)
* @param {string} [view_type] the type of the view
* @param {Boolean} [toolbar] whether or not a toolbar will be displayed
* @return {Deferred} resolved with the requested fields_view
*/
load_fields_view: function (dataset, view_id, view_type, toolbar) {
var key = this._gen_key(dataset.model, view_id, view_type, toolbar, dataset.get_context());
if (!this._cache.fields_views[key]) {
this._cache.fields_views[key] = dataset.call('fields_view_get', {
view_id: view_id,
view_type: view_type,
toolbar: toolbar,
context: dataset.get_context(),
}).then(this._postprocess_fvg.bind(this));
}
return this._cache.fields_views[key];
},
/**
* Loads the fields of a given model.
*
* @param {Object} [dataset] the dataset for which the fields are loaded
* @return {Deferred} resolved with the requested fields
*/
load_fields: function (dataset) {
if (!this._cache.fields[dataset.model]) {
this._cache.fields[dataset.model] = dataset.call('fields_get', {
context: dataset.get_context(),
});
}
return this._cache.fields[dataset.model];
},
/**
* Loads the filters of a given model and optional action id.
*
* @param {Object} [dataset] the dataset for which the filters are loaded
* @param {int} [action_id] the id of the action (optional)
* @return {Deferred} resolved with the requested filters
*/
load_filters: function (dataset, action_id) {
var key = this._gen_key(dataset.model, action_id);
if (!this._cache.filters[key]) {
this._cache.filters[key] = this.Filters.call('get_filters', [dataset.model, action_id], {
context: dataset.get_context(),
});
}
return this._cache.filters[key];
},
/**
* Calls 'create_or_replace' on 'ir_filters'.
*
* @param {Object} [filter] the filter description
* @return {Deferred} resolved with the id of the created or replaced filter
*/
create_filter: function (filter) {
var self = this;
return this.Filters
.call('create_or_replace', [filter])
.then(function (filter_id) {
var key = [
filter.model_id,
filter.action_id || false,
].join(',');
self._cache.filters[key] = null; // invalidate cache
return filter_id;
});
},
/**
* Calls 'unlink' on 'ir_filters'.
*
* @param {Object} [filter] the description of the filter to remove
* @return {Deferred}
*/
delete_filter: function (filter) {
var self = this;
return this.Filters
.call('unlink', [filter.id])
.then(function () {
self._cache.filters = {}; // invalidate cache
});
},
/**
* Private function that postprocesses fields_view (mainly parses the arch attribute)
*/
_postprocess_fvg: function (fields_view) {
var self = this;
var doc = $.parseXML(fields_view.arch).documentElement;
fields_view.arch = utils.xml_to_json(doc, (doc.nodeName.toLowerCase() !== 'kanban'));
if ('id' in fields_view.fields) {
// Special case for id's
var id_field = fields_view.fields.id;
id_field.original_type = id_field.type;
id_field.type = 'id';
}
_.each(fields_view.fields, function(field) {
_.each(field.views || {}, function(view) {
self._postprocess_fvg(view);
});
});
return fields_view;
},
/**
* Private function that generates a cache key from its arguments
*/
_gen_key: function () {
return _.map(Array.prototype.slice.call(arguments), function (arg) {
if (!arg) {
return false;
}
return _.isObject(arg) ? JSON.stringify(arg) : arg;
}).join(',');
},
});
});
@@ -3,7 +3,6 @@ odoo.define('web.Model', function (require) {
var Class = require('web.Class');
var session = require('web.session');
var utils = require('web.utils');
var Model = Class.extend({
/**
@@ -70,43 +69,6 @@ var Model = Class.extend({
signal: signal
});
},
/**
* Performs a fields_view_get and apply postprocessing.
* return a {$.Deferred} resolved with the fvg
*
* @param {Object} args
* @param {String|Object} args.model instance.web.Model instance or string repr of the model
* @param {Object} [args.context] context if args.model is a string
* @param {Number} [args.view_id] id of the view to be loaded, default view if null
* @param {String} [args.view_type] type of view to be loaded if view_id is null
* @param {Boolean} [args.toolbar=false] get the toolbar definition
*/
fields_view_get: function (options) {
return this.call('fields_view_get', {
view_id: options.view_id,
view_type: options.view_type,
context: options.context,
toolbar: options.toolbar || false
}).then(this.postprocess_fvg.bind(this));
},
postprocess_fvg: function (fvg) {
var self = this;
var doc = $.parseXML(fvg.arch).documentElement;
fvg.arch = utils.xml_to_json(doc, (doc.nodeName.toLowerCase() !== 'kanban'));
if ('id' in fvg.fields) {
// Special case for id's
var id_field = fvg.fields.id;
id_field.original_type = id_field.type;
id_field.type = 'id';
}
_.each(fvg.fields, function(field) {
_.each(field.views || {}, function(view) {
self.postprocess_fvg(view);
});
});
return fvg;
},
});
return Model;
+6 -4
View File
@@ -3,6 +3,7 @@ odoo.define('web.View', function (require) {
var core = require('web.core');
var data = require('web.data');
var data_manager = require('web.data_manager');
var pyeval = require('web.pyeval');
var Widget = require('web.Widget');
@@ -122,10 +123,11 @@ var View = Widget.extend({
core.bus.trigger('do_reload_needaction');
});
} else if (action_data.type=="action") {
return this.rpc('/web/action/load', {
action_id: action_data.name,
context: _.extend(pyeval.eval('context', context), {'active_model': dataset.model, 'active_ids': dataset.ids, 'active_id': record_id}),
}).then(handler);
return data_manager.load_action(action_data.name, _.extend(pyeval.eval('context', context), {
active_model: dataset.model,
active_ids: dataset.ids,
active_id: record_id
})).then(handler);
} else {
return dataset.exec_workflow(record_id, action_data.name).then(handler);
}
@@ -0,0 +1,10 @@
odoo.define('web.data_manager', function (require) {
"use strict";
var DataManager = require('web.DataManager');
var data_manager = new DataManager();
return data_manager;
});
+11 -28
View File
@@ -3,6 +3,7 @@ odoo.define('web.ViewManager', function (require) {
var ControlPanelMixin = require('web.ControlPanelMixin');
var core = require('web.core');
var data_manager = require('web.data_manager');
var framework = require('web.framework');
var Model = require('web.DataModel');
var pyeval = require('web.pyeval');
@@ -119,33 +120,24 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
views.push([view.view_id, view.type]);
}
});
var options = {
action_id: this.action.id,
load_fields: load_fields,
toolbar: this.flags.sidebar,
};
if (this.flags.search_view && !this.search_fields_view) {
options.load_filters = true;
var searchview_id = this.action.search_view_id && this.action.search_view_id[0];
views.push([searchview_id || false, 'search']);
}
var options = {
action_id: this.action.id,
load_fields: load_fields && !this.fields_get_def,
toolbar: this.flags.sidebar,
};
return this.dataset._model.call('load_views', {
views: views,
options: options,
context: this.dataset.get_context(),
}).then(function (result) {
_.each(result.fields_views, function (fields_view, view_type) {
return data_manager.load_views(this.dataset, views, options).then(function (fields_views) {
_.each(fields_views, function (fields_view, view_type) {
if (view_type === 'search') {
self.search_fields_view = self.dataset._model.postprocess_fvg(fields_view);
self.search_fields_view = fields_view;
} else {
self.views[view_type].fields_view = self.dataset._model.postprocess_fvg(fields_view);
self.views[view_type].fields_view = fields_view;
}
});
if (result.filters) {
self.search_filters = result.filters;
}
if (result.fields) {
self.fields_get_def = $.when(result.fields);
}
});
},
/**
@@ -158,14 +150,6 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
get_default_view: function() {
return this.views[this.flags.default_view || this.view_order[0].type];
},
get_fields: function() {
if (!this.fields_get_def) {
this.fields_get_def = this.dataset._model.call('fields_get', {
context: this.dataset.get_context()
});
}
return this.fields_get_def;
},
switch_mode: function(view_type, view_options) {
var self = this;
var view = this.views[view_type];
@@ -383,7 +367,6 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
$buttons: $("<div>"),
action: this.action,
search_defaults: search_defaults,
filters: this.search_filters,
};
// Instantiate the SearchView, but do not append it nor its buttons to the DOM as this will
// be done later, simultaneously to all other ControlPanel elements
+6 -14
View File
@@ -3,6 +3,7 @@ odoo.define('web.form_common', function (require) {
var core = require('web.core');
var data = require('web.data');
var data_manager = require('web.data_manager');
var Dialog = require('web.Dialog');
var ListView = require('web.ListView');
var pyeval = require('web.pyeval');
@@ -919,12 +920,7 @@ var FormViewDialog = ViewDialog.extend({
if (this.options.alternative_form_view) {
fields_view_def = $.when(this.options.alternative_form_view);
} else {
fields_view_def = this.dataset._model.fields_view_get({
view_id: this.options.view_id || false,
view_type: 'form',
context: this.dataset.get_context(),
toolbar: false,
});
fields_view_def = data_manager.load_fields_view(this.dataset, this.options.view_id, 'form', false);
}
fields_view_def.then(function (fields_view) {
self.view_form = new FormView(self, self.dataset, fields_view, options);
@@ -977,7 +973,6 @@ var SelectCreateDialog = ViewDialog.extend({
return this.create_edit_record();
}
var self = this;
var _super = this._super.bind(this);
this.init_dataset();
var context = pyeval.sync_eval_domains_and_contexts({
@@ -991,15 +986,12 @@ var SelectCreateDialog = ViewDialog.extend({
search_defaults[match[1]] = value_;
}
});
this.dataset._model.call('load_views', {
views: [[false, 'list'], [false, 'search']],
context: this.dataset.get_context(),
}).then(function (result) {
var fields_views = _.mapObject(result.fields_views, self.dataset._model.postprocess_fvg);
self.setup(search_defaults, fields_views).then(function (fragment) {
data_manager
.load_views(this.dataset, [[false, 'list'], [false, 'search']], {})
.then(this.setup.bind(this, search_defaults))
.then(function (fragment) {
_super().$el.append(fragment);
});
});
return this;
},
+3 -2
View File
@@ -5,6 +5,7 @@ odoo.define('web.GraphView', function (require) {
*---------------------------------------------------------*/
var core = require('web.core');
var data_manager = require('web.data_manager');
var GraphWidget = require('web.GraphWidget');
var View = require('web.View');
@@ -28,7 +29,7 @@ var GraphView = View.extend({
},
willStart: function () {
var self = this;
var load_fields = this.ViewManager.get_fields().then(this.prepare_fields.bind(this));
var fields_def = data_manager.load_fields(this.dataset).then(this.prepare_fields.bind(this));
this.fields_view.arch.children.forEach(function (field) {
var name = field.attrs.name;
if (field.attrs.interval) {
@@ -40,7 +41,7 @@ var GraphView = View.extend({
self.initial_groupbys.push(name);
}
});
return $.when(this._super(), load_fields);
return $.when(this._super(), fields_def);
},
/**
* Render the buttons according to the GraphView.buttons and
+4 -3
View File
@@ -6,6 +6,7 @@ odoo.define('web.PivotView', function (require) {
var core = require('web.core');
var crash_manager = require('web.crash_manager');
var data_manager = require('web.data_manager');
var formats = require('web.formats');
var framework = require('web.framework');
var Model = require('web.DataModel');
@@ -68,8 +69,8 @@ var PivotView = View.extend({
willStart: function () {
var self = this;
var load_fields = this.ViewManager.get_fields();
var load_xlwt = session.rpc('/web/pivot/check_xlwt').then(function(result) {
var fields_def = data_manager.load_fields(this.dataset);
var xlwt_def = session.rpc('/web/pivot/check_xlwt').then(function(result) {
self.xlwt_installed = result;
});
@@ -99,7 +100,7 @@ var PivotView = View.extend({
if ((!this.active_measures.length) || this.fields_view.arch.attrs.display_quantity) {
this.active_measures.push('__count__');
}
return $.when(load_fields, load_xlwt, this._super()).then(function (fields) {
return $.when(fields_def, xlwt_def, this._super()).then(function (fields) {
self.prepare_fields(fields);
// add active measures to the measure list. This is very rarely necessary, but it
// can be useful if one is working with a functional field non stored, but in a
@@ -68,7 +68,9 @@ var Input = Widget.extend( /** @lends instance.web.search.Input# */{
"get_domain not implemented for widget " + this.attrs.type);
},
load_attrs: function (attrs) {
attrs.modifiers = attrs.modifiers ? JSON.parse(attrs.modifiers) : {};
if (!_.isObject(attrs.modifiers)) {
attrs.modifiers = attrs.modifiers ? JSON.parse(attrs.modifiers) : {};
}
this.attrs = attrs;
},
/**
+19 -31
View File
@@ -2,7 +2,7 @@ odoo.define('web.FavoriteMenu', function (require) {
"use strict";
var core = require('web.core');
var Model = require('web.DataModel');
var data_manager = require('web.data_manager');
var pyeval = require('web.pyeval');
var session = require('web.session');
var Widget = require('web.Widget');
@@ -31,25 +31,9 @@ return Widget.extend({
this.searchview = parent;
this.query = query;
this.target_model = target_model;
this.model = new Model('ir.filters');
this.action_id = action_id;
if (filters) {
this.filters = {};
_.each(filters, this.add_filter.bind(this));
}
},
willStart: function () {
var self = this;
var def;
if (!this.filters) {
def = this.model.call('get_filters', [this.target_model, this.action_id], {
context: this.searchview.dataset.context,
}).then(function (filters) {
self.filters = {};
_.each(filters, self.add_filter.bind(self));
});
}
return $.when(def, this._super());
this.filters = {};
_.each(filters, this.add_filter.bind(this));
},
start: function () {
var self = this;
@@ -136,7 +120,7 @@ return Widget.extend({
is_default: default_filter,
action_id: this.action_id,
};
return this.model.call('create_or_replace', [filter]).done(function (id) {
return data_manager.create_filter(filter).done(function (id) {
filter.id = id;
self.toggle_save_menu(false);
self.$save_name.find('input').val('').prop('checked', false);
@@ -267,14 +251,16 @@ return Widget.extend({
if (!confirm(filter.user_id ? warning : global_warning)) {
return;
}
this.model.call('unlink', [filter.id]).done(function () {
$filter.remove();
delete self.$filters[key];
delete self.filters[key];
if (_.isEmpty(self.filters)) {
self.$divider.hide();
}
});
return data_manager
.delete_filter(filter)
.done(function () {
$filter.remove();
delete self.$filters[key];
delete self.filters[key];
if (_.isEmpty(self.filters)) {
self.$divider.hide();
}
});
},
});
@@ -283,6 +269,7 @@ return Widget.extend({
odoo.define('web.FilterMenu', function (require) {
"use strict";
var data_manager = require('web.data_manager');
var search_filters = require('web.search_filters');
var search_inputs = require('web.search_inputs');
var Widget = require('web.Widget');
@@ -327,7 +314,7 @@ return Widget.extend({
},
get_fields: function () {
if (!this._fields_def) {
this._fields_def = this.searchview.ViewManager.get_fields().then(function (data) {
this._fields_def = data_manager.load_fields(this.searchview.dataset).then(function (data) {
var fields = {
id: { string: 'ID', type: 'id', searchable: true }
};
@@ -399,9 +386,10 @@ return Widget.extend({
odoo.define('web.GroupByMenu', function (require) {
"use strict";
var Widget = require('web.Widget');
var core = require('web.core');
var data_manager = require('web.data_manager');
var search_inputs = require('web.search_inputs');
var Widget = require('web.Widget');
var QWeb = core.qweb;
@@ -436,7 +424,7 @@ return Widget.extend({
get_fields: function () {
var self = this;
if (!this._fields_def) {
this._fields_def = this.searchview.ViewManager.get_fields().then(function (fields) {
this._fields_def = data_manager.load_fields(this.searchview.dataset).then(function (fields) {
var groupable_types = ['many2one', 'char', 'boolean', 'selection', 'date', 'datetime'];
var filter_group_field = _.filter(fields, function(field, name) {
if (field.store && _.contains(groupable_types, field.type)) {
+13 -2
View File
@@ -3,6 +3,7 @@ odoo.define('web.SearchView', function (require) {
var AutoComplete = require('web.AutoComplete');
var core = require('web.core');
var data_manager = require('web.data_manager');
var FavoriteMenu = require('web.FavoriteMenu');
var FilterMenu = require('web.FilterMenu');
var GroupByMenu = require('web.GroupByMenu');
@@ -390,7 +391,17 @@ var SearchView = View.extend({
this.filter_menu = undefined;
this.groupby_menu = undefined;
this.favorite_menu = undefined;
},
},
willStart: function () {
var self = this;
var def;
if (!this.options.disable_favorites) {
def = data_manager.load_filters(this.dataset, this.action_id).then(function (filters) {
self.favorite_filters = filters;
});
}
return $.when(this._super(), def);
},
start: function() {
if (this.headless) {
this.do_hide();
@@ -417,7 +428,7 @@ var SearchView = View.extend({
menu_defs.push(this.groupby_menu.appendTo(this.$buttons));
}
if (!this.options.disable_favorites) {
this.favorite_menu = new FavoriteMenu(this, this.query, this.dataset.model, this.action_id, this.options.filters);
this.favorite_menu = new FavoriteMenu(this, this.query, this.dataset.model, this.action_id, this.favorite_filters);
menu_defs.push(this.favorite_menu.appendTo(this.$buttons));
}
}
+2 -2
View File
@@ -5,6 +5,7 @@ var ActionManager = require('web.ActionManager');
var core = require('web.core');
var crash_manager = require('web.crash_manager');
var data = require('web.data');
var data_manager = require('web.data_manager');
var framework = require('web.framework');
var Loading = require('web.Loading');
var Menu = require('web.Menu');
@@ -16,7 +17,6 @@ var UserMenu = require('web.UserMenu');
var utils = require('web.utils');
var Widget = require('web.Widget');
var QWeb = core.qweb;
var _t = core._t;
var WebClient = Widget.extend({
@@ -310,7 +310,7 @@ var WebClient = Widget.extend({
},
on_menu_action: function(options) {
var self = this;
return this.menu_dm.add(this.rpc("/web/action/load", { action_id: options.action_id }))
return this.menu_dm.add(data_manager.load_action(options.action_id))
.then(function (result) {
return self.action_mutex.exec(function() {
if (options.needaction) {
+11 -11
View File
@@ -171,7 +171,7 @@ odoo.define_section('editor', ['web.ListEditor'], function (test, mock) {
});
});
odoo.define_section('list.edition', ['web.data', 'web.ListView'], function (test, mock) {
odoo.define_section('list.edition', ['web.data', 'web.ListView', 'web.data_manager'], function (test, mock) {
function setup () {
var records = {};
@@ -198,7 +198,7 @@ odoo.define_section('list.edition', ['web.data', 'web.ListView'], function (test
});
}
test('newrecord', function (assert, data, ListView) {
test('newrecord', function (assert, data, ListView, data_manager) {
setup();
assert.expect(6);
var got_defaults = false;
@@ -213,7 +213,7 @@ odoo.define_section('list.edition', ['web.data', 'web.ListView'], function (test
});
var ds = new data.DataSetStatic(null, 'demo', null, [1]);
var fields_view = ds._model.postprocess_fvg({
var fields_view = data_manager._postprocess_fvg({
type: 'tree',
fields: {
a: {type: 'char', string: "A"},
@@ -247,7 +247,7 @@ odoo.define_section('list.edition', ['web.data', 'web.ListView'], function (test
});
});
odoo.define_section('list.edition.events', ['web.data', 'web.ListView'], function (test, mock) {
odoo.define_section('list.edition.events', ['web.data', 'web.ListView', 'web.data_manager'], function (test, mock) {
function fields_view_get () {
return {
type: 'tree',
@@ -265,7 +265,7 @@ odoo.define_section('list.edition.events', ['web.data', 'web.ListView'], functio
});
}
test('edition events',function (assert, data, ListView) {
test('edition events',function (assert, data, ListView, data_manager) {
setup();
assert.expect(4);
var ds = new data.DataSetStatic(null, 'demo', null, [1]);
@@ -273,7 +273,7 @@ odoo.define_section('list.edition.events', ['web.data', 'web.ListView'], functio
counter: 0,
onEvent: function (e) { this.counter++; }
};
var fields_view = ds._model.postprocess_fvg(fields_view_get());
var fields_view = data_manager._postprocess_fvg(fields_view_get());
var l = new ListView({}, ds, fields_view, {editable: 'top'});
l.on('edit:before edit:after', o, o.onEvent);
@@ -291,11 +291,11 @@ odoo.define_section('list.edition.events', ['web.data', 'web.ListView'], functio
});
});
test('edition events: cancelling', function (assert, data, ListView) {
test('edition events: cancelling', function (assert, data, ListView, data_manager) {
setup();
var edit_after = false;
var ds = new data.DataSetStatic(null, 'demo', null, [1]);
var fields_view = ds._model.postprocess_fvg(fields_view_get());
var fields_view = data_manager._postprocess_fvg(fields_view_get());
var l = new ListView({}, ds, fields_view, {editable: 'top'});
l.on('edit:before', {}, function (e) {
e.cancel = true;
@@ -320,9 +320,9 @@ odoo.define_section('list.edition.events', ['web.data', 'web.ListView'], functio
});
});
odoo.define_section('list.edition.onwrite', ['web.data', 'web.ListView'], function (test, mock) {
odoo.define_section('list.edition.onwrite', ['web.data', 'web.ListView', 'web.data_manager'], function (test, mock) {
test('record-to-read', function (assert, data, ListView) {
test('record-to-read', function (assert, data, ListView, data_manager) {
assert.expect(4);
mock.add('demo:onchange', function () {
@@ -347,7 +347,7 @@ odoo.define_section('list.edition.onwrite', ['web.data', 'web.ListView'], functi
mock.add('demo:on_write', function () { return [42]; });
var ds = new data.DataSetStatic(null, 'demo', null, []);
var fields_view = ds._model.postprocess_fvg({
var fields_view = data_manager._postprocess_fvg({
type: 'tree',
fields: {
a: {type: 'char', string: "A"}
+3 -3
View File
@@ -1,6 +1,6 @@
odoo.define_section('list.buttons', ['web.ListView', 'web.data'], function (test, mock) {
odoo.define_section('list.buttons', ['web.ListView', 'web.data', 'web.data_manager'], function (test, mock) {
test('record-deletion', function (assert, ListView, data) {
test('record-deletion', function (assert, ListView, data, data_manager) {
assert.expect(2);
mock.add('demo:read', function (args, kwargs) {
@@ -22,7 +22,7 @@ odoo.define_section('list.buttons', ['web.ListView', 'web.data'], function (test
var ds = new data.DataSetStatic(null, 'demo', null, [1, 2, 3]);
var fields_view = ds._model.postprocess_fvg({
var fields_view = data_manager._postprocess_fvg({
type: 'tree',
fields: {
a: {type: 'char', string: "A"}
+11 -13
View File
@@ -160,6 +160,7 @@ function makeSearchView (test, dummy_widget_attributes, defaults, options, raw_f
var core = test.deps['web.core'];
var search_inputs = test.deps['web.search_inputs'];
var data = test.deps['web.data'];
var data_manager = test.deps['web.data_manager'];
var SearchView = test.deps['web.SearchView'];
var mock = test.mock;
@@ -182,14 +183,11 @@ function makeSearchView (test, dummy_widget_attributes, defaults, options, raw_f
var mock_parent = {
getParent: function () { return null; },
get_fields: function () {
return dataset._model.call('fields_get', { context: dataset.get_context() });
},
};
options = _.defaults(options || {}, {$buttons: $('<div>')});
options.search_defaults = defaults;
var fields_view = dataset._model.postprocess_fvg(raw_fields_view || {
var fields_view = data_manager._postprocess_fvg(raw_fields_view || {
type: 'search',
fields: {
dummy: {type: 'char', string: "Dummy", searchable: true}
@@ -204,7 +202,7 @@ function makeSearchView (test, dummy_widget_attributes, defaults, options, raw_f
return view;
};
odoo.define_section('search.defaults', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data'], function (test, mock) {
odoo.define_section('search.defaults', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data', 'web.data_manager'], function (test, mock) {
test('calling', function (assert) {
assert.expect(2);
var defaults_called = false;
@@ -430,7 +428,7 @@ odoo.define_section('search.defaults', ['web.search_inputs', 'web.SearchView', '
});
odoo.define_section('search.completions', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data'], function (test, mock) {
odoo.define_section('search.completions', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data', 'web.data_manager'], function (test, mock) {
test('calling', function (assert) {
assert.expect(4);
@@ -850,7 +848,7 @@ odoo.define_section('search.completions', ['web.search_inputs', 'web.SearchView'
});
});
odoo.define_section('search.serialization', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data'], function (test, mock) {
odoo.define_section('search.serialization', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data', 'web.data_manager'], function (test, mock) {
test('No facet, no call', function (assert, search_inputs, SearchView, core) {
assert.expect(6);
@@ -1190,7 +1188,7 @@ odoo.define_section('search.serialization', ['web.search_inputs', 'web.SearchVie
});
});
odoo.define_section('search.serialization', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data'], function (test, mock) {
odoo.define_section('search.serialization', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data', 'web.data_manager'], function (test, mock) {
test('is-drawn', function (assert) {
assert.expect(3);
@@ -1209,7 +1207,7 @@ odoo.define_section('search.serialization', ['web.search_inputs', 'web.SearchVie
});
odoo.define_section('search.filters', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data'], function (test, mock) {
odoo.define_section('search.filters', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data', 'web.data_manager'], function (test, mock) {
function fields_view_get () {
// view with a single group of filters
return {
@@ -1317,9 +1315,9 @@ odoo.define_section('search.filters', ['web.search_inputs', 'web.SearchView', 'w
});
});
odoo.define_section('search.groupby', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data'], function (test, mock) {
odoo.define_section('search.groupby', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data', 'web.data_manager'], function (test, mock) {
test('basic', ['web.FavoriteMenu', 'web.FilterMenu', 'web.GroupByMenu'], function (assert, search_inputs, SearchView, core, data, FavoriteMenu, FilterMenu, GroupByMenu) {
test('basic', ['web.FavoriteMenu', 'web.FilterMenu', 'web.GroupByMenu'], function (assert, search_inputs, SearchView, core, data, data_manager, FavoriteMenu, FilterMenu, GroupByMenu) {
assert.expect(12);
var view = makeSearchView(this, {}, {}, {}, {
type: 'search',
@@ -1401,7 +1399,7 @@ odoo.define_section('search.groupby', ['web.search_inputs', 'web.SearchView', 'w
});
});
odoo.define_section('search.filters.saved', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data'], function (test, mock) {
odoo.define_section('search.filters.saved', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data', 'web.data_manager'], function (test, mock) {
test('checkboxing', function (assert) {
assert.expect(6);
@@ -1517,7 +1515,7 @@ odoo.define_section('search.filters.saved', ['web.search_inputs', 'web.SearchVie
});
});
odoo.define_section('search.advanced', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data'], function (test, mock) {
odoo.define_section('search.advanced', ['web.search_inputs', 'web.SearchView', 'web.core', 'web.data', 'web.data_manager'], function (test, mock) {
test('single-advanced', function (assert) {
assert.expect(6);
+2
View File
@@ -115,6 +115,8 @@
<script type="text/javascript" src="/web/static/src/js/framework/misc.js"></script>
<script type="text/javascript" src="/web/static/src/js/framework/session_instance.js"></script>
<script type="text/javascript" src="/web/static/src/js/framework/crash_manager.js"></script>
<script type="text/javascript" src="/web/static/src/js/framework/data_manager.js"></script>
<script type="text/javascript" src="/web/static/src/js/services/data_manager.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/change_password.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/debug_manager.js"></script>
<script type="text/javascript" src="/web/static/src/js/widgets/data_export.js"></script>
+2 -1
View File
@@ -1537,6 +1537,7 @@ class BaseModel(object):
:param views: list of [view_id, view_type]
:param options.toolbar: true to include contextual actions when loading fields_views
:param options.load_filters: true to return the model's filters
:param options.action_id: id of the action to get the filters
:param options.load_fields: true to load the model's fields
:return: dictionary with fields_views, filters and fields
@@ -1555,7 +1556,7 @@ class BaseModel(object):
for [v_id, v_type] in views
}
if 'search' in result['fields_views']:
if options.get('load_filters'):
result['filters'] = self.pool['ir.filters'].get_filters(cr, uid, self._name, options.get('action_id'), context=context)
if options.get('load_fields'):