[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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
});
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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'):
|
||||
|
||||
Reference in New Issue
Block a user