3
0
Fork 0

[14.0] [FIX] web_advanced_search: Many2one selection on Filters missing

16.0
Raf Ven 2021-08-11 14:18:33 +02:00
parent 08d34c021e
commit 6814ced9c9
4 changed files with 223 additions and 2 deletions

View File

@ -0,0 +1,86 @@
odoo.define("web_advanced_search.CustomFilterItem", function (require) {
"use strict";
const CustomFilterItem = require("web.CustomFilterItem");
const FieldMany2One = require("web.relational_fields").FieldMany2One;
const Relational = require("web_advanced_search.RelationalOwl");
const {FIELD_TYPES} = require("web.searchUtils");
const {useListener} = require("web.custom_hooks");
CustomFilterItem.patch("web_advanced_search.CustomFilterItem", (T) => {
class AdvancedCustomFilterItem extends T {
constructor() {
super(...arguments);
this.state.field = false;
this.OPERATORS.relational = this.OPERATORS.char;
this.FIELD_TYPES.many2one = "relational";
useListener("m2xchange", this._onM2xDataChanged);
}
_addDefaultCondition() {
super._addDefaultCondition(...arguments);
const condition = this.state.conditions[
this.state.conditions.length - 1
];
condition.index = _.uniqueId("condition_");
}
/**
* @private
* @param {Object} condition
*/
_setDefaultValue(condition) {
const fieldType = this.fields[condition.field].type;
const genericType = FIELD_TYPES[fieldType];
if (genericType === "relational") {
condition.displayedValue = "";
} else {
super._setDefaultValue(...arguments);
}
}
/**
* @private
* @param {Object} condition
* @param {Event} ev
*/
_onFieldSelect(condition, ev) {
super._onFieldSelect(...arguments);
this.state.field = this.fields[ev.target.selectedIndex];
this.state.fieldindex = ev.target.selectedIndex;
this.state.conditionIndex = condition.index;
}
/**
* @private
* @param {Object} condition
* @param {Event} ev
*/
_onOperatorSelect(condition, ev) {
this.trigger("operatorChange");
this.state.operator = ev.target[ev.target.selectedIndex].value;
super._onOperatorSelect(...arguments);
}
_onM2xDataChanged(event) {
const fieldindex = this.fields
.map((field) => field.name)
.indexOf(event.detail.field);
const condition = this.state.conditions.filter(
(con) =>
con.field === fieldindex &&
con.index === this.state.conditionIndex
);
if (condition.length) {
condition[0].value = event.detail.changes.id;
condition[0].value = event.detail.changes.display_name;
}
}
}
return AdvancedCustomFilterItem;
});
// Extends HomeMenuWrapper components
CustomFilterItem.components = Object.assign({}, CustomFilterItem.components, {
FieldMany2One,
Relational,
});
});

View File

@ -0,0 +1,111 @@
odoo.define("web_advanced_search.RelationalOwl", function (require) {
"use strict";
const BasicModel = require("web.BasicModel");
const patchMixin = require("web.patchMixin");
const {ComponentAdapter} = require("web.OwlCompatibility");
const relationalFields = require("web.relational_fields");
const FieldMany2One = relationalFields.FieldMany2One;
const FieldManagerMixin = require("web.FieldManagerMixin");
const {useListener} = require("web.custom_hooks");
/* global owl */
const {Component} = owl;
const {xml} = owl.tags;
const AdvancedSearchWidget = FieldMany2One.extend(FieldManagerMixin, {
init: function (parent) {
const field = parent.__owl__.parent.field;
const model = new BasicModel(field.relation);
// Create dummy record with only the field the user is searching
const params = {
fieldNames: [field.name],
modelName: field.relation,
context: field.context,
type: "record",
viewType: "default",
fieldsInfo: {
default: {},
},
fields: {
[field.name]: _.omit(
field,
// User needs all records, to actually produce a new domain
"domain",
// Onchanges make no sense in this context, there's no record
"onChange"
),
},
};
if (field.type.endsWith("2many")) {
// X2many fields behave like m2o in the search context
params.fields[field.name].type = "many2one";
}
params.fieldsInfo.default[field.name] = {};
// Emulate `model.load()`, without RPC-calling `default_get()`
this.dataPointID = model._makeDataPoint(params).id;
model.generateDefaultValues(this.dataPointID, {});
this._super(parent, field.name, this._get_record(model), {
mode: "edit",
attrs: {
options: {
no_create_edit: true,
no_create: true,
no_open: true,
no_quick_create: true,
},
},
});
FieldManagerMixin.init.call(this, model);
},
_get_record: function (model) {
return model.get(this.dataPointID);
},
/**
* @override
*/
_confirmChange: function (id, fields, event) {
this.trigger_up("m2xchange", {
data: event.data,
changes: event.data.changes[fields[0]],
field: fields[0],
});
this.dataPointID = id;
return this.reset(this._get_record(this.model), event);
},
});
/**
* A search field for relational fields.
*
* It implements and extends the `FieldManagerMixin`, and acts as if it
* were a reduced dummy controller. Some actions "mock" the underlying
* model, since sometimes we use a char widget to fill related fields
* (which is not supported by that widget), and fields need an underlying
* model implementation, which can only hold fake data, given a search view
* has no data on it by definition.
*/
class Relational extends Component {
// eslint-disable-next-line no-unused-vars
constructor(parent, component, props) {
super(...arguments);
this.field = parent.state.field;
this.operator = parent.state.operator;
this.FieldWidget = false;
this.set_widget();
useListener("operatorChange", this.set_widget);
}
/**
* @override
*/
set_widget() {
this.FieldWidget = AdvancedSearchWidget;
}
}
Relational.template = xml`
<div>
<ComponentAdapter Component="FieldWidget" />
</div>`;
Relational.components = {ComponentAdapter};
return patchMixin(Relational);
});

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2017-2018 Jairo Llopis <jairo.llopis@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<templates>
<t t-inherit="web.FilterMenu" t-inherit-mode="extension" owl="1">
<xpath expr="//CustomFilterItem" position="after">
@ -8,6 +6,24 @@
<AdvancedFilterItem fields="props.fields" />
</xpath>
</t>
<t t-inherit="web.CustomFilterItem" t-inherit-mode="extension" owl="1">
<xpath expr="//select[@t-elif]" position="after">
<t t-elif="fieldType === 'many2one'">
<t
t-if="selectedOperator.symbol === '=' || selectedOperator.symbol === '!='"
>
<Relational />
</t>
<input
t-else=""
type="text"
class="o_input"
t-att-value="condition.displayedValue"
t-on-input="_onValueInput(condition)"
/>
</t>
</xpath>
</t>
<t t-name="web_advanced_search.AdvancedFilterItem" owl="1">
<div class="o_generator_menu">
<button

View File

@ -12,10 +12,18 @@
type="text/javascript"
src="/web_advanced_search/static/src/js/control_panel/filter_menu.js"
/>
<script
type="text/javascript"
src="/web_advanced_search/static/src/js/control_panel/custom_filter_item.js"
/>
<script
type="text/javascript"
src="/web_advanced_search/static/src/js/human_domain.js"
/>
<script
type="text/javascript"
src="/web_advanced_search/static/src/js/relational.js"
/>
</xpath>
</template>
</odoo>