Kunal Chavda (OpenERP) has proposed merging
lp:~openerp-dev/openerp-web/trunk-import-kch into lp:openerp-web.
Requested reviews:
OpenERP R&D Web Team (openerp-dev-web)
For more details, see:
https://code.launchpad.net/~openerp-dev/openerp-web/trunk-import-kch/+merge/74216
Add Import related functionality as par specification with some following
feature.
* The pop-up should closing after a successful import.
* User can select field from list of fields under header.
* If there is not select required field than disable import button so user
can not import file till user will select required field.
--
https://code.launchpad.net/~openerp-dev/openerp-web/trunk-import-kch/+merge/74216
Your team OpenERP R&D Team is subscribed to branch
lp:~openerp-dev/openerp-web/trunk-import-kch.
=== modified file 'addons/web/__openerp__.py'
--- addons/web/__openerp__.py 2011-09-05 13:44:57 +0000
+++ addons/web/__openerp__.py 2011-09-06 13:23:44 +0000
@@ -33,6 +33,7 @@
"static/src/js/views.js",
"static/src/js/data.js",
"static/src/js/data_export.js",
+ "static/src/js/data_import.js",
"static/src/js/form.js",
"static/src/js/list.js",
"static/src/js/list-editable.js",
@@ -45,5 +46,6 @@
"static/lib/jquery.ui.notify/css/ui.notify.css",
"static/src/css/base.css",
"static/src/css/data_export.css",
+ "static/src/css/data_import.css",
],
}
=== modified file 'addons/web/controllers/main.py'
--- addons/web/controllers/main.py 2011-09-06 11:57:54 +0000
+++ addons/web/controllers/main.py 2011-09-06 13:23:44 +0000
@@ -167,14 +167,14 @@
"grouping", "decimal_point", "thousands_sep"])
else:
lang_obj = None
-
+
if lang.count("_") > 0:
separator = "_"
else:
separator = "@"
langs = lang.split(separator)
langs = [separator.join(langs[:x]) for x in range(1, len(langs) + 1)]
-
+
transs = {}
for addon_name in mods:
transl = {"messages":[]}
@@ -241,7 +241,7 @@
password, db = operator.itemgetter(
'drop_pwd', 'drop_db')(
dict(map(operator.itemgetter('name', 'value'), fields)))
-
+
try:
return req.session.proxy("db").drop(password, db)
except xmlrpclib.Fault, e:
@@ -328,7 +328,7 @@
}
except Exception, e:
return {"error": e, "title": "Languages"}
-
+
@openerpweb.jsonrequest
def modules(self, req):
# TODO query server for installed web modules
@@ -707,7 +707,7 @@
args[domain_id] = d
if context_id and len(args) - 1 >= context_id:
args[context_id] = c
-
+
for i in xrange(len(args)):
if isinstance(args[i], web.common.nonliterals.BaseContext):
args[i] = req.session.eval_context(args[i])
@@ -937,7 +937,7 @@
if field.get('context'):
field["context"] = self.parse_domain(field["context"], req.session)
return {'fields': fields}
-
+
@openerpweb.jsonrequest
def get_filters(self, req, model):
Model = req.session.model("ir.filters")
@@ -946,7 +946,7 @@
filter["context"] = req.session.eval_context(self.parse_context(filter["context"], req.session))
filter["domain"] = req.session.eval_domain(self.parse_domain(filter["domain"], req.session))
return filters
-
+
@openerpweb.jsonrequest
def save_filter(self, req, model, name, context_to_save, domain):
Model = req.session.model("ir.filters")
@@ -1354,7 +1354,188 @@
report = report_srv.report_get(*args2)
if report["state"]:
break
+
time.sleep(_REPORT_POLLER_DELAY)
#TODO: ok now we've got the report, and so what?
return False
+
+class Import(View):
+ _cp_path = "/web/import"
+
+ def fields_get(self, req, model):
+ Model = req.session.model(model)
+ fields = Model.fields_get(False, req.session.eval_context(req.context))
+ return fields
+
+ @openerpweb.httprequest
+ def detect_data(self, req, **params):
+ import StringIO
+ _fields = {}
+ _fields_invert = {}
+ req_field = []
+ error = None
+ all_fields = []
+ fields = dict(req.session.model(params.get('model')).fields_get(False, req.session.eval_context(req.context)))
+ fields.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
+
+ for field in fields:
+ value = fields[field]
+ if (value.get('required',False) == True):
+ req_field.append(field)
+
+ def model_populate(fields, prefix_node='', prefix=None, prefix_value='', level=2):
+ def str_comp(x,y):
+ if x<y: return 1
+ elif x>y: return -1
+ else: return 0
+
+ fields_order = fields.keys()
+ fields_order.sort(lambda x,y: str_comp(fields[x].get('string', ''), fields[y].get('string', '')))
+ for field in fields_order:
+ if (fields[field].get('type','') not in ('reference',))\
+ and (not fields[field].get('readonly')\
+ or not dict(fields[field].get('states', {}).get(
+ 'draft', [('readonly', True)])).get('readonly',True)):
+
+ st_name = prefix_value+fields[field]['string'] or field
+ _fields[prefix_node+field] = st_name
+ _fields_invert[st_name] = prefix_node+field
+
+ if fields[field].get('type','')=='one2many' and level>0:
+ fields2 = self.fields_get(req, fields[field]['relation'])
+ model_populate(fields2, prefix_node+field+'/', None, st_name+'/', level-1)
+
+ if fields[field].get('relation',False) and level>0:
+ model_populate({'/id': {'type': 'char', 'string': 'ID'}, '.id': {'type': 'char', 'string': 'Database ID'}},
+ prefix_node+field, None, st_name+'/', level-1)
+ fields.update({'id':{'string':'ID'},'.id':{'string':'Database ID'}})
+ model_populate(fields)
+ all_fields = fields.keys()
+
+ try:
+ data = csv.reader(params.get('csvfile'), quotechar=str(params.get('csvdel')), delimiter=str(params.get('csvsep')))
+ except:
+ error={'message': 'error opening .CSV file. Input Error.'}
+ return simplejson.dumps({'error':error})
+
+ records = []
+ fields = []
+ word=''
+ limit = 4
+ count = 0
+ try:
+ for i, row in enumerate(data):
+ records.append(row)
+ if i == limit:
+ break
+
+ for j, line in enumerate(records):
+ if j == 1:
+ break
+ for word in line:
+ word = str(word.decode(params.get('csvcode')))
+ if word in _fields:
+ fields.append((word, _fields[word]))
+ elif word in _fields_invert.keys():
+ fields.append((_fields_invert[word], word))
+ else:
+ count = count + 1
+ fields.append((word, word))
+
+ if len(line) == count:
+ error = {'message':"File has not any column header."}
+ except:
+ error = {'message':('Error processing the first line of the file. Field "%s" is unknown') % (word,)}
+
+ if error:
+ params.get('csvfile').seek(0)
+ error=dict(error, preview=params.get('csvfile').read(200))
+ return simplejson.dumps({'error':error})
+
+ return simplejson.dumps({'records':records[1:],'header':fields,'all_fields':all_fields,'req_field':req_field})
+
+ @openerpweb.httprequest
+ def import_data(self, req, **params):
+ import StringIO
+ _fields = {}
+ _fields_invert = {}
+ prefix_node=''
+ prefix_value = ''
+
+ context = req.session.eval_context(req.context)
+ modle_obj = req.session.model(params.get('model'))
+ res = None
+ content = params.get('csvfile').read()
+ input=StringIO.StringIO(content)
+ limit = 0
+ data = []
+
+ if not (params.get('csvdel') and len(params.get('csvdel')) == 1):
+ error={'message': "The CSV delimiter must be a single character"}
+ return simplejson.dumps({'error':error})
+
+ try:
+ for j, line in enumerate(csv.reader(input, quotechar=str(params.get('csvdel')), delimiter=str(params.get('csvsep')))):
+ # If the line contains no data, we should skip it.
+ if not line:
+ continue
+ if j == limit:
+ fields = line
+ else:
+ data.append(line)
+ except csv.Error, e:
+ error={'message': str(e),'title': 'File Format Error'}
+ return simplejson.dumps({'error':error})
+
+ datas = []
+ ctx = context
+
+ if not isinstance(fields, list):
+ fields = [fields]
+
+ flds = dict(req.session.model(params.get('model')).fields_get(False, req.session.eval_context(req.context)))
+ flds.update({'id':{'string':'ID'},'.id':{'string':'Database ID'}})
+ fields_order = flds.keys()
+ for field in fields_order:
+ st_name = prefix_value+flds[field]['string'] or field
+ _fields[prefix_node+field] = st_name
+ _fields_invert[st_name] = prefix_node+field
+
+ unmatch_field = []
+ for fld in fields:
+ if ((fld not in _fields.keys()) and (fld not in _fields_invert.keys())):
+ unmatch_field.append(fld)
+
+ if unmatch_field:
+ error = {'message':("You cannot import the fields '%s',because we cannot auto-detect it." % (unmatch_field))}
+ return simplejson.dumps({'error':error})
+
+ for line in data:
+ try:
+ datas.append(map(lambda x:x.decode(params.get('csvcode')).encode('utf-8'), line))
+ except:
+ datas.append(map(lambda x:x.decode('latin').encode('utf-8'), line))
+
+ # If the file contains nothing,
+ if not datas:
+ error = {'message': 'The file is empty !', 'title': 'Importation !'}
+ return simplejson.dumps({'error':error})
+
+ #Inverting the header into column names
+ try:
+ res = modle_obj.import_data(fields, datas, 'init', '', False, ctx)
+ except xmlrpclib.Fault, e:
+ error = {"message":e.faultCode}
+ return simplejson.dumps({'error':error})
+
+ if res[0]>=0:
+ success={'message':'Imported %d objects' % (res[0],)}
+ return simplejson.dumps({'success':success})
+
+ d = ''
+ for key,val in res[1].items():
+ d+= ('%s: %s' % (str(key),str(val)))
+ msg = 'Error trying to import this record:%s. ErrorMessage:%s %s' % (d,res[2],res[3])
+ error = {'message':str(msg), 'title':'ImportationError'}
+ return simplejson.dumps({'error':error})
=== added file 'addons/web/static/src/css/data_import.css'
--- addons/web/static/src/css/data_import.css 1970-01-01 00:00:00 +0000
+++ addons/web/static/src/css/data_import.css 2011-09-06 13:23:44 +0000
@@ -0,0 +1,19 @@
+.openerp .oe_import_grid {
+ border: none;
+ border-collapse: collapse;
+}
+.openerp .oe_import_grid-header .oe_import_grid-cell {
+ background: url(../img/gradientlinebg.gif) repeat-x #CCCCCC;
+ border-bottom: 1px solid #E3E3E3;
+ font-weight: bold;
+ text-align: left;
+}
+.openerp .oe_import_grid-row .oe_import_grid-cell {
+ border-bottom: 1px solid #E3E3E3;
+}
+.openerp .separator.horizontal {
+ font-weight: bold;
+ border-bottom-width: 1px;
+ margin: 6px 4px 6px 1px;
+ height: 20px;
+}
\ No newline at end of file
=== added file 'addons/web/static/src/img/gradientlinebg.gif'
Binary files addons/web/static/src/img/gradientlinebg.gif 1970-01-01 00:00:00 +0000 and addons/web/static/src/img/gradientlinebg.gif 2011-09-06 13:23:44 +0000 differ
=== modified file 'addons/web/static/src/js/boot.js'
--- addons/web/static/src/js/boot.js 2011-09-06 09:31:39 +0000
+++ addons/web/static/src/js/boot.js 2011-09-06 13:23:44 +0000
@@ -56,7 +56,7 @@
openerp.web.formats(instance);
openerp.web.chrome(instance);
openerp.web.data(instance);
- var files = ["views","search","list","form","list_editable","web_mobile","view_tree","data_export"];
+ var files = ["views","search","list","form","list_editable","web_mobile","view_tree","data_export","data_import"];
for(var i=0; i<files.length; i++) {
if(openerp.web[files[i]]) {
openerp.web[files[i]](instance);
=== modified file 'addons/web/static/src/js/chrome.js'
--- addons/web/static/src/js/chrome.js 2011-09-05 15:56:42 +0000
+++ addons/web/static/src/js/chrome.js 2011-09-06 13:23:44 +0000
@@ -182,9 +182,8 @@
this.$element.closest(".openerp")
.removeClass("login-mode")
.addClass("database_block");
-
+
var self = this;
-
var fetch_db = this.rpc("/web/database/get_list", {}, function(result) {
self.db_list = result.db_list;
});
@@ -196,7 +195,7 @@
self.lang_list = result.lang_list;
});
$.when(fetch_db, fetch_langs).then(function () {self.do_create();});
-
+
this.$element.find('#db-create').click(this.do_create);
this.$element.find('#db-drop').click(this.do_drop);
this.$element.find('#db-backup').click(this.do_backup);
@@ -363,7 +362,7 @@
do_restore: function() {
var self = this;
self.$option_id.html(QWeb.render("RestoreDB", self));
-
+
self.$option_id.find("form[name=restore_db_form]").validate({
submitHandler: function (form) {
$.blockUI({message:'<img src="/web/static/src/img/throbber2.gif">'});
@@ -428,7 +427,7 @@
openerp.web.Login = openerp.web.Widget.extend({
remember_creditentials: true,
-
+
init: function(parent, element_id) {
this._super(parent, element_id);
this.has_local_storage = typeof(localStorage) != 'undefined';
@@ -454,7 +453,7 @@
},
display: function() {
var self = this;
-
+
this.$element.html(QWeb.render("Login", this));
this.database = new openerp.web.Database(
this, "oe_database", "oe_db_options");
@@ -613,7 +612,7 @@
});
});
},
-
+
on_action: function(action) {
},
on_preferences: function(){
@@ -660,7 +659,7 @@
action_manager.appendTo(this.dialog);
action_manager.render(this.dialog);
},
-
+
change_password :function() {
var self = this;
this.dialog = new openerp.web.Dialog(this,{
@@ -818,7 +817,7 @@
// Do you autorize this ? will be replaced by notify() in controller
openerp.web.Widget.prototype.notification = new openerp.web.Notification(this, "oe_notification");
-
+
this.header = new openerp.web.Header(this);
this.login = new openerp.web.Login(this, "oe_login");
this.header.on_logout.add(this.login.on_logout);
@@ -883,7 +882,7 @@
self.execute_home_action(home_action[0], ds);
})
},
- default_home: function () {
+ default_home: function () {
},
/**
* Bundles the execution of the home action
=== added file 'addons/web/static/src/js/data_import.js'
--- addons/web/static/src/js/data_import.js 1970-01-01 00:00:00 +0000
+++ addons/web/static/src/js/data_import.js 2011-09-06 13:23:44 +0000
@@ -0,0 +1,119 @@
+openerp.web.data_import = function(openerp) {
+openerp.web.DataImport = openerp.web.Dialog.extend({
+ init: function(parent, dataset){
+ this.parent = parent;
+ this._super(parent);
+ this.dataset = dataset;
+ },
+ start: function() {
+ var self = this;
+ self._super(false);
+ self.template = 'ImportDataView';
+ self.dialog_title = "Import Data"
+ self.open({
+ modal: true,
+ width: '70%',
+ height: 'auto',
+ position: 'top',
+ buttons : {
+ "Close" : function() {
+ self.stop();
+ },
+ "Import File" : function() {
+ self.do_import();
+ }
+ },
+ close: function(event, ui){ self.stop();}
+ });
+ this.$element.find('#csvfile').change(this.on_autodetect_data);
+ this.$element.find('fieldset').change(this.on_autodetect_data);
+ this.$element.find('fieldset legend').click(function () {
+ $(this).next().toggle();
+ });
+ },
+ do_import: function() {
+ var self = this;
+ if(!this.$element.find('#csvfile').val()) { return; }
+ this.$element.find('#import_data').attr({
+ 'action': '/web/import/import_data'
+ }).ajaxSubmit({
+ success: this.on_import_results
+ });
+ },
+ on_autodetect_data: function() {
+ var self = this;
+ if(this.$element.find("#res td")){
+ this.$element.find("#res td").remove();
+ this.$element.find("#imported_success").css('display','none');
+ }
+ if(!this.$element.find('#csvfile').val()) { return; }
+ this.$element.find('#import_data').attr({
+ 'action': '/web/import/detect_data'
+ }).ajaxSubmit({
+ success: this.on_import_results
+ });
+ },
+ on_import_results:function(res){
+ var self = this;
+ this.$element.find('#result, #success , #message').empty();
+
+ var results = $.parseJSON(res);
+ var result_node = $("#result");
+ var records = {};
+
+ if (results['records']){
+ records = {'header':results['header'],'sel':results['all_fields'],'row':results['records']};
+ result_node.append(QWeb.render('ImportView-result',{'records':records}));
+ }else if(results['error']){
+ result_node.append(QWeb.render('ImportView-result',{'error': results['error']}));
+ }else if(results['success']){
+ self.stop();
+ this.parent.reload_content();
+ }
+ this.do_check_req_field(results['req_field']);
+ var selected_fields = [];
+ $("td #sel_field").click(function(){
+ selected_fields = [];
+ $("td #sel_field option:selected").each(function(){
+ selected_fields.push($(this).index());
+ });
+ });
+ $("td #sel_field").change(function(){
+ $("#message").empty();
+ $("td #sel_field").css('background-color','');
+ $(".ui-button-text:contains('Import File')").parent().attr("disabled",false);
+ self.do_check_req_field(results['req_field']);
+ var curr_selected = this.selectedIndex;
+ if ($.inArray(curr_selected,selected_fields) > -1){
+ $(this).css('background-color','#FF6666');
+ $("#message").append("*Selected column should not be same.");
+ $(".ui-button-text:contains('Import File')").parent().attr("disabled",true);
+ }else{
+ $(this).css('background-color','');
+ }
+ });
+ },
+ do_check_req_field: function(req_fld){
+ if (req_fld.length){
+ var sel_fields =[];
+ var required_fields = [];
+ $("td #sel_field option:selected").each(function(){
+ sel_fields.push($(this).val());
+ });
+ _.each(req_fld,function(fld){
+ if ($.inArray(fld,sel_fields) <= -1){
+ required_fields.push(fld);
+ }
+ });
+ if (required_fields.length){
+ $("#message").append("*Required Fields are not selected which is "+required_fields+". ");
+ $(".ui-button-text:contains('Import File')").parent().attr("disabled",true);
+ }
+ }
+ },
+ stop: function() {
+ $(this.$dialog).remove();
+ this._super();
+ }
+});
+};
\ No newline at end of file
=== modified file 'addons/web/static/src/js/form.js'
--- addons/web/static/src/js/form.js 2011-09-06 13:02:01 +0000
+++ addons/web/static/src/js/form.js 2011-09-06 13:23:44 +0000
@@ -1336,7 +1336,7 @@
this.$input = this.$element.find("input");
this.$drop_down = this.$element.find(".oe-m2o-drop-down-button");
this.$menu_btn = this.$element.find(".oe-m2o-cm-button");
-
+
// context menu
var init_context_menu_def = $.Deferred().then(function(e) {
var rdataset = new openerp.web.DataSetStatic(self, "ir.values", self.build_context());
@@ -1344,7 +1344,7 @@
[[self.field.relation, false]], false, rdataset.get_context()], false, 0)
.then(function(result) {
self.related_entries = result;
-
+
var $cmenu = $("#" + self.cm_id);
$cmenu.append(QWeb.render("FieldMany2One.context_menu", {widget: self}));
var bindings = {};
=== modified file 'addons/web/static/src/js/views.js'
--- addons/web/static/src/js/views.js 2011-09-06 13:02:01 +0000
+++ addons/web/static/src/js/views.js 2011-09-06 13:23:44 +0000
@@ -674,7 +674,7 @@
* Directly set a view to use instead of calling fields_view_get. This method must
* be called before start(). When an embedded view is set, underlying implementations
* of openerp.web.View must use the provided view instead of any other one.
- *
+ *
* @param embedded_view A view.
*/
set_embedded_view: function(embedded_view) {
@@ -732,6 +732,8 @@
this.log('Todo');
},
on_sidebar_import: function() {
+ var import_view = new openerp.web.DataImport(this, this.dataset);
+ import_view.start(false);
},
on_sidebar_export: function() {
var export_view = new openerp.web.DataExport(this, this.dataset);
=== modified file 'addons/web/static/src/xml/base.xml'
--- addons/web/static/src/xml/base.xml 2011-09-05 16:02:46 +0000
+++ addons/web/static/src/xml/base.xml 2011-09-06 13:23:44 +0000
@@ -1358,6 +1358,155 @@
</table>
</form>
</t>
+
+<t t-name="ImportView">
+ <a id="importview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Import</a>
+</t>
+<t t-name="ImportDataView">
+<form name="import_data" id="import_data" action="" method="post" enctype="multipart/form-data">
+ <input type="hidden" name="session_id" t-att-value="session.session_id"/>
+ <input type="hidden" name="model" t-att-value="dataset.model"/>
+ <table cellspacing="5" border="0" width="100%">
+ <tr>
+ <td>
+ <table width="100%">
+ <tr>
+ <td width="100%" valign="middle" colspan="4">
+ <h2 class="separator horizontal">1. Import a .CSV file</h2>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Select a .CSV file to import. If you need a sample of file to import,
+ you should use the export tool with the "Import Compatible" option.
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table align="left">
+ <tr>
+ <td><label>CSV File:</label></td>
+ <td>
+ <input type="file" id="csvfile" size="50" name="csvfile"/>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td height="10px">
+ </td>
+ </tr>
+ <tr>
+ <td width="100%">
+ <div id="record">
+ <table width="100%">
+ <tr>
+ <td width="100%" valign="middle">
+ <h2 class="separator horizontal">2. Check your file format</h2>
+ </td>
+ </tr>
+ </table>
+ <div id="message" style="color:red"></div>
+ <div id="result"></div>
+ <fieldset>
+ <legend style="cursor:pointer;">CSV Options</legend>
+ <table style="display:none">
+ <tr>
+ <td><label for="csv_separator">Separator:</label></td>
+ <td><input type="text" name="csvsep" id="csv_separator" value=","/></td>
+ <td><label for="csv_delimiter">Delimiter:</label></td>
+ <td><input type="text" name="csvdel" id="csv_delimiter" value='"'/></td>
+ </tr>
+ <tr>
+ <td><label for="csv_encoding">Encoding:</label></td>
+ <td>
+ <select name="csvcode" id="csv_encoding">
+ <option value="utf-8">UTF-8</option>
+ <option value="latin1">Latin 1</option>
+ </select>
+ </td>
+ <td><label>Lines to skip:</label></td>
+ <td><input type="text" name="csvskip" id="csv_skip" value="1"/></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td width="100%">
+ <div id="success"></div>
+ </td>
+ </tr>
+ </table>
+</form>
+</t>
+<t t-name="ImportView-result">
+ <t t-if="error">
+ <table id="error_tbl">
+ <tr style="white-space:pre-line;">The import failed due to:<t t-esc="error.message"/></tr>
+ <t t-if="error.preview">
+ <tr>Here is a preview of the file we could not import:</tr>
+ <tr><pre><t t-esc="error.preview"/></pre></tr>
+ </t>
+ </table>
+ </t>
+ <t t-if="records">
+ <table id="records_data" class="oe_import_grid" width="100%" style="margin: 5px 0;">
+ <t t-foreach="records" t-as="record">
+ <t t-if="record=='header'">
+ <tr class="oe_import_grid-header">
+ <t t-foreach="records.header" t-as="header">
+ <td class="oe_import_grid-cell" id="header"><t t-esc="header[0]"/></td>
+ </t>
+ </tr>
+ </t>
+ <t t-if="record=='sel'">
+ <tr>
+ <t t-foreach="records.header" t-as="header">
+ <td>
+ <select name="sel_field" id="sel_field">
+ <option selected="selected" value=""></option>
+ <t t-foreach="records.sel" t-as="selection">
+ <option t-att="{'selected': header[0] === selection ? 'selected' : null}"
+ t-att-value="selection"><t t-esc="selection"/>
+ </option>
+ </t>
+ </select>
+ </td>
+ </t>
+ </tr>
+ </t>
+ <t t-if="record=='row'">
+ <t t-foreach="records.row" t-as="row">
+ <tr class="oe_import_grid-row">
+ <t t-foreach="row" t-as="column">
+ <td class="oe_import_grid-cell"><t t-esc="column"/></td>
+ </t>
+ </tr>
+ </t>
+ </t>
+ </t>
+ </table>
+ </t>
+ <t t-if="success">
+ <table width="100%">
+ <tr>
+ <td width="100%" valign="middle" colspan="4">
+ <h2 class="separator horizontal">3. File imported</h2>
+ </td>
+ </tr>
+ <tr>
+ <t t-esc="success.message"/>
+ </tr>
+ </table>
+ </t>
+</t>
+
<t t-name="About-Page">
<div>
<h1>OpenERP Web</h1>
@@ -1388,4 +1537,4 @@
</p>
</div>
</t>
-</templates>
+</templates>
\ No newline at end of file
_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help : https://help.launchpad.net/ListHelp