[IMP] web,*: highlight quick create feature to user
Generally, Users are not necessarily aware that they can quick create a most records by simply typing in their name+enter in the many2xxx field input. The exact purpose of this commit is to make sure the user discovers the quick create feature of our many2xxx fields. For that, when the input is empty, display 'Start typing to create a record...' at the bottom of the dropdown when can_create is set and no_create_edit option not set. So the user can easily understand that by typing and pressing enter will create the new record. Also "Search and Create" options in the dropdown only been shown to the user when it type anything in the input box as the same case in the "Create" option. Task : 2266557 Co-authored-by: Mohammed Shekha <msh@openerp.com> Co-authored-by: Julien Mougenot <jum@odoo.com>
This commit is contained in:
committed by
Julien Mougenot
co-authored by
Mohammed Shekha
Julien Mougenot
parent
a392da1601
commit
eacbec1e03
@@ -70,8 +70,8 @@ QUnit.module('sale_expense', {
|
||||
});
|
||||
var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
|
||||
await testUtils.fields.many2one.clickOpenDropdown('sale_order_id');
|
||||
assert.containsN($dropdown, 'li:not(.o_m2o_dropdown_option)', 8, 'autocomplete should contains 8 suggestions');
|
||||
assert.containsN($dropdown, 'li.o_m2o_dropdown_option', 1, 'autocomplete should contain only one option');
|
||||
assert.containsN($dropdown, 'li:not(.o_m2o_dropdown_option)', 9);
|
||||
assert.containsNone($dropdown, 'li.o_m2o_dropdown_option');
|
||||
assert.containsNone($dropdown, 'li.o_m2o_dropdown_option:contains("Search More...")', "Should not display the 'Search More... option'");
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
@@ -600,7 +600,7 @@ var FieldMany2One = AbstractField.extend({
|
||||
});
|
||||
}
|
||||
// create and edit ...
|
||||
if (self.can_create && !self.nodeOptions.no_create_edit) {
|
||||
if (self.can_create && !self.nodeOptions.no_create_edit && search_val.length > 0) {
|
||||
var createAndEditAction = function () {
|
||||
// Clear the value in case the user clicks on discard
|
||||
self.$('input').val('');
|
||||
@@ -616,7 +616,13 @@ var FieldMany2One = AbstractField.extend({
|
||||
label: _t("No results to show..."),
|
||||
});
|
||||
}
|
||||
|
||||
if (!self.value && !search_val.length && self.can_create
|
||||
&& (!self.nodeOptions.no_quick_create || !self.nodeOptions.no_create_edit)) {
|
||||
values.push({
|
||||
label: _t("Start typing..."),
|
||||
classname: 'o_m2o_start_typing',
|
||||
});
|
||||
}
|
||||
resolve(values);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,9 +24,17 @@
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
&.o_m2o_dropdown_option {
|
||||
&.o_m2o_dropdown_option, &.o_m2o_start_typing {
|
||||
text-indent: 20px
|
||||
}
|
||||
&.o_m2o_start_typing {
|
||||
font-style: italic;
|
||||
cursor: default;
|
||||
a.ui-menu-item-wrapper, a.ui-state-active, a.ui-state-active:hover {
|
||||
background: none;
|
||||
color: #adb5bd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1314,8 +1314,7 @@ QUnit.module('fields', {}, function () {
|
||||
});
|
||||
await testUtils.form.clickEdit(form);
|
||||
|
||||
await testUtils.fields.many2one.clickOpenDropdown('timmy');
|
||||
await testUtils.fields.many2one.clickItem('timmy','Create and Edit');
|
||||
await testUtils.fields.many2one.createAndEdit('timmy',"Ralts");
|
||||
assert.containsOnce($(document), '.modal .o_form_view', "should have opened the modal");
|
||||
|
||||
// Create multiple records with save & new
|
||||
@@ -1454,8 +1453,8 @@ QUnit.module('fields', {}, function () {
|
||||
await testUtils.fields.many2one.clickOpenDropdown('partner_ids');
|
||||
|
||||
const $dropdown1 = form.$('.o_field_many2one input').autocomplete('widget');
|
||||
assert.containsOnce($dropdown1, 'li.o_m2o_dropdown_option:contains(Create and Edit...)',
|
||||
'autocomplete should contain Create and Edit...');
|
||||
assert.containsOnce($dropdown1, 'li.o_m2o_start_typing:contains(Start typing...)',
|
||||
'autocomplete should contain Start typing...');
|
||||
|
||||
await testUtils.fields.many2one.clickItem('partner_ids', 'Search More');
|
||||
|
||||
@@ -1468,7 +1467,7 @@ QUnit.module('fields', {}, function () {
|
||||
await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'),
|
||||
'Something that does not exist', 'keydown');
|
||||
// await testUtils.nextTick();
|
||||
assert.containsN($dropdown1, 'li.o_m2o_dropdown_option', 2,
|
||||
assert.containsN(form.$('.o_field_many2one input').autocomplete('widget'), 'li.o_m2o_dropdown_option', 2,
|
||||
'autocomplete should contain Create and Create and Edit... options');
|
||||
|
||||
// set turtle_bar false -> create and delete actions are no longer available
|
||||
|
||||
@@ -625,8 +625,7 @@ QUnit.module('fields', {}, function () {
|
||||
|
||||
assert.strictEqual(document.activeElement, input, "Input should be focused when activated");
|
||||
|
||||
await testUtils.fields.many2one.clickOpenDropdown('trululu');
|
||||
await testUtils.fields.many2one.clickItem('trululu', 'Create');
|
||||
await testUtils.fields.many2one.createAndEdit('trululu', "ABC");
|
||||
|
||||
// At this point, if the focus is correctly registered by the m2o, there
|
||||
// should be only one modal (the "Create" one) and none for saving changes.
|
||||
@@ -667,8 +666,78 @@ QUnit.module('fields', {}, function () {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('empty many2one field', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
const form = await createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: `<form string="Partners">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="trululu"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>`,
|
||||
viewOptions: {
|
||||
mode: 'edit',
|
||||
},
|
||||
});
|
||||
|
||||
const $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
|
||||
await testUtils.fields.many2one.clickOpenDropdown('trululu');
|
||||
assert.containsNone($dropdown, 'li.o_m2o_dropdown_option',
|
||||
'autocomplete should not contains dropdown options');
|
||||
assert.containsOnce($dropdown, 'li.o_m2o_start_typing',
|
||||
'autocomplete should contains start typing option');
|
||||
|
||||
await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="trululu"] input'),
|
||||
'abc', 'keydown');
|
||||
await testUtils.nextTick();
|
||||
assert.containsN($dropdown, 'li.o_m2o_dropdown_option', 2,
|
||||
'autocomplete should contains 2 dropdown options');
|
||||
assert.containsNone($dropdown, 'li.o_m2o_start_typing',
|
||||
'autocomplete should not contains start typing option');
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('empty many2one field with node options', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const form = await createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: `<form string="Partners">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="trululu" options="{'no_create_edit': 1}"/>
|
||||
<field name="product_id" options="{'no_create_edit': 1, 'no_quick_create': 1}"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>`,
|
||||
viewOptions: {
|
||||
mode: 'edit',
|
||||
},
|
||||
});
|
||||
|
||||
const $dropdownTrululu = form.$('.o_field_many2one[name="trululu"] input').autocomplete('widget');
|
||||
const $dropdownProduct = form.$('.o_field_many2one[name="product_id"] input').autocomplete('widget');
|
||||
await testUtils.fields.many2one.clickOpenDropdown('trululu');
|
||||
assert.containsOnce($dropdownTrululu, 'li.o_m2o_start_typing',
|
||||
'autocomplete should contains start typing option');
|
||||
|
||||
await testUtils.fields.many2one.clickOpenDropdown('product_id');
|
||||
assert.containsNone($dropdownProduct, 'li.o_m2o_start_typing',
|
||||
'autocomplete should contains start typing option');
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('many2one in edit mode', async function (assert) {
|
||||
assert.expect(16);
|
||||
assert.expect(17);
|
||||
|
||||
// create 10 partners to have the 'Search More' option in the autocomplete dropdown
|
||||
for (var i = 0; i < 10; i++) {
|
||||
@@ -716,9 +785,11 @@ QUnit.module('fields', {}, function () {
|
||||
assert.ok($dropdown.is(':visible'),
|
||||
'clicking on the m2o input should open the dropdown if it is not open yet');
|
||||
assert.strictEqual($dropdown.find('li:not(.o_m2o_dropdown_option)').length, 7,
|
||||
'autocomplete should contains 7 suggestions');
|
||||
assert.strictEqual($dropdown.find('li.o_m2o_dropdown_option').length, 2,
|
||||
'autocomplete should contain "Search More" and Create and Edit..."');
|
||||
'autocomplete should contains 8 suggestions');
|
||||
assert.strictEqual($dropdown.find('li.o_m2o_dropdown_option').length, 1,
|
||||
'autocomplete should contain "Search More"');
|
||||
assert.containsNone($dropdown, 'li.o_m2o_start_typing',
|
||||
'autocomplete should not contains start typing option if value is available');
|
||||
|
||||
await testUtils.fields.many2one.clickOpenDropdown('trululu');
|
||||
assert.ok(!$dropdown.is(':visible'),
|
||||
@@ -808,9 +879,7 @@ QUnit.module('fields', {}, function () {
|
||||
},
|
||||
});
|
||||
|
||||
// click on 'Create and Edit' in m2o dropdown
|
||||
await testUtils.fields.many2one.clickOpenDropdown('product_id');
|
||||
await testUtils.fields.many2one.clickItem('product_id', 'Create and Edit');
|
||||
await testUtils.fields.many2one.createAndEdit('product_id', "ABC");
|
||||
assert.containsOnce(document.body, '.modal .o_form_view');
|
||||
|
||||
// quick create 'new value'
|
||||
@@ -891,8 +960,8 @@ QUnit.module('fields', {}, function () {
|
||||
|
||||
await testUtils.fields.many2one.clickOpenDropdown('trululu');
|
||||
assert.isVisible($dropdown);
|
||||
assert.containsN($dropdown, 'li:not(.o_m2o_dropdown_option)', 3,
|
||||
'autocomplete should contains 3 suggestions');
|
||||
assert.containsN($dropdown, 'li:not(.o_m2o_dropdown_option)', 4,
|
||||
'autocomplete should contains 4 suggestions');
|
||||
|
||||
// search with leading spaces
|
||||
form.$('.o_field_many2one input').val(' first').trigger('keydown').trigger('keyup');
|
||||
|
||||
@@ -264,7 +264,7 @@ QUnit.module('fields', {}, function () {
|
||||
});
|
||||
|
||||
QUnit.test('O2M with parented m2o and domain on parent.m2o', async function (assert) {
|
||||
assert.expect(3);
|
||||
assert.expect(4);
|
||||
|
||||
/* records in an o2m can have a m2o pointing to themselves
|
||||
* in that case, a domain evaluation on that field followed by name_search
|
||||
@@ -299,8 +299,7 @@ QUnit.module('fields', {}, function () {
|
||||
|
||||
await testUtils.dom.click(form.$('.o_field_x2many_list[name=turtles] .o_field_x2many_list_row_add a'));
|
||||
|
||||
await testUtils.fields.many2one.clickOpenDropdown('parent_id');
|
||||
await testUtils.fields.many2one.clickHighlightedItem('parent_id');
|
||||
await testUtils.fields.many2one.createAndEdit('parent_id');
|
||||
|
||||
var $modal = $('.modal-content');
|
||||
|
||||
@@ -8131,8 +8130,7 @@ QUnit.module('fields', {}, function () {
|
||||
assert.containsOnce(form, '.o_selected_row',
|
||||
"should have create a new row in edition");
|
||||
|
||||
await testUtils.fields.many2one.clickOpenDropdown('turtle_trululu');
|
||||
await testUtils.fields.many2one.clickItem('turtle_trululu','Create and Edit...');
|
||||
await testUtils.fields.many2one.createAndEdit('turtle_trululu', "ABC");
|
||||
|
||||
assert.strictEqual($('.modal .o_form_view').length, 1,
|
||||
"should have opened a form view in a dialog");
|
||||
|
||||
@@ -1370,8 +1370,8 @@ QUnit.module('relational_fields', {
|
||||
// add an other existing tag
|
||||
var $input = form.$('.o_field_many2manytags input');
|
||||
await testUtils.fields.many2one.clickOpenDropdown('timmy');
|
||||
assert.strictEqual($input.autocomplete('widget').find('li').length, 1,
|
||||
"autocomplete dropdown should have 1 entry");
|
||||
assert.strictEqual($input.autocomplete('widget').find('li').length, 2,
|
||||
"autocomplete dropdown should have 2 entry");
|
||||
assert.strictEqual($input.autocomplete('widget').find('li a:contains("red")').length, 1,
|
||||
"autocomplete dropdown should contain 'red'");
|
||||
await testUtils.fields.many2one.clickHighlightedItem('timmy');
|
||||
@@ -1479,8 +1479,8 @@ QUnit.module('relational_fields', {
|
||||
// add an other existing tag
|
||||
var $input = form.$('.o_field_many2manytags input');
|
||||
await testUtils.fields.many2one.clickOpenDropdown('timmy');
|
||||
assert.strictEqual($input.autocomplete('widget').find('li').length, 1,
|
||||
"autocomplete dropdown should have 1 entry");
|
||||
assert.strictEqual($input.autocomplete('widget').find('li').length, 2,
|
||||
"autocomplete dropdown should have 2 entry");
|
||||
assert.strictEqual($input.autocomplete('widget').find('li a:contains("silver")').length, 1,
|
||||
"autocomplete dropdown should contain 'silver'");
|
||||
await testUtils.fields.many2one.clickHighlightedItem('timmy');
|
||||
@@ -3452,6 +3452,7 @@ QUnit.module('relational_fields', {
|
||||
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
|
||||
await testUtils.dom.click(form.$el.find('.o_input_dropdown>input'));
|
||||
|
||||
await testUtils.fields.editInput(form.$('.o_field_many2one input'), 'ABC');
|
||||
// click create and edit
|
||||
await testUtils.dom.click($('.ui-autocomplete .ui-menu-item a:contains(Create and)').trigger('mouseenter'));
|
||||
|
||||
|
||||
@@ -324,7 +324,7 @@ QUnit.module('Views', {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
if (route === '/web/dataset/call_kw/instrument/create') {
|
||||
assert.deepEqual(args.args, [{badassery: [[6, false, [1]]], name: false}],
|
||||
assert.deepEqual(args.args, [{badassery: [[6, false, [1]]], name: "ABC"}],
|
||||
'The method create should have been called with the right arguments');
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
@@ -334,8 +334,7 @@ QUnit.module('Views', {
|
||||
|
||||
await testUtils.form.clickEdit(form);
|
||||
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
|
||||
await testUtils.dom.click(form.$('.o_field_widget .o_field_many2one[name=instrument] input'));
|
||||
await testUtils.dom.click($('ul.ui-autocomplete.ui-front.ui-menu.ui-widget.ui-widget-content li.o_m2o_dropdown_option').first());
|
||||
await testUtils.fields.many2one.createAndEdit("instrument");
|
||||
|
||||
var $modal = $('.modal-lg');
|
||||
|
||||
@@ -495,7 +494,7 @@ QUnit.module('Views', {
|
||||
});
|
||||
|
||||
QUnit.test('propagate can_create onto the search popup o2m', async function (assert) {
|
||||
assert.expect(3);
|
||||
assert.expect(4);
|
||||
|
||||
this.data.instrument.records = [
|
||||
{id: 1, name: 'Tromblon1'},
|
||||
@@ -539,9 +538,13 @@ QUnit.module('Views', {
|
||||
|
||||
await testUtils.fields.many2one.clickOpenDropdown('instrument');
|
||||
|
||||
assert.notOk($('.ui-autocomplete a:contains(Create and Edit)').length,
|
||||
'Create and edit not present in dropdown');
|
||||
assert.containsNone(form, '.ui-autocomplete a:contains(Start typing...)');
|
||||
|
||||
await testUtils.fields.editInput(form.el.querySelector(".o_field_many2one[name=instrument] input"), "a");
|
||||
|
||||
assert.containsNone(form, '.ui-autocomplete a:contains(Create and Edit)');
|
||||
|
||||
await testUtils.fields.editInput(form.el.querySelector(".o_field_many2one[name=instrument] input"), "");
|
||||
await testUtils.fields.many2one.clickItem('instrument', 'Search More...');
|
||||
|
||||
var $modal = $('.modal-dialog.modal-lg');
|
||||
|
||||
@@ -25,6 +25,10 @@ odoo.define('web.test.x2many', function (require) {
|
||||
content: "click on moderator one2many drop down",
|
||||
trigger: 'tr:contains(Moderator) .o_input_dropdown > input',
|
||||
run: 'click',
|
||||
}, {
|
||||
content: "insert value in moderator",
|
||||
trigger: 'input.ui-autocomplete-input',
|
||||
run: 'text test',
|
||||
}, {
|
||||
content: "click on 'Create and Edit...'",
|
||||
trigger: '.ui-autocomplete .o_m2o_dropdown_option:last',
|
||||
|
||||
Reference in New Issue
Block a user