[FIX] web: execute action from new record and go back
Let's assume a form view with a readonly many2one field with a default value. When creating a new record, the user can click on the many2one value, which should open the related record in a form view (stacked in the breadcrumbs). Before this rev., this didn't work: we actually came back to the previous view/action in the breadcrumbs, when trying to open the related record. closes odoo/odoo#33172 Signed-off-by: VincentSchippefilt <VincentSchippefilt@users.noreply.github.com>
This commit is contained in:
@@ -122,8 +122,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
|
||||
@@ -137,9 +140,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();
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -373,14 +373,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);
|
||||
|
||||
@@ -50,13 +50,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';
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -3347,6 +3347,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) {
|
||||
|
||||
Reference in New Issue
Block a user