[FIX] web: FieldDomain in debug: domains with dynamic content
In debug mode, the FieldDomain displays a textarea to allow the manual edition of complex domains. However, when those domains contain dynamic content (e.g. datetime stuff), the evaluated version of that content was displayed, which isn't what we want. We want to see the raw version of the domain as written in db, and be able to edit it. This commit fixes that issue. Moreover, we also ensure to keep whitespaces and new lines, which can be useful for large domains. closes odoo/odoo#80866 X-original-commit: 15301a1ddaf00e51688d8134b7cb19baf386577c Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com> Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -3795,7 +3795,7 @@ var FieldDomain = AbstractField.extend({
|
||||
// we don't want to recompute the count if the domain has been edited
|
||||
// from the debug textarea (for performance reasons, as it might be costly)
|
||||
this.debugEdition = !!e.data.debug;
|
||||
this._setValue(Domain.prototype.arrayToString(e.data.domain));
|
||||
this._setValue(e.data.domain);
|
||||
},
|
||||
/**
|
||||
* Called when the in-dialog domain selector value is confirmed
|
||||
|
||||
@@ -377,10 +377,11 @@ var DomainTree = DomainNode.extend({
|
||||
*/
|
||||
_renderChildrenTo: function ($to) {
|
||||
var $div = $("<div/>");
|
||||
return Promise.all(_.map(this.children, (function (child) {
|
||||
const children = this.children;
|
||||
return Promise.all(_.map(children, (function (child) {
|
||||
return child.appendTo($div);
|
||||
}).bind(this))).then((function () {
|
||||
_.each(this.children, function (child) {
|
||||
_.each(children, function (child) {
|
||||
child.$el.appendTo($to); // Forced to do it this way so that the
|
||||
// children are not misordered
|
||||
});
|
||||
@@ -469,6 +470,12 @@ var DomainSelector = DomainTree.extend({
|
||||
domain_changed: "_onDomainChange",
|
||||
}),
|
||||
|
||||
init(parent, model, domain) {
|
||||
this._super(...arguments);
|
||||
this.rawDomain = domain;
|
||||
this._redrawId = 0;
|
||||
},
|
||||
|
||||
start: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
@@ -541,7 +548,7 @@ var DomainSelector = DomainTree.extend({
|
||||
// Display technical domain if in debug mode
|
||||
this.$debugInput = this.$(".o_domain_debug_input");
|
||||
if (this.$debugInput.length) {
|
||||
this.$debugInput.val(Domain.prototype.arrayToString(this.getDomain()));
|
||||
this.$debugInput.val(this.rawDomain);
|
||||
dom.autoresize(this.$debugInput);
|
||||
}
|
||||
|
||||
@@ -557,9 +564,13 @@ var DomainSelector = DomainTree.extend({
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_redraw: function (domain) {
|
||||
const _redrawId = ++this._redrawId;
|
||||
var oldChildren = this.children.slice();
|
||||
this._initialize(domain || this.getDomain());
|
||||
return this._renderChildrenTo($("<div/>")).then((function () {
|
||||
if (_redrawId !== this._redrawId) {
|
||||
return;
|
||||
}
|
||||
_.each(oldChildren, function (child) { child.destroy(); });
|
||||
this.renderElement();
|
||||
this._postRender();
|
||||
@@ -589,14 +600,19 @@ var DomainSelector = DomainTree.extend({
|
||||
// is syntax-valid a "domain_changed" event is triggered to notify the
|
||||
// parent, but the widget isn't redrawn.
|
||||
// If the domain is not valid, a warning is shown to the user.
|
||||
var domain;
|
||||
const rawDomain = e.currentTarget.value;
|
||||
try {
|
||||
domain = Domain.prototype.stringToArray(e.currentTarget.value);
|
||||
Domain.prototype.stringToArray(rawDomain);
|
||||
} catch (err) { // If there is a syntax error, just ignore the change
|
||||
this.displayNotification({ title: _t("Syntax error"), message: _t("Domain not properly formed"), type: 'danger' });
|
||||
return;
|
||||
}
|
||||
this.trigger_up("domain_changed", { child: this, noRedraw: true, domain, debug: true });
|
||||
this.trigger_up("domain_changed", {
|
||||
child: this,
|
||||
noRedraw: true,
|
||||
domain: rawDomain,
|
||||
debug: true,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Called when a (child's) domain has changed -> redraw the entire tree
|
||||
@@ -607,6 +623,7 @@ var DomainSelector = DomainTree.extend({
|
||||
_onDomainChange: function (e) {
|
||||
// Add the current domain to the payload if not already there
|
||||
e.data.domain = e.data.domain || this.getDomain();
|
||||
this.rawDomain = Domain.prototype.arrayToString(e.data.domain);
|
||||
// If a subdomain notifies that it underwent some modifications, the
|
||||
// DomainSelector catches the message and performs a full re-rendering.
|
||||
if (!e.data.noRedraw) {
|
||||
|
||||
@@ -8056,6 +8056,55 @@ QUnit.module('basic_fields', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('domain field: edit domain with dynamic content', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const originalDebug = odoo.debug;
|
||||
odoo.debug = true;
|
||||
let rawDomain = `
|
||||
[
|
||||
["date", ">=", datetime.datetime.combine(context_today() + relativedelta(days = -365), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")]
|
||||
]
|
||||
`;
|
||||
this.data.partner.records[0].foo = rawDomain;
|
||||
this.data.partner.fields.bar.type = "char";
|
||||
this.data.partner.records[0].bar = "partner";
|
||||
|
||||
const form = await createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="bar"/>
|
||||
<field name="foo" widget="domain" options="{'model': 'bar'}"/>
|
||||
</form>`,
|
||||
async mockRPC(route, args) {
|
||||
if (args.method === 'write') {
|
||||
assert.strictEqual(args.args[1].foo, rawDomain);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
res_id: 1,
|
||||
viewOptions: {
|
||||
mode: 'edit',
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(form.$(".o_domain_debug_input").val(), rawDomain);
|
||||
|
||||
rawDomain = `
|
||||
[
|
||||
["date", ">=", datetime.datetime.combine(context_today() + relativedelta(days = -1), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")]
|
||||
]
|
||||
`;
|
||||
await testUtils.fields.editAndTrigger(form.$('.o_domain_debug_input'), rawDomain, ["change"]);
|
||||
await testUtils.form.clickSave(form);
|
||||
|
||||
form.destroy();
|
||||
odoo.debug = originalDebug;
|
||||
});
|
||||
|
||||
QUnit.module('FieldProgressBar');
|
||||
|
||||
QUnit.test('Field ProgressBar: max_value should update', async function (assert) {
|
||||
|
||||
@@ -272,15 +272,13 @@ QUnit.module('DomainSelector', {
|
||||
assert.expect(5);
|
||||
|
||||
const $target = $("#qunit-fixture");
|
||||
let newValue;
|
||||
|
||||
// Create the domain selector and its mock environment
|
||||
const Parent = Widget.extend({
|
||||
custom_events: {
|
||||
domain_changed: (e) => {
|
||||
assert.deepEqual(e.data.domain, [
|
||||
["product_id", "ilike", 1],
|
||||
["id", "=", 0]
|
||||
]);
|
||||
assert.deepEqual(e.data.domain, newValue);
|
||||
assert.ok(e.data.debug);
|
||||
},
|
||||
},
|
||||
@@ -294,7 +292,7 @@ QUnit.module('DomainSelector', {
|
||||
await domainSelector.appendTo($target);
|
||||
|
||||
assert.containsOnce(domainSelector, ".o_domain_node", "should have a single domain node");
|
||||
const newValue = `
|
||||
newValue = `
|
||||
[
|
||||
['product_id', 'ilike', 1],
|
||||
['id', '=', 0]
|
||||
|
||||
Reference in New Issue
Block a user