From 1c1aaa883c55b6e62fd23e372e1ac833abeac9df Mon Sep 17 00:00:00 2001 From: Lucas Perais Date: Tue, 23 May 2023 15:49:28 +0000 Subject: [PATCH] [FIX] web: list: _view_ref and search_default should not be passed down Have an action with *_view_ref and search_default_* context keys. This action has a list view that itself has a many2many_tags field (it is editable for simplicity's sake) click on that many2many_tags field and click on the search more item. Before this commit, the action's context keys *_view_ref and search_default_* were passed down all the way to the field and to the search more dialog, causing, inevatibly, crashes. After this commit, those keys are not passed and there are no crash. opw-3226398 closes odoo/odoo#124252 X-original-commit: 47eab4d987d8cb91a30507c6c33348d1945698f1 Signed-off-by: Aaron Bohy (aab) Signed-off-by: Lucas Perais (lpe) --- .../web/static/src/views/relational_model.js | 11 +++ .../web/static/tests/views/list_view_tests.js | 75 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js index 071a80abaf0..4bdfbc4c224 100644 --- a/addons/web/static/src/views/relational_model.js +++ b/addons/web/static/src/views/relational_model.js @@ -3503,6 +3503,17 @@ export class RelationalModel extends Model { ) { rootParams.groupBy = [this.defaultGroupBy]; } + + if (rootParams.context) { + // *_view_ref and search_default_* context keys are not destined to us, rather + // they were tyîcally "consumed" by the View. + // The default_* context keys are, on the contrary, destined for us. + rootParams.context = Object.fromEntries( + Object.entries(rootParams.context).filter( + ([key]) => !key.endsWith("_view_ref") && !key.startsWith("search_default_") + ) + ); + } rootParams.rawContext = { make: () => { return makeContext([rootParams.context], {}); diff --git a/addons/web/static/tests/views/list_view_tests.js b/addons/web/static/tests/views/list_view_tests.js index 8240d64beae..930a7c11d25 100644 --- a/addons/web/static/tests/views/list_view_tests.js +++ b/addons/web/static/tests/views/list_view_tests.js @@ -12,6 +12,7 @@ import { uiService } from "@web/core/ui/ui_service"; import { getNextTabableElement } from "@web/core/utils/ui"; import { session } from "@web/session"; import { FloatField } from "@web/views/fields/float/float_field"; +import { AutoComplete } from "@web/core/autocomplete/autocomplete"; import { Many2XAutocomplete } from "@web/views/fields/relational_utils"; import { textField } from "@web/views/fields/text/text_field"; import { ListController } from "@web/views/list/list_controller"; @@ -18837,4 +18838,78 @@ QUnit.module("Views", (hooks) => { "onchange result should be applied" ); }); + + QUnit.test("context keys not passed down the stack and not to fields", async (assert) => { + patchWithCleanup(AutoComplete, { + timeout: 0, + }); + serverData.actions = { + 1: { + id: 1, + name: "Foo", + res_model: "foo", + type: "ir.actions.act_window", + views: [[false, "list"]], + context: { + tree_view_ref: "foo_view_ref", + search_default_bar: true, + }, + }, + }; + serverData.views = { + "foo,foo_view_ref,list": ` + + + `, + "foo,false,search": "", + "bar,false,list": ``, + "bar,false,search": "", + }; + + const barRecs = []; + for (let i = 1; i < 50; i++) { + barRecs.push({ + id: i, + display_name: `Value ${i}`, + }); + } + serverData.models.bar.records = barRecs; + + const mockRPC = (route, args) => { + if (args.method) { + assert.step( + `${args.model}: ${args.method}: ${JSON.stringify(args.kwargs.context)}` + ); + } + }; + const wc = await createWebClient({ serverData, mockRPC }); + await doAction(wc, 1); + assert.verifySteps([ + `foo: get_views: {"lang":"en","uid":7,"tz":"taht","tree_view_ref":"foo_view_ref","search_default_bar":true}`, + `foo: web_search_read: {"lang":"en","uid":7,"tz":"taht","bin_size":true}`, + `bar: read: {"lang":"en","uid":7,"tz":"taht","bin_size":true}`, + ]); + + await click(target.querySelectorAll(".o_data_row .o_data_cell")[1]); + + const input = target.querySelector(".o_selected_row .o_field_many2many_tags input"); + await triggerEvent(input, null, "focus"); + await click(input); + await nextTick(); + assert.verifySteps([`bar: name_search: {"lang":"en","uid":7,"tz":"taht"}`]); + + const items = Array.from( + target.querySelectorAll(".o_selected_row .o_field_many2many_tags .dropdown-item") + ); + await click(items.find((el) => el.textContent.trim() === "Search More...")); + assert.verifySteps([ + `bar: get_views: {"lang":"en","uid":7,"tz":"taht"}`, + `bar: web_search_read: {"lang":"en","uid":7,"tz":"taht","bin_size":true}`, + ]); + assert.containsOnce(target, ".modal"); + assert.strictEqual( + target.querySelector(".modal .modal-header .modal-title").textContent, + "Search: M2M field" + ); + }); });