forked from Techsystech/web
[14.0] [FIX] web_advanced_search: Many2one selection on Filters missing
parent
d043e62ae7
commit
fa2d0ef54c
|
@ -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,
|
||||||
|
});
|
||||||
|
});
|
|
@ -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);
|
||||||
|
});
|
|
@ -1,6 +1,4 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?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>
|
<templates>
|
||||||
<t t-inherit="web.FilterMenu" t-inherit-mode="extension" owl="1">
|
<t t-inherit="web.FilterMenu" t-inherit-mode="extension" owl="1">
|
||||||
<xpath expr="//CustomFilterItem" position="after">
|
<xpath expr="//CustomFilterItem" position="after">
|
||||||
|
@ -8,6 +6,24 @@
|
||||||
<AdvancedFilterItem fields="props.fields" />
|
<AdvancedFilterItem fields="props.fields" />
|
||||||
</xpath>
|
</xpath>
|
||||||
</t>
|
</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">
|
<t t-name="web_advanced_search.AdvancedFilterItem" owl="1">
|
||||||
<div class="o_generator_menu">
|
<div class="o_generator_menu">
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -12,10 +12,18 @@
|
||||||
type="text/javascript"
|
type="text/javascript"
|
||||||
src="/web_advanced_search/static/src/js/control_panel/filter_menu.js"
|
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
|
<script
|
||||||
type="text/javascript"
|
type="text/javascript"
|
||||||
src="/web_advanced_search/static/src/js/human_domain.js"
|
src="/web_advanced_search/static/src/js/human_domain.js"
|
||||||
/>
|
/>
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="/web_advanced_search/static/src/js/relational.js"
|
||||||
|
/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
Loading…
Reference in New Issue