From a066638cd55ec2a3e74a1916c8fb010d9e23a272 Mon Sep 17 00:00:00 2001 From: "Tiffany Chang (tic)" Date: Wed, 24 Aug 2022 09:47:46 +0000 Subject: [PATCH] [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 --- .../static/src/views/list/list_arch_parser.js | 5 ++ .../static/src/views/list/list_controller.js | 19 +++++++- .../web/static/tests/views/list_view_tests.js | 46 +++++++++++++++++++ odoo/addons/base/rng/tree_view.rng | 2 + 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/views/list/list_arch_parser.js b/addons/web/static/src/views/list/list_arch_parser.js index d697c0649fb..fe415739c4e 100644 --- a/addons/web/static/src/views/list/list_arch_parser.js +++ b/addons/web/static/src/views/list/list_arch_parser.js @@ -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; } }); diff --git a/addons/web/static/src/views/list/list_controller.js b/addons/web/static/src/views/list/list_controller.js index 9af25c26907..fb985f67b13 100644 --- a/addons/web/static/src/views/list/list_controller.js +++ b/addons/web/static/src/views/list/list_controller.js @@ -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() { diff --git a/addons/web/static/tests/views/list_view_tests.js b/addons/web/static/tests/views/list_view_tests.js index c99a27a3f06..6c70921fb00 100644 --- a/addons/web/static/tests/views/list_view_tests.js +++ b/addons/web/static/tests/views/list_view_tests.js @@ -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: '', + 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: '', + 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; diff --git a/odoo/addons/base/rng/tree_view.rng b/odoo/addons/base/rng/tree_view.rng index 8985ea827ea..6caca915e2e 100644 --- a/odoo/addons/base/rng/tree_view.rng +++ b/odoo/addons/base/rng/tree_view.rng @@ -46,6 +46,8 @@ + +