[IMP] web: SearchView: Allow user to quickly search on mobile

Currently the search panel is nice for a search with filters but
that was not 100% efficient for simple research without filters.

The Search is now integrated in the form view, with the ability
to open the Search panel to apply filters or group by.

Task ID : 1924760

closes odoo/odoo#36183

Signed-off-by: Adrien Dieudonné (adr) <adr@odoo.com>
This commit is contained in:
Odoo's Mergebot
2019-09-16 19:13:39 +02:00
committed by GitHub
6 changed files with 143 additions and 65 deletions
@@ -50,6 +50,7 @@ var ControlPanelRenderer = Renderer.extend({
this.$subMenus = null;
this.action = params.action;
this.displaySearchMenu = true;
this.isMobile = config.device.isMobile;
this.menusSetup = false;
this.searchMenuTypes = params.searchMenuTypes || [];
this.subMenus = {};
@@ -9,9 +9,9 @@ if (!config.device.isMobile) {
}
ControlPanelRenderer.include({
template:'MobileControlPanel',
events:_.extend({}, ControlPanelRenderer.prototype.events, {
'click .o_mobile_search_close, .o_mobile_search_show_result, .o_enable_searchview': '_toggleMobileSearchView',
'click .o_mobile_search_close, .o_mobile_search_show_result, .o_toggle_searchview_full': '_toggleMobileSearchView',
'click .o_enable_searchview': '_toggleMobileQuickSearchView',
'click': '_onOpenMobileSearchView',
'click .o_mobile_search_clear_facets': '_onEmptyAll',
'show.bs.dropdown .o_mobile_search_filter .o_dropdown': '_onDropdownToggle',
@@ -49,17 +49,40 @@ ControlPanelRenderer.include({
_renderSearchBar: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
self.searchBar.$el.detach().insertAfter(self.$('.o_mobile_search_header'));
self._renderSearchviewInput();
});
},
_renderSearchviewInput: function () {
if (this.$('.o_toggle_searchview_full').is(':visible') && !this.$('.o_mobile_search').is(':visible')) {
this.$('.o_toggle_searchview_full').toggleClass('btn-secondary', !!this.state.query.length);
this.searchBar.$el.detach().insertAfter(this.$('.o_mobile_search'));
} else {
this.searchBar.$el.detach().insertAfter(this.$('.o_mobile_search_header'));
}
},
/**
* Toggles mobile search view screen.
*
* @private
*/
_toggleMobileSearchView: function () {
this.$('.o_enable_searchview').toggleClass('btn-secondary', !!this.state.query.length);
this.$('.o_mobile_search').toggleClass('o_hidden');
this._renderSearchviewInput();
},
/**
* Toggles mobile quick search view on screen.
*
* @private
*/
_toggleMobileQuickSearchView: function () {
this.$('.o_cp_searchview').toggleClass('o_searchview_quick');
this.$('.breadcrumb').toggleClass('o_hidden',
this.$('.o_cp_searchview').hasClass('o_searchview_quick'));
this.$('.o_toggle_searchview_full')
.toggleClass('o_hidden')
.toggleClass('btn-secondary', !!this.state.query.length);
this._renderSearchviewInput();
this.$('.o_enable_searchview').toggleClass("fa-search").toggleClass("fa-close");
},
//--------------------------------------------------------------------------
+18 -10
View File
@@ -1,13 +1,24 @@
.o_control_panel {
display: flex;
flex-flow: row wrap;
border-bottom: 1px solid darken($o-control-panel-background-color, 20%);
@include o-webclient-padding($top: 10px, $bottom: 10px);
background-color: $o-control-panel-background-color;
> .breadcrumb {
width: 50%;
> div {
display: flex;
justify-content: space-between;
min-height: 30px;
}
.breadcrumb, .o_cp_left {
flex: 1 1 auto;
}
.o_cp_searchview, .o_cp_right {
flex: 0 0 50%;
}
.breadcrumb {
font-size: 18px;
> li {
@@ -19,8 +30,7 @@
}
}
> .o_cp_searchview {
width: 50%;
.o_cp_searchview {
min-height: $o-cp-breadcrumb-height;
}
@@ -30,10 +40,9 @@
background: white;
}
> .o_cp_left {
.o_cp_left {
display: flex;
justify-content: space-between;
width: 50%;
margin-top: 5px;
> .o_cp_sidebar {
@@ -65,9 +74,8 @@
}
}
> .o_cp_right {
.o_cp_right {
display: flex;
width: 50%;
margin-top: 5px;
> .o_cp_pager {
+33 -45
View File
@@ -148,18 +148,22 @@
<t t-name="ControlPanel">
<div class="o_control_panel">
<ol class="breadcrumb" role="navigation"/>
<div class="o_cp_searchview" role="search">
<t t-call="SearchView"/>
<div>
<ol class="breadcrumb" role="navigation"/>
<div class="o_cp_searchview" role="search">
<t t-if="widget.withSearchBar" t-call="SearchView"/>
</div>
</div>
<div class="o_cp_left">
<div class="o_cp_buttons" role="toolbar" aria-label="Control panel toolbar"/>
<aside class="o_cp_sidebar"/>
</div>
<div class="o_cp_right">
<div class="btn-group o_search_options" role="search"/>
<nav class="o_cp_pager" role="search" aria-label="Pager"/>
<nav class="btn-group o_cp_switch_buttons" role="toolbar" aria-label="View switcher"/>
<div>
<div class="o_cp_left">
<div class="o_cp_buttons" role="toolbar" aria-label="Control panel toolbar"/>
<aside class="o_cp_sidebar"/>
</div>
<div class="o_cp_right">
<div class="btn-group o_search_options" role="search"/>
<nav class="o_cp_pager" role="search" aria-label="Pager"/>
<nav class="btn-group o_cp_switch_buttons" role="toolbar" aria-label="View switcher"/>
</div>
</div>
</div>
</t>
@@ -1164,7 +1168,14 @@
</div>
<div t-name="SearchView" class="o_searchview" role="search" aria-autocomplete="list">
<span class="o_searchview_more fa" title="Advanced Search..." role="img" aria-label="Advanced Search..."/>
<t t-if="widget.isMobile">
<t t-call="MobileSearchView"/>
<button class="o_toggle_searchview_full o_hidden btn fa fa-filter"/>
<button class="o_enable_searchview btn btn-link fa fa-search"/>
</t>
<t t-else="">
<span class="o_searchview_more fa" title="Advanced Search..." role="img" aria-label="Advanced Search..."/>
</t>
</div>
<div t-name="SearchView.SearchBar" class="o_searchview_input_container">
@@ -1233,40 +1244,17 @@
</select>
</t>
<t t-name="MobileControlPanel">
<div class="o_control_panel">
<ol class="breadcrumb" role="navigation"/>
<div class="o_cp_searchview" role="search">
<t t-call="MobileSearchView"/>
</div>
<div class="o_cp_left">
<div class="o_cp_buttons" role="toolbar" aria-label="Control panel toolbar"/>
<aside class="o_cp_sidebar"/>
</div>
<div class="o_cp_right">
<div class="btn-group o_search_options" role="search"/>
<nav class="o_cp_pager" role="search" aria-label="Pager"/>
<nav class="btn-group o_cp_switch_buttons" role="toolbar" aria-label="View switcher"/>
</div>
<div t-name="MobileSearchView" class="o_mobile_search o_hidden">
<div class="o_mobile_search_header">
<span class="o_mobile_search_close float-left mt16 mb16 mr8 ml16">
<i class="fa fa-arrow-left"/>
<strong class="float-right ml8">FILTER</strong>
</span>
<span class="float-right o_mobile_search_clear_facets mt16 mr16">CLEAR</span>
</div>
</t>
<t t-name="MobileSearchView">
<div class="o_searchview" role="search" aria-autocomplete="list">
<button class="o_enable_searchview btn fa fa-search"/>
<div class="o_mobile_search o_hidden">
<div class="o_mobile_search_header">
<span class="o_mobile_search_close float-left mt16 mb16 mr8 ml16">
<i class="fa fa-arrow-left"/>
<strong class="float-right ml8">FILTER</strong>
</span>
<span class="float-right o_mobile_search_clear_facets mt16 mr16">CLEAR</span>
</div>
<div class="o_mobile_search_filter o_search_options mb8 mt8 ml16 mr16"/>
<div class="btn btn-primary o_mobile_search_show_result">SEE RESULT</div>
</div>
</div>
</t>
<div class="o_mobile_search_filter o_search_options mb8 mt8 ml16 mr16"/>
<div class="btn btn-primary o_mobile_search_show_result">SEE RESULT</div>
</div>
<div t-name="AddNewFavoriteMenu">
<button type="button" class="dropdown-item o_generator_menu o_add_favorite o_menu_header">Save Current Search</button>
@@ -39,8 +39,61 @@ QUnit.module('Mobile Search view Screen', {
};
},
}, function () {
QUnit.test('can activate a filter with mobile search view', async function (assert) {
assert.expect(3);
QUnit.test('can activate a filter with mobile search view in quick search mode', async function (assert) {
assert.expect(7);
var searchRPCFlag = false;
var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function (route, args) {
if (searchRPCFlag) {
assert.deepEqual(args.domain, [['foo', 'ilike', 'A']],
"domain should have been properly transferred to list view");
}
return this._super.apply(this, arguments);
},
});
await actionManager.doAction(1);
assert.strictEqual($('button.o_enable_searchview.fa-search').length, 1,
"should display a button to open the searchview");
assert.deepEqual($('.o_searchview_input_container:visible').length, 0,
"Quick search input should be hidden");
// open the search view
await testUtils.dom.click($('button.o_enable_searchview'));
assert.deepEqual($('.o_toggle_searchview_full:visible').length, 1,
"should display a button to expand the searchview");
assert.deepEqual($('.o_searchview_input_container:visible').length, 1,
"Quick search input should now be visible");
searchRPCFlag = true;
// use quick search input
$('.o_searchview_input')
.val("A")
.trigger($.Event('keypress', { which: 65, keyCode: 65 }));
await testUtils.nextTick();
actionManager.$('.o_searchview_input')
.trigger($.Event('keydown', { which: $.ui.keyCode.ENTER, keyCode: $.ui.keyCode.ENTER }));
await testUtils.nextTick();
// close quick search
await testUtils.dom.click($('button.o_enable_searchview.fa-close'));
assert.deepEqual($('.o_toggle_searchview_full:visible').length, 0,
"Expand icon shoud be hidden");
assert.deepEqual($('.o_searchview_input_container:visible').length, 0,
"Quick search input should be hidden");
actionManager.destroy();
});
QUnit.test('can activate a filter with mobile search view in full screen mode', async function (assert) {
assert.expect(4);
var filterActiveFlag = false;
@@ -61,20 +114,25 @@ QUnit.module('Mobile Search view Screen', {
assert.ok(!$('.o_mobile_search').is(':visible'),
'mobile search view is not visible');
// open the search view
await testUtils.dom.click($('button.o_enable_searchview'));
// open it in full screen
await testUtils.dom.click($('.o_toggle_searchview_full'));
assert.ok($('.o_mobile_search').is(':visible'),
'mobile search view is visible');
// open filter sub menu
await testUtils.dom.click($('button.o_dropdown_toggler_btn').first());
filterActiveFlag = true;
// click on Active filter
await testUtils.dom.click($('.o_filters_menu a:contains(Active)'));
// closing search view
await testUtils.dom.click($('.o_mobile_search_close'));
assert.ok(!$('.o_mobile_search').is(':visible'),
'mobile search view is not visible');
actionManager.destroy();
});
@@ -604,7 +604,7 @@ tour.register('main_flow_tour', {
position: "bottom"
}, {
trigger: ".o_data_row:first",
extra_trigger: '.o_control_panel > .breadcrumb:contains("Sales Orders")',
extra_trigger: '.o_control_panel .breadcrumb:contains("Sales Orders")',
content: _t("Go to the last sale order"),
position: "right"
}, {