[IMP] web: allow custom row click action
This commit adds a generic `action="action_some_method"` attribute to the list view to allow for a custom action when clicking on a (record) row. This feature mirrors the existing Kanban "action" attribute. Note that in cases where the action method does not return a valid action then the default action `act_window_close` will be called instead (same behavior as the kanban view and buttons in general). Supports "magic link" part of Task: 2882539 Part-of: odoo/odoo#97109
This commit is contained in:
@@ -163,6 +163,11 @@ export class ListArchParser extends XMLParser {
|
||||
treeAttr.noOpen = archParseBoolean(node.getAttribute("no_open") || "");
|
||||
treeAttr.expand = archParseBoolean(xmlDoc.getAttribute("expand") || "");
|
||||
treeAttr.decorations = getDecoration(xmlDoc);
|
||||
|
||||
// custom open action when clicking on record row
|
||||
const action = xmlDoc.getAttribute("action");
|
||||
const type = xmlDoc.getAttribute("type");
|
||||
treeAttr.openAction = action && type ? { action, type } : null;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -167,8 +167,23 @@ export class ListController extends Component {
|
||||
}
|
||||
|
||||
async openRecord(record) {
|
||||
const activeIds = this.model.root.records.map((datapoint) => datapoint.resId);
|
||||
this.props.selectRecord(record.resId, { activeIds });
|
||||
if (this.archInfo.openAction) {
|
||||
this.actionService.doActionButton({
|
||||
name: this.archInfo.openAction.action,
|
||||
type: this.archInfo.openAction.type,
|
||||
resModel: record.resModel,
|
||||
resId: record.resId,
|
||||
resIds: record.resIds,
|
||||
context: record.context,
|
||||
onClose: async () => {
|
||||
await record.model.root.load();
|
||||
record.model.notify();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const activeIds = this.model.root.records.map((datapoint) => datapoint.resId);
|
||||
this.props.selectRecord(record.resId, { activeIds });
|
||||
}
|
||||
}
|
||||
|
||||
onClickCreate() {
|
||||
|
||||
@@ -1799,6 +1799,52 @@ QUnit.module("Views", (hooks) => {
|
||||
assert.verifySteps(["openRecord", "openRecord"]);
|
||||
});
|
||||
|
||||
QUnit.test("action/type attributes on tree arch, type='object'", async (assert) => {
|
||||
const list = await makeView({
|
||||
type: "list",
|
||||
resModel: "foo",
|
||||
serverData,
|
||||
arch: '<tree action="a1" type="object"><field name="foo"/></tree>',
|
||||
mockRPC(route, args) {
|
||||
assert.step(args.method);
|
||||
},
|
||||
});
|
||||
|
||||
patchWithCleanup(list.env.services.action, {
|
||||
doActionButton(params) {
|
||||
assert.step(`doActionButton type ${params.type} name ${params.name}`);
|
||||
params.onClose();
|
||||
},
|
||||
});
|
||||
|
||||
assert.verifySteps(["get_views", "web_search_read"]);
|
||||
await click(target.querySelector(".o_data_cell"));
|
||||
assert.verifySteps(["doActionButton type object name a1", "web_search_read"]);
|
||||
});
|
||||
|
||||
QUnit.test("action/type attributes on tree arch, type='action'", async (assert) => {
|
||||
const list = await makeView({
|
||||
type: "list",
|
||||
resModel: "foo",
|
||||
serverData,
|
||||
arch: '<tree action="a1" type="action"><field name="foo"/></tree>',
|
||||
mockRPC(route, args) {
|
||||
assert.step(args.method);
|
||||
},
|
||||
});
|
||||
|
||||
patchWithCleanup(list.env.services.action, {
|
||||
doActionButton(params) {
|
||||
assert.step(`doActionButton type ${params.type} name ${params.name}`);
|
||||
params.onClose();
|
||||
},
|
||||
});
|
||||
|
||||
assert.verifySteps(["get_views", "web_search_read"]);
|
||||
await click(target.querySelector(".o_data_cell"));
|
||||
assert.verifySteps(["doActionButton type action name a1", "web_search_read"]);
|
||||
});
|
||||
|
||||
QUnit.test("editable list view: readonly fields cannot be edited", async function (assert) {
|
||||
serverData.models.foo.fields.foo.readonly = true;
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
<rng:optional><rng:attribute name="decoration-warning"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="banner_route"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="sample"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="action"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="type"/></rng:optional>
|
||||
<rng:optional>
|
||||
<rng:attribute name="limit">
|
||||
<rng:data type="int"/>
|
||||
|
||||
Reference in New Issue
Block a user