[IMP] web: add control action button in x2many

This commit adds the possibility to define control action buttons in the
arch of a list view for a x2many. These buttons are action buttons that
will be placed in the same place as the control create ("Add a line").

The goal of this new feature is to offer the possibility to define
buttons that execute actions linked to an x2many.

Here is an example where we define a control create and a control action
button:
<tree>
    <control>
        <create string="Create" context="{}" />
        <button string="Action Button" name="do_something"
            class="btn-link" type="object" context="{'parent_id': parent.id}"/>
    </control>
    <field name="display_name"/>
</tree>

Part-of: odoo/odoo#97558
This commit is contained in:
FrancoisGe
2022-08-23 16:28:57 +02:00
parent b2a0a1c7d3
commit a11dafc99c
6 changed files with 77 additions and 9 deletions
@@ -125,11 +125,21 @@ export class ListArchParser extends XMLParser {
}))
.filter((button) => button.modifiers.invisible !== true);
return false;
} else if (node.tagName === "create") {
creates.push({
context: node.getAttribute("context"),
description: node.getAttribute("string"),
});
} else if (node.tagName === "control") {
for (const childNode of node.children) {
if (childNode.tagName === "button") {
creates.push({
type: "button",
...processButton(childNode),
});
} else if (childNode.tagName === "create") {
creates.push({
type: "create",
context: childNode.getAttribute("context"),
string: childNode.getAttribute("string"),
});
}
}
return false;
} else if (["tree", "list"].includes(node.tagName)) {
const activeActions = {
@@ -330,10 +330,16 @@
}
.o_field_x2many_list_row_add, .o_group_field_row_add {
a:focus, a:active {
a:focus, a:active, button:focus, button:active {
color: $link-hover-color;
outline: none;
}
button {
font-weight: 400;
padding: 0;
vertical-align: baseline;
}
}
}
@@ -78,7 +78,7 @@ export class ListRenderer extends Component {
this.creates = this.props.archInfo.creates.length
? this.props.archInfo.creates
: [{ description: this.env._t("Add a line") }];
: [{ type: "create", string: this.env._t("Add a line") }];
this.cellToFocus = null;
this.activeRowId = null;
@@ -81,14 +81,25 @@
>
<t t-foreach="creates" t-as="create" t-key="create_index">
<a
t-if="create.type === 'create'"
href="#"
role="button"
t-att-class="create_index !== 0 ? 'ml16' : ''"
t-att-tabindex="props.list.editedRecord ? '-1' : '0'"
t-on-click.stop.prevent="() => this.props.onAdd({context: create.context})"
>
<t t-esc="create.description"/>
<t t-esc="create.string"/>
</a>
<ViewButton
t-if="create.type === 'button'"
className="`${create.className} ${create_index !== 0 ? 'ml16' : ''}`"
clickParams="create.clickParams"
icon="create.icon"
record="props.list"
string="create.string"
title="create.title"
tabindex="props.list.editedRecord ? '-1' : '0'"
/>
</t>
</td>
</tr>
@@ -9099,6 +9099,45 @@ QUnit.module("Fields", (hooks) => {
);
});
QUnit.test("o2m add an action button control", async function (assert) {
await makeView({
type: "form",
resModel: "partner",
serverData,
resId: 2,
arch: `
<form>
<field name="p">
<tree>
<control>
<create string="Create" context="{}" />
<button string="Action Button" name="do_something" class="btn-link" type="object" context="{'parent_id': parent.id}"/>
</control>
<field name="display_name"/>
</tree>
</field>
</form>`,
mockRPC(route, args) {
if (args.method === "do_something") {
assert.step("do_something");
assert.strictEqual(args.kwargs.context.parent_id, 2);
return true;
}
},
});
await clickEdit(target);
assert.deepEqual(
[...target.querySelector(".o_field_x2many_list_row_add").children].map(
(el) => el.textContent
),
["Create", "Action Button"]
);
await click(target, ".o_field_x2many_list_row_add button");
assert.verifySteps(["do_something"]);
});
QUnit.test("o2m add a line custom control create align with handle", async function (assert) {
await makeView({
type: "form",
+3 -1
View File
@@ -415,7 +415,8 @@
<rng:element name="create">
<rng:ref name="overload"/>
<rng:attribute name="string"/>
<rng:attribute name="context"/>
<rng:optional><rng:attribute name="context"/></rng:optional>
<rng:optional><rng:attribute name="name"/></rng:optional>
</rng:element>
</rng:define>
@@ -425,6 +426,7 @@
<rng:oneOrMore>
<rng:choice>
<rng:ref name="create"/>
<rng:ref name="button"/>
</rng:choice>
</rng:oneOrMore>
</rng:element>