[IMP] web: documentation link widget

This commit introduces the documentation link widget, the aim is to
standardize the help documentation links that can be found in the views.

This widget will add an icon (o_doc_link), this icon is a link to the
documentation. Note that you can use relative or absolute path. The
relative path is relative to `https://www.odoo.com/documentation/server_version`,
so it's not necessary to hard-code the server version on the arch any more.

```xml
<widget name="documentation_link"  documentation="/applications/technical/web/settings/this_is_a_test.html"/>
```

Task-id: 2980478
Part-of: odoo/odoo#110432
This commit is contained in:
Jorge Pinna Puissant
2023-01-25 08:18:00 +01:00
parent fff31b316f
commit 80e1c0062e
6 changed files with 124 additions and 14 deletions
@@ -0,0 +1,36 @@
/** @odoo-module **/
import { session } from "@web/session";
import { standardWidgetProps } from "@web/views/widgets/standard_widget_props";
import { Component } from "@odoo/owl";
import { registry } from "@web/core/registry";
const LINK_REGEX = new RegExp("^https?://");
export class DocumentationLink extends Component {
get url() {
if (LINK_REGEX.test(this.props.path)) {
return this.props.path;
} else {
const serverVersion = session.server_version.includes("alpha")
? "master"
: session.server_version;
return "https://www.odoo.com/documentation/" + serverVersion + this.props.path;
}
}
}
DocumentationLink.template = "web.DocumentationLink";
DocumentationLink.props = {
...standardWidgetProps,
record: { type: Object, optional: 1 }, // The record is not needed in this widget
path: { type: String },
};
DocumentationLink.extractProps = ({ attrs }) => {
const { path } = attrs;
return {
path,
};
};
DocumentationLink.additionalClasses = ["d-inline"];
registry.category("view_widgets").add("documentation_link", DocumentationLink);
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="web.DocumentationLink" owl="1">
<a t-att-href="url" title="Documentation" class="o_doc_link me-2" target="_blank"></a>
</t>
</templates>
@@ -25,11 +25,17 @@ export class Widget extends Component {
}
get classNames() {
return {
const classNames = {
o_widget: true,
[`o_widget_${this.props.name}`]: true,
[this.props.className]: Boolean(this.props.className),
};
if (this.Widget.additionalClasses) {
for (const cls of this.Widget.additionalClasses) {
classNames[cls] = true;
}
}
return classNames;
}
get widgetProps() {
const { node: rawNode } = this.props;
@@ -5,9 +5,8 @@ import { HighlightText } from "../highlight_text/highlight_text";
import { session } from "@web/session";
import { FormLabelHighlightText } from "../highlight_text/form_label_highlight_text";
import { Component, useState } from "@odoo/owl";
import { DocumentationLink } from "@web/views/widgets/documentation_link/documentation_link";
const LINK_REGEX = new RegExp("^https?://");
export class Setting extends Component {
setup() {
this.state = useState({
@@ -57,16 +56,6 @@ export class Setting extends Component {
return label || "";
}
get url() {
if (LINK_REGEX.test(this.props.documentation)) {
return this.props.documentation;
} else {
const serverVersion = session.server_version.includes("alpha")
? "master"
: session.server_version;
return "https://www.odoo.com/documentation/" + serverVersion + this.props.documentation;
}
}
visible() {
if (!this.state.search.value) {
return true;
@@ -84,6 +73,7 @@ export class Setting extends Component {
Setting.components = {
FormLabelHighlightText,
HighlightText,
DocumentationLink,
};
Setting.template = "web.Setting";
Setting.props = {
@@ -13,7 +13,7 @@
<span class="o_form_label"><HighlightText originalText="labelString"/></span>
</t>
<t t-if="labelString and props.documentation">
<a t-att-href="url" title="Documentation" class="o_doc_link me-2" target="_blank"></a>
<DocumentationLink path="props.documentation"/>
</t>
<t t-if="displayCompanyDependentIcon">
<span class="fa fa-lg fa-building-o" title="Values set here are company-specific."/>
@@ -0,0 +1,72 @@
/** @odoo-module **/
import { getFixture } from "@web/../tests/helpers/utils";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
let target;
let serverData;
QUnit.module("Widgets", (hooks) => {
hooks.beforeEach(() => {
target = getFixture();
serverData = {
models: {
partner: {
fields: {
bar: { string: "Bar", type: "boolean" },
},
},
},
};
setupViewRegistries();
});
QUnit.module("DocumentationLink");
QUnit.test("documentation_link: relative path", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="bar"/>
<widget name="documentation_link" path="/applications/technical/web/settings/this_is_a_test.html"/>
</form>`,
});
assert.hasAttrValue(
target.querySelector(".o_doc_link"),
"href",
"https://www.odoo.com/documentation/1.0/applications/technical/web/settings/this_is_a_test.html"
);
});
QUnit.test("documentation_link: absoluth path (http)", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="bar"/>
<widget name="documentation_link" path="http://www.odoo.com/"/>
</form>`,
});
assert.hasAttrValue(target.querySelector(".o_doc_link"), "href", "http://www.odoo.com/");
});
QUnit.test("documentation_link: absoluth path (https)", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="bar"/>
<widget name="documentation_link" path="https://www.odoo.com/"/>
</form>`,
});
assert.hasAttrValue(target.querySelector(".o_doc_link"), "href", "https://www.odoo.com/");
});
});