[IMP] web: DomainSelector: enhance user experience

The purpose of this commit is to improve the domain selector UX with
multiple little changes:

- The model field selector popover is now autofocused when opened
- Removal of a div that appeared during a hover on "add leaf" and
"ellipsis button"
- Caret icon next to the root node selector
- Minor CSS changes

task-2861497

closes odoo/odoo#99321

Signed-off-by: Géry Debongnie <ged@odoo.com>
This commit is contained in:
Dardenne Florent (dafl)
2022-09-16 14:25:21 +02:00
parent bd8afccf16
commit af89b46c5b
10 changed files with 40 additions and 36 deletions
@@ -17,4 +17,8 @@ DomainSelectorBranchOperator.template = "web.DomainSelectorBranchOperator";
DomainSelectorBranchOperator.props = {
node: Object,
readonly: Boolean,
showCaret: {
type: Boolean,
optional: true,
},
};
@@ -3,23 +3,23 @@
<t t-name="web.DomainSelectorBranchOperator" owl="1">
<t t-if="!props.readonly">
<div class="btn-group o_domain_tree_operator_selector" aria-atomic="true">
<Dropdown togglerClass="'btn btn-sm btn-primary o_domain_tree_operator_caret'">
<div class="d-inline-flex o_domain_tree_operator_selector" aria-atomic="true">
<Dropdown togglerClass="'btn btn-link btn-sm btn-primary py-0 px-1 o_domain_tree_operator_caret'" showCaret="props.showCaret">
<t t-set-slot="toggler">
<t t-if="props.node.operator === '&amp;'">All</t>
<t t-elif="props.node.operator === '|'">Any</t>
<t t-elif="props.node.operator === '!'">None</t>
<t t-if="props.node.operator === '&amp;'">all</t>
<t t-elif="props.node.operator === '|'">any</t>
<t t-elif="props.node.operator === '!'">none</t>
</t>
<DropdownItem onSelected="() => this.onOperatorSelected('&amp;')">All</DropdownItem>
<DropdownItem onSelected="() => this.onOperatorSelected('|')">Any</DropdownItem>
<DropdownItem onSelected="() => this.onOperatorSelected('&amp;')">all</DropdownItem>
<DropdownItem onSelected="() => this.onOperatorSelected('|')">any</DropdownItem>
</Dropdown>
</div>
</t>
<t t-else="">
<strong>
<t t-if="props.node.operator === '&amp;'">ALL</t>
<t t-elif="props.node.operator === '|'">ANY</t>
<t t-elif="props.node.operator === '!'">NONE</t>
<t t-if="props.node.operator === '&amp;'">all</t>
<t t-elif="props.node.operator === '|'">any</t>
<t t-elif="props.node.operator === '!'">none</t>
</strong>
</t>
</t>
@@ -42,7 +42,7 @@
<t t-set="field" t-value="getFieldComponent(fieldInfo.type)" />
<t t-if="field">
<div>
<select class="o_domain_leaf_operator_select o_input" t-on-change="onOperatorChange">
<select class="o_domain_leaf_operator_select o_input text-truncate pe-1" t-on-change="onOperatorChange">
<t t-foreach="field.getOperators()" t-as="operator" t-key="operator.value">
<option
t-att-value="operator_index"
@@ -27,7 +27,7 @@
</t>
<t t-else="">
<span>Match records with </span>
<DomainSelectorBranchOperator node="node" readonly="props.readonly" />
<DomainSelectorBranchOperator node="node" readonly="props.readonly" showCaret="true" />
<span> of the following rules:</span>
<div class="o_domain_node_children_container">
<t t-foreach="node.operands" t-as="subNode" t-key="subNode.id">
@@ -91,6 +91,7 @@ export class ModelFieldSelector extends Component {
},
{
closeOnClickAway: true,
popoverClass: "o-popover-no-arrow",
}
);
}
@@ -4,6 +4,7 @@ import { sortBy } from "../utils/arrays";
import { useModelField } from "./model_field_hook";
import { fuzzyLookup } from "@web/core/utils/search";
import { useAutofocus } from "../utils/hooks";
const { Component, onWillStart } = owl;
@@ -15,6 +16,9 @@ export class ModelFieldSelectorPopover extends Component {
this.fieldKeys = [];
this.searchValue = "";
this.fullFieldName = this.fieldNameChain.join(".");
if (!this.env.isSmall) {
useAutofocus();
}
onWillStart(async () => {
await this.loadFields();
@@ -24,7 +24,7 @@
<t t-if="props.showSearchInput">
<div class="o_field_selector_search mt-2">
<input type="text" placeholder='Search...' class="o_input" t-att-value="searchValue" t-on-input="onSearch" />
<input type="text" placeholder='Search...' class="o_input" t-att-value="searchValue" t-on-input="onSearch" t-ref="autofocus" />
</div>
</t>
</div>
@@ -66,5 +66,13 @@
&.o-popover--le .popover-arrow, &.o-popover--re .popover-arrow {
bottom: $popover-border-radius;
}
&.o-popover-no-arrow > .popover-arrow {
display: none;
}
&.o-popover-no-arrow {
border: 0px;
}
}
/*!rtl:end:ignore*/
@@ -42,13 +42,12 @@
&.o_domain_tree {
> .o_domain_tree_header {
position: relative;
.o_domain_tree_operator_caret::after {
@include o-caret-down;
}
}
.o_domain_tree_operator_caret::after {
@include o-caret-down;
}
> .o_domain_node_children_container {
& .o_domain_node_children_container {
padding-left: $o-domain-selector-indent;
}
@@ -180,21 +179,4 @@
}
}
}
&.o_hover_btns {
background: darken(white, 3%);
}
&.o_hover_add_node {
margin-bottom: $o-domain-animation-bar-height;
transition: margin .15s ease .5s;
&::after {
max-height: $o-domain-animation-bar-height;
transition: max-height .15s ease .5s;
}
&.o_hover_add_inset_node::after {
left: $o-domain-selector-indent;
}
}
}
@@ -68,7 +68,7 @@ QUnit.module("Components", (hooks) => {
QUnit.module("ModelFieldSelector");
QUnit.test("creating a field chain from scratch", async (assert) => {
assert.expect(14);
assert.expect(15);
function getValueFromDOM(el) {
return [...el.querySelectorAll(".o_field_selector_chain_part")]
@@ -101,6 +101,11 @@ QUnit.module("Components", (hooks) => {
// Focusing the field selector input should open a field selector popover
await click(target, ".o_field_selector");
assert.strictEqual(
target.querySelector("input.o_input[placeholder='Search...']"),
document.activeElement,
"the field selector input should be focused"
);
assert.containsOnce(
target,
".o_field_selector_popover",