[IMP] web/list: multi edition ux
This commit introcudes two changes to the multi edition in list views:
1. Editing one record does not require confirmation through a dialog
2. Successfully saving multiple records unselects all currently checked records
Task 2146429
closes odoo/odoo#41099
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -400,6 +400,25 @@ var ListController = BasicController.extend({
|
||||
return result;
|
||||
}, []);
|
||||
return new Promise((resolve, reject) => {
|
||||
const saveRecords = () => {
|
||||
this.model.saveRecords(this.handle, recordId, validRecordIds, fieldName)
|
||||
.then(async () => {
|
||||
this._updateButtons('readonly');
|
||||
const state = this.model.get(this.handle);
|
||||
// We need to check the current multi-editable state here
|
||||
// in case the selection is changed. If there are changes
|
||||
// and the list was multi-editable, we do not want to select
|
||||
// the next row.
|
||||
this.selectedRecords = [];
|
||||
await this.renderer.updateState(state, {
|
||||
keepWidths: true,
|
||||
selectedRecords: [],
|
||||
});
|
||||
this.renderer.focusCell(recordId, node);
|
||||
resolve(!Object.keys(changes).length);
|
||||
})
|
||||
.guardedCatch(discardAndReject);
|
||||
};
|
||||
const discardAndReject = () => {
|
||||
this.model.discardChanges(recordId);
|
||||
this._confirmSave(recordId).then(() => {
|
||||
@@ -408,18 +427,12 @@ var ListController = BasicController.extend({
|
||||
});
|
||||
};
|
||||
if (validRecordIds.length > 0) {
|
||||
if (recordIds.length === 1) {
|
||||
// Save without prompt
|
||||
return saveRecords();
|
||||
}
|
||||
const dialogOptions = {
|
||||
confirm_callback: () => {
|
||||
this.model.saveRecords(this.handle, recordId, validRecordIds, fieldName)
|
||||
.then(async () => {
|
||||
this._updateButtons('readonly');
|
||||
const state = this.model.get(this.handle);
|
||||
await this.renderer.updateState(state, { keepWidths: true });
|
||||
await this.renderer.focusCell(recordId, node);
|
||||
resolve(Object.keys(changes));
|
||||
})
|
||||
.guardedCatch(discardAndReject);
|
||||
},
|
||||
confirm_callback: saveRecords,
|
||||
cancel_callback: discardAndReject,
|
||||
};
|
||||
const record = this.model.get(recordId);
|
||||
|
||||
@@ -507,12 +507,12 @@ ListRenderer.include({
|
||||
onSuccess: resolve,
|
||||
onFailure: reject,
|
||||
});
|
||||
}).then(changedFields => {
|
||||
}).then(selectNextRow => {
|
||||
this._enableRecordSelectors();
|
||||
// If any field has changed and if the list is in multiple edition,
|
||||
// we send a truthy boolean to _selectRow to tell it not to select
|
||||
// the following record.
|
||||
return changedFields && changedFields.length && this.isInMultipleRecordEdition(recordID);
|
||||
return selectNextRow;
|
||||
}).guardedCatch(() => {
|
||||
toggleWidgets(false);
|
||||
});
|
||||
@@ -1300,8 +1300,8 @@ ListRenderer.include({
|
||||
var recordId = this._getRecordID(rowIndex);
|
||||
// To select a row, the currently selected one must be unselected first
|
||||
var self = this;
|
||||
return this.unselectRow().then(noSelectNext => {
|
||||
if (noSelectNext) {
|
||||
return this.unselectRow().then((selectNextRow = true) => {
|
||||
if (!selectNextRow) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!recordId) {
|
||||
|
||||
@@ -5495,7 +5495,7 @@ QUnit.module('Views', {
|
||||
});
|
||||
|
||||
QUnit.test('editable list view: multi edition', async function (assert) {
|
||||
assert.expect(24);
|
||||
assert.expect(26);
|
||||
|
||||
var list = await createView({
|
||||
View: ListView,
|
||||
@@ -5549,6 +5549,8 @@ QUnit.module('Views', {
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_data_cell:eq(0)'));
|
||||
assert.containsOnce(document.body, '.modal', "modal appears when switching cells");
|
||||
await testUtils.dom.click($('.modal .btn:contains(Cancel)'));
|
||||
assert.containsN(list, '.o_list_record_selector input:checked', 2,
|
||||
"Selection should remain unchanged");
|
||||
assert.strictEqual(list.$('.o_data_row:eq(0) .o_data_cell').text(), 'yop10',
|
||||
"changes have been discarded and row is back to readonly");
|
||||
assert.strictEqual(document.activeElement, list.$('.o_data_row:eq(0) .o_data_cell:eq(1)')[0],
|
||||
@@ -5559,6 +5561,7 @@ QUnit.module('Views', {
|
||||
assert.ok($('.modal').text().includes('those 2 records'), "the number of records should be correctly displayed");
|
||||
await testUtils.dom.click($('.modal .btn-primary'));
|
||||
assert.containsNone(list, '.o_data_cell input.o_field_widget', "no field should be editable anymore");
|
||||
assert.containsNone(list, '.o_list_record_selector input:checked', "no record should be selected anymore");
|
||||
assert.verifySteps(['write', 'read']);
|
||||
assert.strictEqual(list.$('.o_data_row:eq(0) .o_data_cell').text(), "yop666",
|
||||
"the first row should be updated");
|
||||
@@ -5626,18 +5629,16 @@ QUnit.module('Views', {
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_list_record_selector input'));
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_data_cell:eq(0)'));
|
||||
await testUtils.fields.editInput(list.$('.o_field_widget[name=foo]'), 'hi');
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_data_cell:eq(1)'));
|
||||
|
||||
assert.containsOnce(document.body, '.modal'); // save dialog
|
||||
await testUtils.dom.click($('.modal .btn-primary'));
|
||||
|
||||
assert.containsNone(document.body, '.modal');
|
||||
assert.strictEqual(list.$('.o_data_row:eq(0) .o_data_cell').text(), "hi2");
|
||||
assert.strictEqual(list.$('.o_data_row:eq(1) .o_data_cell').text(), "blip9");
|
||||
|
||||
assert.verifySteps(['write', 'read']);
|
||||
|
||||
// select the second record (the first one is still selected)
|
||||
assert.ok(list.$('.o_data_row:eq(0) .o_list_record_selector input').is(':checked'));
|
||||
assert.containsNone(list, '.o_list_record_selector input:checked');
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_list_record_selector input'));
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(1) .o_list_record_selector input'));
|
||||
|
||||
// edit foo, first row
|
||||
@@ -6063,7 +6064,7 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('editable readonly list view: single edition behaves like a multi-edition', async function (assert) {
|
||||
QUnit.test('editable readonly list view: single edition does not behave like a multi-edition', async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
const list = await createView({
|
||||
@@ -6083,17 +6084,14 @@ QUnit.module('Views', {
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_data_cell:eq(0)'));
|
||||
await testUtils.fields.editInput(list.$('.o_field_widget[name=foo]'), "");
|
||||
|
||||
assert.containsOnce($('body'),'.modal', "should have a modal");
|
||||
assert.containsOnce($('body'),'.modal', "should have a modal (invalid fields)");
|
||||
await testUtils.dom.click($('.modal button.btn'));
|
||||
|
||||
// edit a field
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_data_cell:eq(0)'));
|
||||
await testUtils.fields.editInput(list.$('.o_field_widget[name=foo]'), "bar");
|
||||
|
||||
assert.containsOnce($('body'),'.modal', "should have a modal");
|
||||
await testUtils.dom.click($('.modal button.btn.btn-primary'));
|
||||
|
||||
|
||||
assert.containsNone($('body'),'.modal', "should not have a modal");
|
||||
assert.strictEqual(list.$('.o_data_row:eq(0) .o_data_cell').text(), "bar",
|
||||
"the first row should be updated");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user