[FIX] web: add support for editable=top/bottom in o2m
Before this commit, we lost the functionality of editing records top or bottom. However, it as almost ready, but we needed to change the way commands are generated, to respect the actual order in the UI. Also, the mock server needed to be updated, to make sure he also save the new ids in the correct order.
This commit is contained in:
committed by
Aaron Bohy
parent
39ab5712ed
commit
e7dfa4af77
@@ -777,8 +777,8 @@ var FieldOne2Many = FieldX2Many.extend({
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
if (event && event.target === self && self.view.arch.tag === 'tree') {
|
||||
if (event.data.changes[self.name].operation === 'CREATE') {
|
||||
// todo: get last record if editable = bottom
|
||||
var newID = self.value.data[0].id;
|
||||
var index = self.editable === 'top' ? 0 : self.value.data.length - 1;
|
||||
var newID = self.value.data[index].id;
|
||||
self.renderer.editRecord(newID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,7 +1058,7 @@ var BasicModel = AbstractModel.extend({
|
||||
return this.notifyChanges(id, command.data);
|
||||
}));
|
||||
} else {
|
||||
defs.push(this.addDefaultRecord(list.id));
|
||||
defs.push(this.addDefaultRecord(list.id, {position: command.position}));
|
||||
}
|
||||
break;
|
||||
case 'UPDATE':
|
||||
@@ -1715,20 +1715,29 @@ var BasicModel = AbstractModel.extend({
|
||||
var removedIds = _.difference(list.res_ids, relIds);
|
||||
var addedIds = _.difference(relIds, list.res_ids);
|
||||
var keptIds = _.intersection(list.res_ids, relIds);
|
||||
|
||||
// the didChange variable keeps track of the fact that at
|
||||
// least one id was updated
|
||||
var didChange = false;
|
||||
var command, i, relRecord;
|
||||
for (i = 0; i < keptIds.length; i++) {
|
||||
relRecord = _.findWhere(relData, {res_id: keptIds[i]});
|
||||
if (!_.isEmpty(relRecord._changes)) {
|
||||
var changes = this._generateChanges(relRecord);
|
||||
command = x2ManyCommands.update(relRecord.res_id, changes);
|
||||
didChange = true;
|
||||
} else {
|
||||
command = x2ManyCommands.link_to(keptIds[i]);
|
||||
var command, relRecord;
|
||||
for (var i = 0; i < relIds.length; i++) {
|
||||
if (_.contains(keptIds, relIds[i])) {
|
||||
// this is an id that already existed
|
||||
relRecord = _.findWhere(relData, {res_id: relIds[i]});
|
||||
if (!_.isEmpty(relRecord._changes)) {
|
||||
var changes = this._generateChanges(relRecord);
|
||||
command = x2ManyCommands.update(relRecord.res_id, changes);
|
||||
didChange = true;
|
||||
} else {
|
||||
command = x2ManyCommands.link_to(relIds[i]);
|
||||
}
|
||||
commands[fieldName].push(command);
|
||||
} else if (_.contains(addedIds, relIds[i])) {
|
||||
// this is a new id
|
||||
relRecord = _.findWhere(relData, {res_id: relIds[i]});
|
||||
relRecord = this.get(relRecord.id, {raw: true});
|
||||
commands[fieldName].push(x2ManyCommands.create(_.omit(relRecord.data, 'id')));
|
||||
}
|
||||
commands[fieldName].push(command);
|
||||
}
|
||||
if (changesOnly && !didChange && addedIds.length === 0 && removedIds.length === 0) {
|
||||
// in this situation, we have no changed ids, no added
|
||||
@@ -1736,11 +1745,7 @@ var BasicModel = AbstractModel.extend({
|
||||
// last changes
|
||||
commands[fieldName] = [];
|
||||
}
|
||||
for (i = 0; i < addedIds.length; i++) {
|
||||
relRecord = _.findWhere(relData, {res_id: addedIds[i]});
|
||||
relRecord = this.get(relRecord.id, {raw: true});
|
||||
commands[fieldName].push(x2ManyCommands.create(_.omit(relRecord.data, 'id')));
|
||||
}
|
||||
// add delete commands
|
||||
for (i = 0; i < removedIds.length; i++) {
|
||||
commands[fieldName].push(x2ManyCommands.delete(removedIds[i]));
|
||||
}
|
||||
|
||||
@@ -2628,6 +2628,98 @@ QUnit.module('relational_fields', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('one2many list editable = top', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<group>' +
|
||||
'<field name="turtles">' +
|
||||
'<tree editable="top">' +
|
||||
'<field name="turtle_foo"/>' +
|
||||
'</tree>' +
|
||||
'</field>' +
|
||||
'</group>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'write') {
|
||||
var commands = args.args[1].turtles;
|
||||
assert.strictEqual(commands[0][0], 0,
|
||||
"first command is a create");
|
||||
assert.strictEqual(commands[1][0], 4,
|
||||
"second command is a link to");
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
form.$buttons.find('.o_form_button_edit').click();
|
||||
|
||||
assert.strictEqual(form.$('.o_data_row').length, 1,
|
||||
"should start with one data row");
|
||||
|
||||
form.$('.o_form_field_x2many_list_row_add a').click();
|
||||
|
||||
assert.strictEqual(form.$('.o_data_row').length, 2,
|
||||
"should have 2 data rows");
|
||||
assert.ok(form.$('tr.o_data_row:first:contains(My little Foo Value)').length, 1,
|
||||
"first row should be the new value");
|
||||
assert.ok(form.$('tr.o_data_row:first').hasClass('o_selected_row'),
|
||||
"first row should be selected");
|
||||
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('one2many list editable = bottom', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<group>' +
|
||||
'<field name="turtles">' +
|
||||
'<tree editable="bottom">' +
|
||||
'<field name="turtle_foo"/>' +
|
||||
'</tree>' +
|
||||
'</field>' +
|
||||
'</group>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'write') {
|
||||
var commands = args.args[1].turtles;
|
||||
assert.strictEqual(commands[0][0], 4,
|
||||
"first command is a link to");
|
||||
assert.strictEqual(commands[1][0], 0,
|
||||
"second command is a create");
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
form.$buttons.find('.o_form_button_edit').click();
|
||||
|
||||
assert.strictEqual(form.$('.o_data_row').length, 1,
|
||||
"should start with one data row");
|
||||
|
||||
form.$('.o_form_field_x2many_list_row_add a').click();
|
||||
|
||||
assert.strictEqual(form.$('.o_data_row').length, 2,
|
||||
"should have 2 data rows");
|
||||
assert.ok(form.$('tr.o_data_row:eq(1):contains(My little Foo Value)').length, 1,
|
||||
"second row should be the new value");
|
||||
assert.ok(form.$('tr.o_data_row:eq(1)').hasClass('o_selected_row'),
|
||||
"second row should be selected");
|
||||
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.module('FieldMany2Many');
|
||||
|
||||
QUnit.test('many2many kanban: edition', function (assert) {
|
||||
|
||||
@@ -896,26 +896,26 @@ var MockServer = Class.extend({
|
||||
continue;
|
||||
}
|
||||
if (_.contains(['one2many', 'many2many'], field.type)) {
|
||||
var ids = [];
|
||||
// convert commands
|
||||
_.each(value, function (command) {
|
||||
if (command[0] === 0) { // CREATE
|
||||
var id = self._mockCreate(field.relation, command[2]);
|
||||
record[field_changed].push(id);
|
||||
ids.push(id);
|
||||
} else if (command[0] === 1) { // UPDATE
|
||||
self._mockWrite(field.relation, [[command[1]], command[2]]);
|
||||
} else if (command[0] === 2) { // DELETE
|
||||
record[field_changed] = _.without(record[field_changed], command[1]);
|
||||
} else if (command[0] === 4) { // LINK_TO
|
||||
// nothing to do, this command is called by a one2many,
|
||||
// and should do nothing in a non concurrent environment.
|
||||
ids.push(command[1]);
|
||||
} else if (command[0] === 5) { // DELETE ALL
|
||||
record[field_changed] = [];
|
||||
ids = [];
|
||||
} else if (command[0] === 6) { // REPLACE WITH
|
||||
record[field_changed] = command[2];
|
||||
ids = command[2];
|
||||
} else {
|
||||
console.error('Command ' + JSON.stringify(command) + ' not supported by the MockServer');
|
||||
}
|
||||
});
|
||||
record[field_changed] = ids;
|
||||
} else if (field.type === 'many2one') {
|
||||
if (value) {
|
||||
var relatedRecord = _.findWhere(this.data[field.relation].records, {
|
||||
|
||||
Reference in New Issue
Block a user