[IMP] web: improve setting search
Before this commit, the setting search was done exclusively in some selected texts. These texts needed to be on some specific selectors (field, label, span.o_form_label and div.text-muted). Now, all text on a setting are searchable (including the text in buttons). This commit also re-structure the setting compilers file to remove the functions outside the class, this is done to standardize the compilers (setting, form and view). closes odoo/odoo#107226 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -3,192 +3,175 @@
|
||||
import { append, createElement, getTag } from "@web/core/utils/xml";
|
||||
import { FormCompiler } from "@web/views/form/form_compiler";
|
||||
import { toStringExpression } from "@web/views/utils";
|
||||
|
||||
function compileApp(el, params) {
|
||||
if (el.getAttribute("notApp") === "1") {
|
||||
return;
|
||||
}
|
||||
const module = {
|
||||
key: el.getAttribute("name"),
|
||||
string: el.getAttribute("string"),
|
||||
imgurl:
|
||||
el.getAttribute("logo") ||
|
||||
"/" + el.getAttribute("name") + "/static/description/icon.png",
|
||||
};
|
||||
params.modules.push(module);
|
||||
const settingsApp = createElement("SettingsApp", {
|
||||
key: toStringExpression(module.key),
|
||||
string: toStringExpression(module.string || ""),
|
||||
imgurl: toStringExpression(module.imgurl),
|
||||
selectedTab: "settings.selectedTab",
|
||||
});
|
||||
|
||||
for (const child of el.children) {
|
||||
append(settingsApp, this.compileNode(child, params));
|
||||
}
|
||||
|
||||
return settingsApp;
|
||||
}
|
||||
|
||||
function compileBlock(el, params) {
|
||||
const settingsContainer = createElement("SettingsBlock", {
|
||||
title: toStringExpression(el.getAttribute("title") || ""),
|
||||
tip: toStringExpression(el.getAttribute("help") || ""),
|
||||
});
|
||||
for (const child of el.children) {
|
||||
append(settingsContainer, this.compileNode(child, params));
|
||||
}
|
||||
return settingsContainer;
|
||||
}
|
||||
|
||||
function compileSetting(el, params) {
|
||||
const componentName = el.getAttribute("type") === "header" ? "SettingHeader" : "Setting";
|
||||
const setting = createElement(componentName, {
|
||||
title: toStringExpression(el.getAttribute("title") || ""),
|
||||
help: toStringExpression(el.getAttribute("help") || ""),
|
||||
companyDependent: el.getAttribute("company_dependent") === "1" || "false",
|
||||
documentation: toStringExpression(el.getAttribute("documentation") || ""),
|
||||
record: `this.props.record`,
|
||||
});
|
||||
let string = toStringExpression(el.getAttribute("string") || "");
|
||||
let addLabel = true;
|
||||
params.labels = [];
|
||||
Array.from(el.children).forEach((child, index) => {
|
||||
if (getTag(child, true) === "field" && index === 0) {
|
||||
const fieldSlot = createElement("t", { "t-set-slot": "fieldSlot" });
|
||||
const field = this.compileNode(child, params);
|
||||
if (field) {
|
||||
append(fieldSlot, field);
|
||||
setting.setAttribute("fieldInfo", field.getAttribute("fieldInfo"));
|
||||
|
||||
addLabel = child.hasAttribute("nolabel")
|
||||
? child.getAttribute("nolabel") !== "1"
|
||||
: true;
|
||||
const fieldName = child.getAttribute("name");
|
||||
string = child.hasAttribute("string")
|
||||
? toStringExpression(child.getAttribute("string"))
|
||||
: string;
|
||||
setting.setAttribute("fieldName", toStringExpression(fieldName));
|
||||
setting.setAttribute(
|
||||
"fieldId",
|
||||
toStringExpression(child.getAttribute("field_id") || fieldName)
|
||||
);
|
||||
}
|
||||
append(setting, fieldSlot);
|
||||
} else {
|
||||
append(setting, this.compileNode(child, params));
|
||||
}
|
||||
});
|
||||
setting.setAttribute("string", string);
|
||||
setting.setAttribute("addLabel", addLabel);
|
||||
setting.setAttribute("labels", JSON.stringify(params.labels));
|
||||
return setting;
|
||||
}
|
||||
|
||||
function compileField(el, params) {
|
||||
const res = this.compileField(el, params);
|
||||
if (el.hasAttribute("widget")) {
|
||||
const label = params.getFieldExpr(el.getAttribute("name"), el.getAttribute("widget"));
|
||||
if (label) {
|
||||
params.labels.push(label);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const labelsWeak = new WeakMap();
|
||||
function compileLabel(el, params) {
|
||||
const res = this.compileLabel(el, params);
|
||||
// It the node is a FormLabel component node, the label is
|
||||
// localized *after* the field.
|
||||
// We don't know yet if the label refers to a field or not.
|
||||
if (res.textContent && res.tagName !== "FormLabel") {
|
||||
params.labels.push(res.textContent.trim());
|
||||
labelsWeak.set(res, { textContent: res.textContent });
|
||||
highlightElement(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function compileGenericLabel(el, params) {
|
||||
const res = this.compileGenericNode(el, params);
|
||||
if (res.textContent) {
|
||||
params.labels.push(res.textContent.trim());
|
||||
highlightElement(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function highlightElement(el) {
|
||||
for (const child of el.childNodes) {
|
||||
if (child.nodeType === Node.TEXT_NODE) {
|
||||
if (child.textContent.trim()) {
|
||||
const highlight = createElement("HighlightText");
|
||||
highlight.setAttribute("originalText", `\`${child.textContent}\``);
|
||||
el.replaceChild(highlight, child);
|
||||
}
|
||||
} else if (child.childNodes.length) {
|
||||
highlightElement(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function compileForm(el, params) {
|
||||
const settingsPage = createElement("SettingsPage");
|
||||
settingsPage.setAttribute("slots", "{NoContentHelper:this.props.slots.NoContentHelper}");
|
||||
settingsPage.setAttribute("initialTab", "this.props.initialApp");
|
||||
settingsPage.setAttribute("t-slot-scope", "settings");
|
||||
|
||||
//props
|
||||
params.modules = [];
|
||||
|
||||
const res = this.compileForm(...arguments);
|
||||
res.classList.remove("o_form_nosheet");
|
||||
|
||||
settingsPage.setAttribute("modules", JSON.stringify(params.modules));
|
||||
|
||||
for (const child of res.childNodes) {
|
||||
append(settingsPage, this.compileNode(child, params));
|
||||
}
|
||||
while (res.lastChild) {
|
||||
res.removeChild(res.lastChild);
|
||||
}
|
||||
append(res, settingsPage);
|
||||
|
||||
return res;
|
||||
}
|
||||
import { isTextNode } from "@web/views/view_compiler";
|
||||
|
||||
export class SettingsFormCompiler extends FormCompiler {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.compilers.unshift(
|
||||
{ selector: "form", fn: compileForm },
|
||||
{ selector: "app", fn: compileApp },
|
||||
{ selector: "block", fn: compileBlock },
|
||||
{ selector: "setting", fn: compileSetting },
|
||||
// search terms and highlight :
|
||||
{ selector: "label", fn: compileLabel, doNotCopyAttributes: true },
|
||||
{ selector: "span.o_form_label", fn: compileGenericLabel },
|
||||
{ selector: "div.text-muted", fn: compileGenericLabel },
|
||||
{ selector: "field", fn: compileField }
|
||||
this.compilers.push(
|
||||
{ selector: "app", fn: this.compileApp },
|
||||
{ selector: "block", fn: this.compileBlock },
|
||||
{ selector: "setting", fn: this.compileSetting }
|
||||
);
|
||||
}
|
||||
createLabelFromField(fieldId, fieldName, fieldString, label, params) {
|
||||
const labelweak = labelsWeak.get(label);
|
||||
if (labelweak) {
|
||||
// Undo what we've done when we where not sure whether this label was attached to a field
|
||||
// Now, we now it is.
|
||||
label.textContent = labelweak.textContent;
|
||||
}
|
||||
const res = super.createLabelFromField(fieldId, fieldName, fieldString, label, params);
|
||||
if (labelweak || label.hasAttribute("data-no-label")) {
|
||||
// the work of pushing the label in the search structure is already done
|
||||
return res;
|
||||
}
|
||||
let labelText = label.textContent || fieldString;
|
||||
labelText = labelText ? labelText : params.record.fields[fieldName].string;
|
||||
|
||||
params.labels.push(labelText);
|
||||
compileForm(el, params) {
|
||||
const settingsPage = createElement("SettingsPage");
|
||||
settingsPage.setAttribute("slots", "{NoContentHelper:this.props.slots.NoContentHelper}");
|
||||
settingsPage.setAttribute("initialTab", "this.props.initialApp");
|
||||
settingsPage.setAttribute("t-slot-scope", "settings");
|
||||
|
||||
//props
|
||||
params.modules = [];
|
||||
|
||||
const res = super.compileForm(...arguments);
|
||||
res.classList.remove("o_form_nosheet");
|
||||
|
||||
settingsPage.setAttribute("modules", JSON.stringify(params.modules));
|
||||
|
||||
// Move the compiled content of the form inside the settingsPage
|
||||
while (res.firstChild) {
|
||||
append(settingsPage, res.firstChild);
|
||||
}
|
||||
append(res, settingsPage);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
compileApp(el, params) {
|
||||
if (el.getAttribute("notApp") === "1") {
|
||||
//An app noted with notApp="1" is not rendered.
|
||||
|
||||
//This hack is used when a technical module defines settings, and we don't want to render
|
||||
//the settings until the corresponding app is not installed.
|
||||
|
||||
// For example, when installing the module website_sale, the module sale is also installed,
|
||||
// but we don't want to render its settings (notApp="1").
|
||||
// On the contrary, when sale_management is installed, the module sale is also installed
|
||||
// but in this case we want to see its settings (notApp="0").
|
||||
return;
|
||||
}
|
||||
const module = {
|
||||
key: el.getAttribute("name"),
|
||||
string: el.getAttribute("string"),
|
||||
imgurl:
|
||||
el.getAttribute("logo") ||
|
||||
"/" + el.getAttribute("name") + "/static/description/icon.png",
|
||||
};
|
||||
params.modules.push(module);
|
||||
const settingsApp = createElement("SettingsApp", {
|
||||
key: toStringExpression(module.key),
|
||||
string: toStringExpression(module.string || ""),
|
||||
imgurl: toStringExpression(module.imgurl),
|
||||
selectedTab: "settings.selectedTab",
|
||||
});
|
||||
|
||||
for (const child of el.children) {
|
||||
append(settingsApp, this.compileNode(child, params));
|
||||
}
|
||||
|
||||
return settingsApp;
|
||||
}
|
||||
|
||||
compileBlock(el, params) {
|
||||
const settingsContainer = createElement("SettingsBlock", {
|
||||
title: toStringExpression(el.getAttribute("title") || ""),
|
||||
tip: toStringExpression(el.getAttribute("help") || ""),
|
||||
});
|
||||
for (const child of el.children) {
|
||||
append(settingsContainer, this.compileNode(child, params));
|
||||
}
|
||||
return settingsContainer;
|
||||
}
|
||||
|
||||
compileSetting(el, params) {
|
||||
const componentName = el.getAttribute("type") === "header" ? "SettingHeader" : "Setting";
|
||||
const setting = createElement(componentName, {
|
||||
title: toStringExpression(el.getAttribute("title") || ""),
|
||||
help: toStringExpression(el.getAttribute("help") || ""),
|
||||
companyDependent: el.getAttribute("company_dependent") === "1" || "false",
|
||||
documentation: toStringExpression(el.getAttribute("documentation") || ""),
|
||||
record: `this.props.record`,
|
||||
});
|
||||
let string = toStringExpression(el.getAttribute("string") || "");
|
||||
let addLabel = true;
|
||||
params.labels = [];
|
||||
Array.from(el.children).forEach((child, index) => {
|
||||
if (getTag(child, true) === "field" && index === 0) {
|
||||
const fieldSlot = createElement("t", { "t-set-slot": "fieldSlot" });
|
||||
const field = this.compileNode(child, params);
|
||||
if (field) {
|
||||
append(fieldSlot, field);
|
||||
setting.setAttribute("fieldInfo", field.getAttribute("fieldInfo"));
|
||||
|
||||
addLabel = child.hasAttribute("nolabel")
|
||||
? child.getAttribute("nolabel") !== "1"
|
||||
: true;
|
||||
const fieldName = child.getAttribute("name");
|
||||
string = child.hasAttribute("string")
|
||||
? toStringExpression(child.getAttribute("string"))
|
||||
: string;
|
||||
setting.setAttribute("fieldName", toStringExpression(fieldName));
|
||||
setting.setAttribute(
|
||||
"fieldId",
|
||||
toStringExpression(child.getAttribute("field_id") || fieldName)
|
||||
);
|
||||
}
|
||||
append(setting, fieldSlot);
|
||||
} else {
|
||||
append(setting, this.compileNode(child, params));
|
||||
}
|
||||
});
|
||||
setting.setAttribute("string", string);
|
||||
setting.setAttribute("addLabel", addLabel);
|
||||
setting.setAttribute("labels", JSON.stringify(params.labels));
|
||||
delete params.labels;
|
||||
return setting;
|
||||
}
|
||||
|
||||
compileField(el, params) {
|
||||
const res = super.compileField(el, params);
|
||||
if (params.labels && el.hasAttribute("widget")) {
|
||||
const label = params.getFieldExpr(el.getAttribute("name"), el.getAttribute("widget"));
|
||||
if (label) {
|
||||
params.labels.push(label);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
compileNode(node, params, evalInvisible) {
|
||||
if (isTextNode(node)) {
|
||||
if (params.labels && node.textContent.trim()) {
|
||||
params.labels.push(node.textContent.trim());
|
||||
return createElement("HighlightText", {
|
||||
originalText: toStringExpression(node.textContent),
|
||||
});
|
||||
}
|
||||
}
|
||||
return super.compileNode(node, params, evalInvisible);
|
||||
}
|
||||
|
||||
createLabelFromField(fieldId, fieldName, fieldString, label, params) {
|
||||
const res = super.createLabelFromField(fieldId, fieldName, fieldString, label, params);
|
||||
if (res.hasAttribute("string") && params.labels) {
|
||||
params.labels.push(res.getAttribute("string"));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
compileButton(el, params) {
|
||||
const res = super.compileButton(el, params);
|
||||
if (res.hasAttribute("string") && params.labels && res.children.length === 0) {
|
||||
params.labels.push(res.getAttribute("string"));
|
||||
const contentSlot = createElement("t");
|
||||
contentSlot.setAttribute("t-set-slot", "contents");
|
||||
const content = createElement("HighlightText", {
|
||||
originalText: res.getAttribute("string"),
|
||||
});
|
||||
append(contentSlot, content);
|
||||
append(res, contentSlot);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +77,13 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
<block title="Title of group Bar">
|
||||
<setting help="this is bar" documentation="/applications/technical/web/settings/this_is_a_test.html">
|
||||
<field name="bar"/>
|
||||
<button name="buttonName" icon="fa-arrow-right" type="action" string="Manage Users" class="btn-link"/>
|
||||
</setting>
|
||||
<setting string="This is Big BAR" help="this is big bar">
|
||||
<field name="bar"/>
|
||||
<setting>
|
||||
<label string="Big BAZ" for="baz"/>
|
||||
<div class="text-muted">this is a baz</div>
|
||||
<field name="baz"/>
|
||||
<label>label with content</label>
|
||||
</setting>
|
||||
</block>
|
||||
<block title="Title of group Foo">
|
||||
@@ -113,11 +117,11 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
[...target.querySelectorAll(".settings .o_settings_container .o_form_label")].map(
|
||||
(x) => x.textContent
|
||||
),
|
||||
["Bar", "This is Big BAR", "Foo", "Personalize setting"]
|
||||
["Bar", "Big BAZ", "Foo", "Personalize setting"]
|
||||
);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".settings .text-muted")].map((x) => x.textContent),
|
||||
["this is bar", "this is big bar", "this is foo", "this is full personalize setting"]
|
||||
["this is bar", "this is a baz", "this is foo", "this is full personalize setting"]
|
||||
);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".settings h2:not(.d-none)")].map((x) => x.textContent),
|
||||
@@ -161,7 +165,7 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
[...target.querySelectorAll(".o_settings_container .o_setting_box .o_form_label")].map(
|
||||
(x) => x.textContent
|
||||
),
|
||||
["Bar", "This is Big BAR"],
|
||||
["Bar", "Big BAZ"],
|
||||
"Foo is not shown"
|
||||
);
|
||||
|
||||
@@ -181,8 +185,8 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
[...target.querySelectorAll(".o_settings_container .o_setting_box .o_form_label")].map(
|
||||
(x) => x.textContent
|
||||
),
|
||||
["This is Big BAR"],
|
||||
"Only 'Big Bar' is shown"
|
||||
["Big BAZ"],
|
||||
"Only 'Big Baz' is shown"
|
||||
);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".settings h2:not(.d-none)")].map((x) => x.textContent),
|
||||
@@ -194,13 +198,46 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
".app_settings_block:not(.d-none) .app_settings_header .o_setting_box"
|
||||
);
|
||||
|
||||
await editSearch(target, "Manage Us");
|
||||
await execTimeouts();
|
||||
assert.strictEqual(
|
||||
target.querySelector(".highlighter").textContent,
|
||||
"Manage Us",
|
||||
"Manage Us word highlighted"
|
||||
);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".o_settings_container .o_setting_box .o_form_label")].map(
|
||||
(x) => x.textContent
|
||||
),
|
||||
["Bar"],
|
||||
"Foo is not shown"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".app_settings_block:not(.d-none) .app_settings_header .o_setting_box"
|
||||
);
|
||||
|
||||
await editSearch(target, "group Bar");
|
||||
await execTimeouts();
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".o_settings_container .o_setting_box .o_form_label")].map(
|
||||
(x) => x.textContent
|
||||
),
|
||||
["Bar", "This is Big BAR"],
|
||||
["Bar", "Big BAZ"],
|
||||
"When searching a title, all group is shown"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".app_settings_block:not(.d-none) .app_settings_header .o_setting_box"
|
||||
);
|
||||
|
||||
await editSearch(target, "different");
|
||||
await execTimeouts();
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".o_settings_container .o_setting_box .o_form_label")].map(
|
||||
(x) => x.textContent
|
||||
),
|
||||
["Personalize setting"],
|
||||
"When searching a title, all group is shown"
|
||||
);
|
||||
assert.containsOnce(
|
||||
@@ -418,11 +455,11 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
serverData,
|
||||
arch: `
|
||||
<form string="Settings" class="oe_form_configuration o_base_settings" js_class="base_settings">
|
||||
<app string="Base Setting" name="base-setting">
|
||||
<setting>
|
||||
<field name="bar"/>Make Changes
|
||||
</setting>
|
||||
</app>
|
||||
<app string="Base Setting" name="base-setting">
|
||||
<setting>
|
||||
<field name="bar"/>Make Changes
|
||||
</setting>
|
||||
</app>
|
||||
</form>`,
|
||||
mockRPC(route, { args, method, model }) {
|
||||
if (method === "create" && model === "res.config.settings") {
|
||||
@@ -454,9 +491,9 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
<app string="CRM" name="crm">
|
||||
<block>
|
||||
<setting>
|
||||
<label for="foo" string="Label Before" class="a"/>
|
||||
<field name="foo" class="b"/>
|
||||
<label for="foo" string="Label After" class="c"/>
|
||||
<label for="foo" string="Label Before" class="a"/>
|
||||
<field name="foo" class="b"/>
|
||||
<label for="foo" string="Label After" class="c"/>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
@@ -482,13 +519,13 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
serverData.views = {
|
||||
"res.config.settings,1,form": `
|
||||
<form string="Settings" js_class="base_settings">
|
||||
<app string="CRM" name="crm">
|
||||
<block>
|
||||
<setting help="this is foo">
|
||||
<field name="foo"/>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
<app string="CRM" name="crm">
|
||||
<block>
|
||||
<setting help="this is foo">
|
||||
<field name="foo"/>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</form>`,
|
||||
"task,2,list": `
|
||||
<tree>
|
||||
@@ -648,14 +685,14 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
serverData.views = {
|
||||
"res.config.settings,1,form": `
|
||||
<form string="Settings" js_class="base_settings">
|
||||
<app string="CRM" name="crm">
|
||||
<block>
|
||||
<setting string="Foo" help="this is foo">
|
||||
<field name="foo"/>
|
||||
</setting>
|
||||
</block>
|
||||
<button name="4" string="Execute action" type="action"/>
|
||||
</app>
|
||||
<app string="CRM" name="crm">
|
||||
<block>
|
||||
<setting string="Foo" help="this is foo">
|
||||
<field name="foo"/>
|
||||
</setting>
|
||||
</block>
|
||||
<button name="4" string="Execute action" type="action"/>
|
||||
</app>
|
||||
</form>`,
|
||||
"task,2,list": '<tree><field name="display_name"/></tree>',
|
||||
"res.config.settings,false,search": "<search></search>",
|
||||
@@ -1084,14 +1121,14 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
serverData.views = {
|
||||
"res.config.settings,1,form": `
|
||||
<form string="Settings" js_class="base_settings">
|
||||
<app string="CRM" name="crm">
|
||||
<block>
|
||||
<setting string="Foo" help="this is foo">
|
||||
<field name="foo"/>
|
||||
</setting>
|
||||
<button name="4" string="Execute action" type="action"/>
|
||||
</block>
|
||||
</app>
|
||||
<app string="CRM" name="crm">
|
||||
<block>
|
||||
<setting string="Foo" help="this is foo">
|
||||
<field name="foo"/>
|
||||
</setting>
|
||||
<button name="4" string="Execute action" type="action"/>
|
||||
</block>
|
||||
</app>
|
||||
</form>
|
||||
`,
|
||||
"res.config.settings,false,search": "<search></search>",
|
||||
@@ -1278,10 +1315,12 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
serverData,
|
||||
arch: `
|
||||
<form js_class="base_settings">
|
||||
<app string="CRM" name="crm">
|
||||
<label string="My" little ' Label" for="display_name" class="highhopes"/>
|
||||
<field name="display_name" />
|
||||
</app>
|
||||
<app string="CRM" name="crm">
|
||||
<setting>
|
||||
<label string="My" little ' Label" for="display_name" class="highhopes"/>
|
||||
<field name="display_name" />
|
||||
</setting>
|
||||
</app>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
@@ -1293,8 +1332,10 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
const expectedCompiled = `
|
||||
<SettingsPage slots="{NoContentHelper:this.props.slots.NoContentHelper}" initialTab="this.props.initialApp" t-slot-scope="settings" modules="[{"key":"crm","string":"CRM","imgurl":"/crm/static/description/icon.png"}]">
|
||||
<SettingsApp key="\`crm\`" string="\`CRM\`" imgurl="\`/crm/static/description/icon.png\`" selectedTab="settings.selectedTab">
|
||||
<FormLabel id="'display_name'" fieldName="'display_name'" record="this.props.record" fieldInfo="this.props.archInfo.fieldNodes['display_name']" className=""highhopes"" string="\`My" little ' Label\`"/>
|
||||
<Field id="'display_name'" name="'display_name'" record="this.props.record" fieldInfo="this.props.archInfo.fieldNodes['display_name']"/>
|
||||
<Setting title="\`\`" help="\`\`" companyDependent="false" documentation="\`\`" record="this.props.record" string="\`\`" addLabel="true" labels="["\`My\\" little ' Label\`"]">
|
||||
<FormLabel id="'display_name'" fieldName="'display_name'" record="this.props.record" fieldInfo="this.props.archInfo.fieldNodes['display_name']" className=""highhopes"" string="\`My" little ' Label\`"/>
|
||||
<Field id="'display_name'" name="'display_name'" record="this.props.record" fieldInfo="this.props.archInfo.fieldNodes['display_name']"/>
|
||||
</Setting>
|
||||
</SettingsApp>
|
||||
</SettingsPage>`;
|
||||
assert.areEquivalent(compiled.firstChild.innerHTML, expectedCompiled);
|
||||
@@ -1316,15 +1357,15 @@ QUnit.module("SettingsFormView", (hooks) => {
|
||||
serverData,
|
||||
arch: `
|
||||
<form string="Settings" class="oe_form_configuration o_base_settings" js_class="base_settings">
|
||||
<app string="CRM" name="crm">
|
||||
<block title="Title of group Bar">
|
||||
<setting>
|
||||
<field name="bar"/>
|
||||
<div class="text-muted">this is Baz value: <field name="baz" readonly="1"/> and this is the after text</div>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</form>`,
|
||||
<app string="CRM" name="crm">
|
||||
<block title="Title of group Bar">
|
||||
<setting>
|
||||
<field name="bar"/>
|
||||
<div class="text-muted">this is Baz value: <field name="baz" readonly="1"/> and this is the after text</div>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
|
||||
Reference in New Issue
Block a user