summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorJulien Mougenot <jum@odoo.com>2019-08-14 13:16:04 +0000
committerJulien Mougenot <jum@odoo.com>2019-08-16 09:03:49 +0000
commitdd27b2e9c6935d095611c75ffa4f06cc565e4802 (patch)
tree0f713d53859c3a465ac5ad0351a9cdb2d36558ef /addons/web/static/src
parent291dad6bc869eeeba9bbb5cf13d498ece9266d2d (diff)
[FIX] web: multi edition in editable listviews error handling
Fixed crashes/incorrect behaviours in multi edition in the list views. The solution to these problems was mainly to refactor the function used to save multiple records. Before this commit: - Cancelling the confirmation dialog in multi edition caused the edited record to be editable but disabled - Saving an empty field in multi edition triggered a JS error - Static confirmation message ("saving 0 valid records") After this commit: - Ability to cancel confirmation - Proper error display when trying to save empty fields - Message consistent with the situation
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/js/views/list/list_controller.js88
-rw-r--r--addons/web/static/src/js/views/list/list_editable_renderer.js12
2 files changed, 66 insertions, 34 deletions
diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js
index 4edf5287ac2..65e2ed7f5a0 100644
--- a/addons/web/static/src/js/views/list/list_controller.js
+++ b/addons/web/static/src/js/views/list/list_controller.js
@@ -49,6 +49,7 @@ var ListController = BasicController.extend({
this.editable = params.editable;
this.noLeaf = params.noLeaf;
this.selectedRecords = params.selectedRecords || [];
+ this.multipleRecordsSavingPromise = null;
},
//--------------------------------------------------------------------------
@@ -347,15 +348,6 @@ var ListController = BasicController.extend({
return _.extend(env, {domain: record.getDomain()});
},
/**
- * @private
- * @returns {boolean}
- */
- _inMultipleRecordEdition: function (recordId) {
- var record = this.model.get(recordId, { raw: true });
- var recordIds = _.union([recordId], this.selectedRecords);
- return recordIds.length > 1 && record.res_id;
- },
- /**
* Only display the pager when there are data to display.
*
* @override
@@ -366,10 +358,16 @@ var ListController = BasicController.extend({
return !!state.count;
},
/**
+ * Saves multiple records at once. This method is called by the _onFieldChanged method
+ * since the record must be confirmed as soon as the focus leaves a dirty cell.
+ * Pseudo-validation is performed with registered modifiers.
+ * Returns a promise that is resolved when confirming and rejected in any other case.
+ *
* @private
* @param {string} recordId
* @param {Object} node
* @param {Object} changes
+ * @returns {Promise}
*/
_saveMultipleRecords: function (recordId, node, changes) {
var self = this;
@@ -383,22 +381,42 @@ var ListController = BasicController.extend({
}
return result;
}, []);
- var message = _.str.sprintf(
- _t('Do you want to set the value on the %d valid selected records?'),
- validRecordIds.length);
- if (recordIds.length !== validRecordIds.length) {
- var nbInvalid = recordIds.length - validRecordIds.length;
- message += ' ' + _.str.sprintf(_t('(%d invalid)'), nbInvalid);
- }
- Dialog.confirm(this, message, {
- confirm_callback: function () {
- self.model.saveRecords(recordId, validRecordIds)
- .then(function () {
- self._updateButtons('readonly');
- var state = self.model.get(self.handle);
- self.renderer.updateState(state, {});
- });
- },
+ const nbInvalid = recordIds.length - validRecordIds.length;
+
+ return new Promise((resolve, reject) => {
+ const rejectAndDiscard = () => {
+ this.model.discardChanges(recordId);
+ return this._confirmSave(recordId).then(reject);
+ };
+ if (validRecordIds.length > 0) {
+ let message;
+ if (nbInvalid === 0) {
+ message = _.str.sprintf(
+ _t("Do you want to set the value on the %d selected records?"),
+ validRecordIds.length);
+ } else {
+ message = _.str.sprintf(
+ _t("Do you want to set the value on the %d valid selected records? (%d invalid)"),
+ validRecordIds.length, nbInvalid);
+ }
+ Dialog.confirm(this, message, {
+ confirm_callback: () => {
+ this.model.saveRecords(recordId, validRecordIds)
+ .then(() => {
+ this._updateButtons('readonly');
+ const state = this.model.get(this.handle);
+ this.renderer.updateState(state, {});
+ resolve();
+ })
+ .guardedCatch(rejectAndDiscard);
+ },
+ cancel_callback: rejectAndDiscard,
+ });
+ } else {
+ Dialog.alert(this, _t("No valid record to save"), {
+ confirm_callback: rejectAndDiscard,
+ });
+ }
});
},
/**
@@ -409,10 +427,11 @@ var ListController = BasicController.extend({
*/
_saveRecord: function (recordId) {
var record = this.model.get(recordId, { raw: true });
- if (record.isDirty() && this._inMultipleRecordEdition(recordId)) {
+ if (record.isDirty() && this.renderer.inMultipleRecordEdition(recordId)) {
// do not save the record (see _saveMultipleRecords)
- return Promise.resolve();
-
+ const prom = this.multipleRecordsSavingPromise || Promise.reject();
+ this.multipleRecordsSavingPromise = null;
+ return prom;
}
return this._super.apply(this, arguments);
},
@@ -621,14 +640,15 @@ var ListController = BasicController.extend({
*/
_onFieldChanged: function (ev) {
ev.stopPropagation();
- var self = this;
+ const recordId = ev.data.dataPointID;
- if (this._inMultipleRecordEdition(ev.data.dataPointID)) {
+ if (this.renderer.inMultipleRecordEdition(recordId)) {
// deal with edition of multiple lines
- var _onSuccess = ev.data.onSuccess;
- ev.data.onSuccess = function () {
- Promise.resolve(_onSuccess()).then(function () {
- self._saveMultipleRecords(ev.data.dataPointID, ev.target.__node, ev.data.changes);
+ const _onSuccess = ev.data.onSuccess;
+ ev.data.onSuccess = () => {
+ Promise.resolve(_onSuccess()).then(() => {
+ const savedRecordsPromise = this._saveMultipleRecords(ev.data.dataPointID, ev.target.__node, ev.data.changes);
+ this.multipleRecordsSavingPromise = savedRecordsPromise;
});
};
}
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 979e0a41496..3943446d9b6 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
@@ -289,6 +289,18 @@ ListRenderer.include({
return null;
},
/**
+ * Returns whether the list is in multiple record edition from a given record.
+ *
+ * @private
+ * @param {string} recordId
+ * @returns {boolean}
+ */
+ inMultipleRecordEdition: function (recordId) {
+ const record = this._getRecord(recordId) || {};
+ const recordIds = [...new Set([recordId, ...this.selection])];
+ return this.editable && recordIds.length > 1 && record.res_id;
+ },
+ /**
* Removes the line associated to the given recordID (the index of the row
* is found thanks to the old state), then updates the state.
*