[FIX] web: Kanban QuickCreate: create on 'ENTER'

Rev. 241704536d highlighted a bug in the Kanban RecordQuickCreate
widget, when a form view is used inside the widget.

Let's assume a quick create form view with a char field. The user
fill in this field and press 'ENTER' (without focusing out). The
record is about to be created. But first, we have to ask all fields
to commit their value (through 'commitChanges'), in case they
wouldn't have yet. The char field thus notifies its parents of its
new value at that moment. The form controller handles this request
in its '_applyChanges' function, but this is done in its mutex (to
prevent overlapping onchange RPCs). Unfortunately, this leads to a
deadlock as the quick create form controller already executed the
'commitChanges' request in this mutex.

Actually, there is no need for the quick create form controller to
execute the 'commitChanges' request in the mutex, as it is already
properly mutexified upstream. This rev. thus remove the use of the
mutex at that spot.

Note that before rev. 241704536d, the bug didn't occur because the
'commitChanges' function of InputField didn't return a deferred,
and thus the mutex was unlocked directly.

To be complete, let us mention that there are still some
concurrency issues with the quick create widget (like multiple
records creation on double clicks or double 'ENTER' keypress).
Those issues will be tackled in a future commit.

Task 1878977
This commit is contained in:
Aaron Bohy
2018-08-23 16:18:32 +02:00
parent 3f2bc7b11f
commit f6e5bd13d4
2 changed files with 51 additions and 2 deletions
@@ -72,8 +72,7 @@ var QuickCreateFormController = FormController.extend({
* @return {Deferred}
*/
commitChanges: function () {
return this.mutex
.exec(this.renderer.commitChanges.bind(this.renderer, this.handle));
return this.renderer.commitChanges(this.handle);
},
/**
* @returns {Object} the changes done on the current record
@@ -810,6 +810,56 @@ QUnit.module('Views', {
kanban.destroy();
});
QUnit.test('quick create record: validate with ENTER', function (assert) {
// in this test, we accurately mock the behavior of the webclient by specifying a
// fieldDebounce > 0, meaning that the changes in an InputField aren't notified to the model
// on 'input' events, but they wait for the 'change' event (or a call to 'commitChanges',
// e.g. triggered by a navigation event)
// in this scenario, the call to 'commitChanges' actually does something (i.e. it notifies
// the new value of the char field), whereas it does nothing if the changes are notified
// directly
assert.expect(3);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '<kanban on_create="quick_create" quick_create_view="some_view_ref">' +
'<field name="bar"/>' +
'<templates><t t-name="kanban-box">' +
'<div><field name="foo"/></div>' +
'</t></templates></kanban>',
archs: {
'partner,some_view_ref,form': '<form>' +
'<field name="foo"/>' +
'<field name="int_field"/>' +
'</form>',
},
groupBy: ['bar'],
fieldDebounce: 5000,
});
assert.strictEqual(kanban.$('.o_kanban_record').length, 4,
"should have 4 records at the beginning");
// add an element and confirm by pressing ENTER
kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click();
kanban.$('.o_kanban_quick_create').find('input[name=foo]')
.val('new partner')
.trigger('input') // changes aren't notified here thanks to the fieldDebounce
.trigger($.Event('keydown', {
keyCode: $.ui.keyCode.ENTER,
which: $.ui.keyCode.ENTER,
})); // triggers a navigation event, leading to the 'commitChanges' and record creation
assert.strictEqual(kanban.$('.o_kanban_record').length, 5,
"should have created a new record");
assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), '',
"quick create should now be empty");
kanban.destroy();
});
QUnit.test('quick create when first column is folded', function (assert) {
assert.expect(6);