[IMP] move fetching of fields for import to javascript. Also extraction of required fields

bzr revid: xmo@openerp.com-20110923083341-xa3sg2t053zonlsm
This commit is contained in:
Xavier Morel 2011-09-23 10:33:41 +02:00
parent 6bd754060e
commit baf367d0e1
6 changed files with 178 additions and 18 deletions

View File

@ -19,6 +19,7 @@
"static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js",
"static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js",
"static/lib/jquery.ui.notify/js/jquery.notify.js",
"static/lib/jquery.deferred-queue/jquery.deferred-queue.js",
"static/lib/json/json2.js",
"static/lib/qweb/qweb2.js",
"static/lib/underscore/underscore.js",

View File

@ -1428,9 +1428,6 @@ class Import(View):
fields = req.session.model(model).fields_get(False, req.session.eval_context(req.context))
fields.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
required_fields = [field_name for field_name, field in fields.iteritems()
if field.get('required')]
def model_populate(fields, prefix_node='', prefix=None, prefix_value='', level=2):
def str_comp(x,y):
if x<y: return 1
@ -1459,9 +1456,6 @@ class Import(View):
fields.update({'id':{'string':'ID'},'.id':{'string':'Database ID'}})
model_populate(fields)
all_fields = _fields.keys()
all_fields.sort()
try:
data = csv.reader(csvfile, quotechar=str(csvdel), delimiter=str(csvsep))
except:
@ -1504,8 +1498,7 @@ class Import(View):
return '<script>window.top.%s(%s);</script>' % (
jsonp, simplejson.dumps({
'records':records[1:],'header':header_fields,
'all_fields':all_fields,'required_fields':required_fields}))
'records':records[1:],'header':header_fields}))
@openerpweb.httprequest
def import_data(self, req, model, csvfile, csvsep, csvdel, csvcode, csvskip,

View File

@ -0,0 +1,21 @@
Copyright 2011 Xavier Morel. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY XAVIER MOREL ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,59 @@
.. -*- restructuredtext -*-
In jQuery 1.5, jQuery has introduced a Deferred object in order to
better handle callbacks.
Along with Deferred, it introduced ``jQuery.when`` which allows, among
other things, for multiplexing deferreds (waiting on multiple
deferreds at the same time).
While this is very nice if all deferreds are available at the same
point, it doesn't really work if the resolution of a deferred can
generate more deferreds, or for collections of deferreds coming from
multiple sources (which may not be aware of one another).
Deferred.queue tries to be a solution to this. It is based on the
principle of FIFO multiple-producers multiple-consumers tasks queues,
such as Python's `queue.Queue`_. Any code with a reference to the
queue can add a promise to the queue, and the queue (which is a
promise itself) will only be resolved once all promises within are
resolved.
Quickstart
----------
Deferred.queue has a very simple life cycle: it is dormant when
created, it starts working as soon as promises get added to it (via
``.push``, or by providing them directly to its constructor), and as
soon as the last promise in the queue is resolved it resolves itself.
If any promise in the queue fails, the queue itself will be rejected
(without waiting for further promises).
Once a queue has been resolved or rejected, adding new promises to it
results in an error.
API
---
``jQuery.Deferred.queue([promises...])``
Creates a new deferred queue. Can be primed with a series of promise
objects.
``.push(promise...)``
Adds promises to the queue. Returns the queue itself (can be
chained).
If the queue has already been resolved or rejected, raises an error.
``.then([doneCallbacks][, failCallbacks])``
Promise/A ``then`` method.
``.done(doneCallbacks)``
jQuery ``done`` extension to promise objects
``.fail(failCallbacks)``
jQuery ``fail`` extension to promise objects
.. _queue.Queue:
http://docs.python.org/dev/library/queue.html

View File

@ -0,0 +1,34 @@
(function ($) {
"use strict";
$.extend($.Deferred, {
queue: function () {
var queueDeferred = $.Deferred();
var promises = 0;
function resolve() {
if (--promises > 0) {
return;
}
setTimeout($.proxy(queueDeferred, 'resolve'), 0);
}
var promise = $.extend(queueDeferred.promise(), {
push: function () {
if (this.isResolved() || this.isRejected()) {
throw new Error("Can not add promises to a resolved "
+ "or rejected promise queue");
}
promises += 1;
$.when.apply(null, arguments).then(
resolve, $.proxy(queueDeferred, 'reject'));
return this;
}
});
if (arguments.length) {
promise.push.apply(promise, arguments);
}
return promise;
}
});
})(jQuery)

View File

@ -23,11 +23,36 @@ function jsonp(form, attributes, callback) {
data: options
}, attributes));
}
openerp.web.DataImport = openerp.web.Dialog.extend({
template: 'ImportDataView',
dialog_title: "Import Data",
init: function(parent, dataset){
var self = this;
this._super(parent, {});
this.model = parent.model;
this.fields = [];
this.all_fields = [];
this.required_fields;
var convert_fields = function (root, prefix) {
prefix = prefix || '';
_(root.fields).each(function (f) {
var name = prefix + f.name;
self.all_fields.push(name);
if (f.fields) {
convert_fields(f, name + '/');
}
});
};
this.ready = $.Deferred.queue().then(function () {
self.required_fields = _(self.fields).chain()
.filter(function (field) { return field.required; })
.pluck('name')
.value();
convert_fields(self);
self.all_fields.sort();
});
},
start: function() {
var self = this;
@ -51,6 +76,35 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
this.$element.find('fieldset legend').click(function() {
$(this).next().toggle();
});
this.ready.push(new openerp.web.DataSet(this, this.model).call(
'fields_get', [], function (fields) {
self.graft_fields(fields);
}));
},
graft_fields: function (fields, parent, level) {
parent = parent || this;
level = level || 0;
var self = this;
_(fields).each(function (field, field_name) {
var f = {
name: field_name,
string: field.string,
required: field.required
};
if (field.type === 'one2many') {
f.fields = [];
// only fetch sub-fields to a depth of 2 levels
if (level < 2) {
self.ready.push(new openerp.web.DataSet(self, field.relation).call(
'fields_get', [], function (fields) {
self.graft_fields(fields, f, level+1);
}));
}
}
parent.fields.push(f);
});
},
toggle_import_button: function (newstate) {
this.$dialog.dialog('widget')
@ -89,15 +143,13 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
var self = this;
this.$element.find('.sel_fields').autocomplete({
minLength: 0,
source: results.all_fields,
change: function () {
self.on_check_field_values(results['required_fields']);
}
source: this.all_fields,
change: self.on_check_field_values
}).focus(function () {
$(this).autocomplete('search');
});
this.on_check_field_values(results['required_fields']);
this.on_check_field_values();
},
/**
* Looks through all the field selections, and tries to find if two
@ -134,10 +186,10 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
});
return duplicates;
},
on_check_field_values: function (required_fields) {
on_check_field_values: function () {
this.$element.find("#message, #msg").remove();
var required_valid = this.check_required(required_fields);
var required_valid = this.check_required();
var duplicates = this.find_duplicate_fields();
if (_.isEmpty(duplicates)) {
@ -156,15 +208,15 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
}
},
check_required: function(required_fields) {
if (!required_fields.length) { return true; }
check_required: function() {
if (!this.required_fields.length) { return true; }
var selected_fields = _(this.$element.find('.sel_fields').get()).chain()
.pluck('value')
.compact()
.value();
var missing_fields = _.difference(required_fields, selected_fields);
var missing_fields = _.difference(this.required_fields, selected_fields);
if (missing_fields.length) {
this.$element.find("#result").before('<div id="message" style="color:red">*Required Fields are not selected : ' + missing_fields + '.</div>');
return false;