[IMP] web: hide "Remove" button in FormViewDialog

When we open any x2m record (in a FormViewDialog), there is a "Remove"
button to delete/unlink the opened record from parent.

This button is placed besides "Discard" button and it creates little
confusion in some cases. For example, in list view, there's already a
bin / 'x' icon depending on the field type using which people are used
to delete/unlink the record. And when they open a record, they might
accidentally click "Remove" button instead of "Discard".

To avoid this, now we won't show "Remove" button when we open record from
x2many list view. However, we have to keep this button in case x2many of
kanban as there's no other way to remove the record.

task-1886913

closes odoo/odoo#34333

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Pratima Gupta
2019-06-26 09:04:06 +00:00
committed by Vincent Schippefilt
parent 83aaea9e5c
commit e719824271
4 changed files with 130 additions and 42 deletions
@@ -1609,7 +1609,7 @@ var FieldOne2Many = FieldX2Many.extend({
fields_view: this.attrs.views && this.attrs.views.form,
parentID: this.value.id,
viewInfo: this.view,
deletable: this.activeActions.delete,
deletable: this.activeActions.delete && params.deletable,
}));
},
@@ -1714,7 +1714,7 @@ var FieldOne2Many = FieldX2Many.extend({
on_remove: function () {
self._setValue({operation: 'DELETE', ids: [id]});
},
deletable: this.activeActions.delete,
deletable: this.activeActions.delete && this.view.arch.tag !== 'tree',
readonly: this.mode === 'readonly',
});
},
@@ -1788,7 +1788,7 @@ var FieldMany2Many = FieldX2Many.extend({
self._setValue({operation: 'FORGET', ids: [ev.data.id]});
},
readonly: this.mode === 'readonly',
deletable: this.activeActions.delete,
deletable: this.activeActions.delete && this.view.arch.tag !== 'tree',
string: this.string,
});
},
@@ -350,7 +350,7 @@ QUnit.module('fields', {}, function () {
});
QUnit.test('many2many list (non editable): edition', async function (assert) {
assert.expect(27);
assert.expect(29);
this.data.partner.records[0].timmy = [12, 14];
this.data.partner_type.records.push({ id: 15, display_name: "bronze", color: 6 });
@@ -386,10 +386,9 @@ QUnit.module('fields', {}, function () {
return this._super.apply(this, arguments);
},
});
assert.ok(!form.$('.o_list_record_remove').length,
assert.containsNone(form.$('.o_list_record_remove'),
'delete icon should not be visible in readonly');
assert.ok(!form.$('.o_field_x2many_list_row_add').length,
assert.containsNone(form.$('.o_field_x2many_list_row_add'),
'"Add an item" should not be visible in readonly');
await testUtils.form.clickEdit(form);
@@ -406,6 +405,9 @@ QUnit.module('fields', {}, function () {
// edit existing subrecord
await testUtils.dom.click(form.$('.o_list_view tbody tr:first()'));
assert.containsNone($('.modal .modal-footer .o_btn_remove'),
'there should not be a "Remove" button in the modal footer');
await testUtils.fields.editInput($('.modal .o_form_view input'), 'new name');
await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name',
@@ -413,6 +415,8 @@ QUnit.module('fields', {}, function () {
// add new subrecords
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsNone($('.modal .modal-footer .o_btn_remove'),
'there should not be a "Remove" button in the modal footer');
assert.strictEqual($('.modal .o_list_view').length, 1,
"a modal should be open");
assert.strictEqual($('.modal .o_list_view .o_data_row').length, 1,
@@ -1478,6 +1478,7 @@ QUnit.module('fields', {}, function () {
},
});
assert.containsOnce(form, '.o_data_row',
"the onchange should have created one record in the relation");
@@ -1532,7 +1533,7 @@ QUnit.module('fields', {}, function () {
"there should be two records in the one2many in the dialog");
// click on 'Discard'
await testUtils.dom.clickFirst($('.modal-footer .btn-secondary'));
await testUtils.dom.click($('.modal-footer .btn-secondary'));
assert.strictEqual($('.modal').length, 0, "dialog should be closed");
@@ -2140,7 +2141,7 @@ QUnit.module('fields', {}, function () {
});
QUnit.test('one2many list: unlink two records', async function (assert) {
assert.expect(9);
assert.expect(8);
this.data.partner.records[0].p = [1, 2, 4];
var form = await createView({
View: FormView,
@@ -2159,12 +2160,12 @@ QUnit.module('fields', {}, function () {
var commands = args.args[1].p;
assert.strictEqual(commands.length, 3,
'should have generated three commands');
assert.ok(commands[0][0] === 4 && commands[0][1] === 4,
assert.ok(commands[0][0] === 4 && commands[0][1] === 2,
'should have generated the command 4 (LINK_TO) with id 4');
assert.ok(commands[1][0] === 3 && commands[1][1] === 1,
assert.ok(commands[1][0] === 4 && commands[1][1] === 4,
'should have generated the command 4 (LINK_TO) with id 4');
assert.ok(commands[2][0] === 3 && commands[2][1] === 1,
'should have generated the command 3 (UNLINK) with id 1');
assert.ok(commands[2][0] === 3 && commands[2][1] === 2,
'should have generated the command 3 (UNLINK) with id 2');
}
return this._super.apply(this, arguments);
},
@@ -2187,20 +2188,16 @@ QUnit.module('fields', {}, function () {
"should have 2 remove buttons (a record is supposed to have been unlinked)");
await testUtils.dom.click(form.$('tr.o_data_row').first());
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
'there should be a modal having Remove Button');
await testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
assert.containsNone($('.modal .modal-footer .o_btn_remove'),
'there should not be a modal having Remove Button');
assert.containsOnce(form, 'td.o_list_record_remove button',
"should have 1 delete button (another record is supposed to have been unlinked)");
// save and check that the correct command has been generated
await testUtils.dom.click($('.modal .btn-secondary'))
await testUtils.form.clickSave(form);
form.destroy();
});
QUnit.test('one2many list: deleting two records', async function (assert) {
assert.expect(9);
QUnit.test('one2many list: deleting one records', async function (assert) {
assert.expect(7);
this.data.partner.records[0].p = [1, 2, 4];
var form = await createView({
View: FormView,
@@ -2219,11 +2216,11 @@ QUnit.module('fields', {}, function () {
var commands = args.args[1].p;
assert.strictEqual(commands.length, 3,
'should have generated three commands');
assert.ok(commands[0][0] === 4 && commands[0][1] === 4,
'should have generated the command 4 (LINK_TO) with id 4');
assert.ok(commands[1][0] === 2 && commands[1][1] === 1,
'should have generated the command 2 (DELETE) with id 1');
assert.ok(commands[2][0] === 2 && commands[2][1] === 2,
assert.ok(commands[0][0] === 4 && commands[0][1] === 2,
'should have generated the command 4 (LINK_TO) with id 2');
assert.ok(commands[1][0] === 4 && commands[1][1] === 4,
'should have generated the command 2 (LINK_TO) with id 1');
assert.ok(commands[2][0] === 2 && commands[2][1] === 1,
'should have generated the command 2 (DELETE) with id 2');
}
return this._super.apply(this, arguments);
@@ -2244,15 +2241,7 @@ QUnit.module('fields', {}, function () {
await testUtils.dom.click(form.$('td.o_list_record_remove button').first());
assert.containsN(form, 'td.o_list_record_remove button', 2,
"should have 2 remove buttons (a record is supposed to have been deleted)");
await testUtils.dom.click(form.$('tr.o_data_row').first());
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
'there should be a modal having Remove Button');
await testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
assert.containsOnce(form, 'td.o_list_record_remove button',
"should have 1 remove button (another record is supposed to have been deleted)");
"should have 2 remove buttons");
// save and check that the correct command has been generated
await testUtils.form.clickSave(form);
@@ -5674,6 +5663,41 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
QUnit.test('one2many list edition, no "Remove" button in modal', async function (assert) {
assert.expect(2);
this.data.partner.fields.foo.default = false;
var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form string="Partners">' +
'<field name="p">' +
'<tree>' +
'<field name="foo"/>' +
'</tree>' +
'<form string="Partners">' +
'<field name="display_name"/>' +
'</form>' +
'</field>' +
'</form>',
res_id: 1,
});
await testUtils.form.clickEdit(form);
await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
assert.containsOnce($(document), $('.modal'), 'there should be a modal opened');
assert.containsNone($('.modal .modal-footer .o_btn_remove'),
'modal should not contain a "Remove" button');
// Discard a modal
await testUtils.dom.click($('.modal-footer .btn-secondary'));
await testUtils.form.clickDiscard(form);
form.destroy();
});
QUnit.test('x2many fields use their "mode" attribute', async function (assert) {
assert.expect(1);
@@ -5933,12 +5957,12 @@ QUnit.module('fields', {}, function () {
View: FormView,
model: 'partner',
data: this.data,
arch: '<form string="Partners">' +
'<field name="turtles">' +
'<tree editable="bottom">' +
'<field name="turtle_trululu" required="1"/>' +
'</tree>' +
'</field>' +
arch: '<form>' +
'<field name="turtles">' +
'<tree editable="bottom">' +
'<field name="turtle_trululu" required="1"/>' +
'</tree>' +
'</field>' +
'</form>',
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
@@ -20,6 +20,7 @@ QUnit.module('relational_fields', {
qux: {string: "Qux", type: "float", digits: [16,1] },
p: {string: "one2many field", type: "one2many", relation: 'partner', relation_field: 'trululu'},
trululu: {string: "Trululu", type: "many2one", relation: 'partner'},
partner_ids: {string: "many2many field", type: "many2many", relation: 'partner'},
},
records: [{
id: 1,
@@ -114,6 +115,65 @@ QUnit.module('relational_fields', {
await testUtils.form.clickSave(form);
form.destroy();
});
QUnit.module('FieldMany2Many');
QUnit.test('many2many kanban: deletion in mobile', async function (assert) {
assert.expect(8);
this.data.partner.records[0].partner_ids = [2, 4];
var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form string="Partners">' +
'<field name="display_name"/>' +
'<field name="partner_ids">' +
'<kanban>' +
'<field name="display_name"/>' +
'<templates>' +
'<t t-name="kanban-box">' +
'<div class="oe_kanban_global_click">' +
'<span><t t-esc="record.display_name.value"/></span>' +
'</div>' +
'</t>' +
'</templates>' +
'</kanban>' +
'<form string="Partners">' +
'<field name="display_name"/>' +
'</form>' +
'</field>' +
'</form>',
res_id: 1,
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/partner/write') {
var commands = args.args[1].partner_ids;
assert.strictEqual(commands.length, 1,
'should have generated one commands');
assert.deepEqual(commands[0], [6, false, [4]] ,
'should properly write ids');
}
return this._super.apply(this, arguments);
},
});
assert.containsNone(form.$('.o_field_many2many .o-kanban-button-new'),
'"Add" button should not be visible in readonly');
await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_many2many .o-kanban-button-new',
'"Add" button should be visible in edit');
assert.containsN(form, '.o_kanban_record:not(.o_kanban_ghost)', 2,
"should have 2 records");
// open and delete record
await testUtils.dom.click(form.$('.oe_kanban_global_click').first());
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
'there should be a modal having "Remove" Button');
await testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
assert.containsNone($('.o_modal'), "modal should have been closed");
assert.containsOnce(form, '.o_kanban_record:not(.o_kanban_ghost)',
'should contain 1 records');
// save and check that the correct command has been generated
await testUtils.form.clickSave(form);
form.destroy();
});
});
});
});