summaryrefslogtreecommitdiff
path: root/addons/web/static
diff options
context:
space:
mode:
authorMartin Trigaux <mat@odoo.com>2019-07-22 14:47:52 +0200
committerMartin Trigaux <mat@odoo.com>2019-07-22 14:47:52 +0200
commit5a6a414e2c5a281df886a2779caf618e5f633ee9 (patch)
tree722412d4d6e684d6fcc3ac4c04bc9bb9c21cc8dc /addons/web/static
parente532d4df0d3767c7a6dfb0d0e336f332bbdca8b7 (diff)
parentaadc4a9f0be4a17ab3f25c48ac26feabf9aaab9a (diff)
[MERGE] Forward port of saas-12.4 to master up to aadc4a9f0be4
Diffstat (limited to 'addons/web/static')
-rw-r--r--addons/web/static/src/js/views/abstract_controller.js10
-rw-r--r--addons/web/static/src/js/views/basic/basic_controller.js4
-rw-r--r--addons/web/static/src/js/views/form/form_controller.js11
-rw-r--r--addons/web/static/src/js/views/list/list_renderer.js2
-rw-r--r--addons/web/static/tests/chrome/action_manager_tests.js74
-rw-r--r--addons/web/static/tests/views/calendar_tests.js6
-rw-r--r--addons/web/static/tests/views/list_tests.js36
7 files changed, 131 insertions, 12 deletions
diff --git a/addons/web/static/src/js/views/abstract_controller.js b/addons/web/static/src/js/views/abstract_controller.js
index 53bcc0d5bad..07a0109e9a7 100644
--- a/addons/web/static/src/js/views/abstract_controller.js
+++ b/addons/web/static/src/js/views/abstract_controller.js
@@ -136,8 +136,11 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
* @override
*/
canBeRemoved: function () {
- // AAB: get rid of this option when on_hashchange mechanism is improved
- return this.discardChanges(undefined, {readonlyIfRealDiscard: true});
+ // AAB: get rid of 'readonlyIfRealDiscard' option when on_hashchange mechanism is improved
+ return this.discardChanges(undefined, {
+ noAbandon: true,
+ readonlyIfRealDiscard: true,
+ });
},
/**
* Discards the changes made on the record associated to the given ID, or
@@ -151,9 +154,10 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
*
* @param {string} [recordID]
* if not given, we consider all the changes made by the controller
+ * @param {Object} [options]
* @returns {Promise} resolved if properly discarded, rejected otherwise
*/
- discardChanges: function (recordID) {
+ discardChanges: function (recordID, options) {
return Promise.resolve();
},
/**
diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js
index 610e7e6dc6b..e76aec046e8 100644
--- a/addons/web/static/src/js/views/basic/basic_controller.js
+++ b/addons/web/static/src/js/views/basic/basic_controller.js
@@ -374,14 +374,16 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* the new record to be in edit mode too, but the view manager calls
* this function as the URL changes...) @todo get rid of this when
* the webclient/action_manager's hashchange mechanism is improved.
+ * @param {boolean} [options.noAbandon=false]
* @returns {Promise}
*/
_discardChanges: function (recordID, options) {
var self = this;
recordID = recordID || this.handle;
+ options = options || {};
return this.canBeDiscarded(recordID)
.then(function (needDiscard) {
- if (options && options.readonlyIfRealDiscard && !needDiscard) {
+ if (options.noAbandon || (options.readonlyIfRealDiscard && !needDiscard)) {
return;
}
self.model.discardChanges(recordID);
diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js
index b3a65cc2bde..83edf12212b 100644
--- a/addons/web/static/src/js/views/form/form_controller.js
+++ b/addons/web/static/src/js/views/form/form_controller.js
@@ -49,13 +49,18 @@ var FormController = BasicController.extend({
this.autofocus();
},
/**
- * Force mode back to readonly. Whenever we leave a form view, it is saved,
- * and should no longer be in edit mode.
+ * This hook is called when a form view is restored (by clicking on the
+ * breadcrumbs). In general, we force mode back to readonly, because
+ * whenever we leave a form view by stacking another action on the top of
+ * it, it is saved, and should no longer be in edit mode. However, there is
+ * a special case for new records for which we still want to be in 'edit'
+ * as no record has been created (changes have been discarded before
+ * leaving).
*
* @override
*/
willRestore: function () {
- this.mode = 'readonly';
+ this.mode = this.model.isNew(this.handle) ? 'edit' : 'readonly';
},
//--------------------------------------------------------------------------
diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js
index abc487a98fb..b4d6e5e036b 100644
--- a/addons/web/static/src/js/views/list/list_renderer.js
+++ b/addons/web/static/src/js/views/list/list_renderer.js
@@ -620,7 +620,7 @@ var ListRenderer = BasicRenderer.extend({
var $pager = this._renderGroupPager(group);
$lastCell.addClass('o_group_pager').append($pager);
}
- if (group.isOpen && this.groupbys[groupBy]) {
+ if (groupLevel === 0 && group.isOpen && this.groupbys[groupBy]) {
var $buttons = this._renderGroupButtons(group, this.groupbys[groupBy]);
if ($buttons.length) {
var $buttonSection = $('<div>', {
diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js
index ac944425a8c..6b572af4285 100644
--- a/addons/web/static/tests/chrome/action_manager_tests.js
+++ b/addons/web/static/tests/chrome/action_manager_tests.js
@@ -3502,6 +3502,80 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
+ QUnit.test('execute action from dirty, new record, and come back', async function (assert) {
+ assert.expect(19);
+
+ this.data.partner.fields.bar.default = 1;
+ this.archs['partner,false,form'] = '<form>' +
+ '<field name="foo"/>' +
+ '<field name="bar" readonly="1"/>' +
+ '</form>';
+
+ var actionManager = await createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method || route);
+ if (args.method === 'get_formview_action') {
+ return Promise.resolve({
+ res_id: 1,
+ res_model: 'partner',
+ type: 'ir.actions.act_window',
+ views: [[false, 'form']],
+ });
+ }
+ return this._super.apply(this, arguments);
+ },
+ intercepts: {
+ do_action: function (ev) {
+ actionManager.doAction(ev.data.action, {});
+ },
+ },
+ });
+
+ // execute an action and create a new record
+ await actionManager.doAction(3);
+ await testUtils.dom.click(actionManager.$('.o_list_button_add'));
+ assert.containsOnce(actionManager, '.o_form_view.o_form_editable');
+ assert.containsOnce(actionManager, '.o_form_uri:contains(First record)');
+ assert.strictEqual(actionManager.$('.o_control_panel .breadcrumb-item').text(),
+ "PartnersNew");
+
+ // set form view dirty and open m2o record
+ await testUtils.fields.editInput(actionManager.$('input[name=foo]'), 'val');
+ await testUtils.dom.click(actionManager.$('.o_form_uri:contains(First record)'));
+ assert.containsOnce($('body'), '.modal'); // confirm discard dialog
+
+ // confirm discard changes
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+
+ assert.containsOnce(actionManager, '.o_form_view.o_form_readonly');
+ assert.strictEqual(actionManager.$('.o_control_panel .breadcrumb-item').text(),
+ "PartnersNewFirst record");
+
+ // go back to New using the breadcrumbs
+ await testUtils.dom.click(actionManager.$('.o_control_panel .breadcrumb-item:nth(1) a'));
+ assert.containsOnce(actionManager, '.o_form_view.o_form_editable');
+ assert.strictEqual(actionManager.$('.o_control_panel .breadcrumb-item').text(),
+ "PartnersNew");
+
+ assert.verifySteps([
+ '/web/action/load', // action 3
+ 'load_views', // views of action 3
+ '/web/dataset/search_read', // list
+ 'default_get', // form (create)
+ 'name_get', // m2o in form
+ 'get_formview_action', // click on m2o
+ 'load_views', // form view of dynamic action
+ 'read', // form
+ 'default_get', // form (create)
+ 'name_get', // m2o in form
+ ]);
+
+ actionManager.destroy();
+ });
+
QUnit.module('Actions in target="new"');
QUnit.test('can execute act_window actions in target="new"', async function (assert) {
diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js
index babb22a5ba1..16e304c14a6 100644
--- a/addons/web/static/tests/views/calendar_tests.js
+++ b/addons/web/static/tests/views/calendar_tests.js
@@ -34,10 +34,8 @@ function _preventScroll(ev) {
}
QUnit.module('Views', {
- before: function () {
- window.addEventListener('scroll', _preventScroll, true);
- },
beforeEach: function () {
+ window.addEventListener('scroll', _preventScroll, true);
session.uid = -1; // TO CHECK
this.data = {
event: {
@@ -106,7 +104,7 @@ QUnit.module('Views', {
},
};
},
- after: function () {
+ afterEach: function () {
window.removeEventListener('scroll', _preventScroll, true);
},
}, function () {
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index ae3cbf7fe82..2447be64837 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -2068,6 +2068,42 @@ QUnit.module('Views', {
list.destroy();
});
+ QUnit.test('groupby node with a button in inner groupbys', async function (assert) {
+ assert.expect(5);
+
+ var list = await createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '<tree>' +
+ '<field name="foo"/>' +
+ '<groupby name="currency_id">' +
+ '<button string="Button 1" type="object" name="button_method"/>' +
+ '</groupby>' +
+ '</tree>',
+ groupBy: ['bar', 'currency_id'],
+ });
+
+ assert.containsN(list, '.o_group_header', 2,
+ "there should be 2 group headers");
+ assert.containsNone(list, '.o_group_header button',
+ "there should be no button in the header");
+
+ await testUtils.dom.click(list.$('.o_group_header:eq(0)'));
+
+ assert.containsN(list, 'tbody:eq(1) .o_group_header', 2,
+ "there should be 2 inner groups header");
+ assert.containsNone(list, 'tbody:eq(1) .o_group_header button',
+ "there should be no button in the header");
+
+ await testUtils.dom.click(list.$('tbody:eq(1) .o_group_header:eq(0)'));
+
+ assert.containsNone(list, '.o_group_header button',
+ "there should be no button in the header");
+
+ list.destroy();
+ });
+
QUnit.test('groupby node with a button with modifiers', async function (assert) {
assert.expect(11);