diff options
| author | Julien Mougenot <jum@odoo.com> | 2019-08-14 13:16:04 +0000 |
|---|---|---|
| committer | Julien Mougenot <jum@odoo.com> | 2019-08-16 09:03:49 +0000 |
| commit | dd27b2e9c6935d095611c75ffa4f06cc565e4802 (patch) | |
| tree | 0f713d53859c3a465ac5ad0351a9cdb2d36558ef /addons/web/static/src | |
| parent | 291dad6bc869eeeba9bbb5cf13d498ece9266d2d (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.js | 88 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/list/list_editable_renderer.js | 12 |
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. * |
