diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js index 9f7cbba8696..b384b122f5f 100644 --- a/addons/web/static/src/js/views/list/list_editable_renderer.js +++ b/addons/web/static/src/js/views/list/list_editable_renderer.js @@ -311,7 +311,16 @@ ListRenderer.include({ if (this.state.count >= 4) { $row.remove(); } else { - $row.replaceWith(this._renderEmptyRow()); + // we want to always keep at least 4 (possibly empty) rows + var $emptyRow = this._renderEmptyRow(); + $row.replaceWith($emptyRow); + if (this.editable === "top") { + // move the empty row we just inserted after data rows + var $lastDataRow = this.$('.o_data_row:last'); + if ($lastDataRow.length) { + $emptyRow.insertAfter($lastDataRow); + } + } } }, /** diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index cb5ab7dd510..c81a4e48db2 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -359,6 +359,34 @@ QUnit.module('Views', { list.destroy(); }); + QUnit.test('discard a new record in editable="top" list with less than 4 records', async function (assert) { + assert.expect(7); + + var list = await createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '', + domain: [['bar', '=', true]], + }); + + assert.containsN(list, '.o_data_row', 3); + assert.containsN(list, 'tbody tr', 4); + + await testUtils.dom.click(list.$('.o_list_button_add')); + + assert.containsN(list, '.o_data_row', 4); + assert.hasClass(list.$('tbody tr:first'), 'o_selected_row'); + + await testUtils.dom.click(list.$('.o_list_button_discard')); + + assert.containsN(list, '.o_data_row', 3); + assert.containsN(list, 'tbody tr', 4); + assert.hasClass(list.$('tbody tr:first'), 'o_data_row'); + + list.destroy(); + }); + QUnit.test('basic grouped list rendering', async function (assert) { assert.expect(4);