diff --git a/addons/web/static/src/views/kanban/kanban_view.js b/addons/web/static/src/views/kanban/kanban_view.js index 0cb59157b78..a82f5607218 100644 --- a/addons/web/static/src/views/kanban/kanban_view.js +++ b/addons/web/static/src/views/kanban/kanban_view.js @@ -12,7 +12,6 @@ export const kanbanView = { display_name: "Kanban", icon: "oi oi-view-kanban", - isMobileFriendly: true, multiRecord: true, ArchParser: KanbanArchParser, diff --git a/addons/web/static/src/webclient/actions/action_service.js b/addons/web/static/src/webclient/actions/action_service.js index 2ae1993c2b2..de0dff5eaa3 100644 --- a/addons/web/static/src/webclient/actions/action_service.js +++ b/addons/web/static/src/webclient/actions/action_service.js @@ -943,11 +943,10 @@ function makeActionManager(env) { } if (env.isSmall) { - if (!view.isMobileFriendly) { - view = _findMobileView(views, view.multiRecord) || view; - } - if (lazyView && !lazyView.isMobileFriendly) { - lazyView = _findMobileView(views, lazyView.multiRecord) || lazyView; + view = _findView(views, view.multiRecord, action.mobile_view_mode) || view; + if (lazyView) { + lazyView = + _findView(views, lazyView.multiRecord, action.mobile_view_mode) || lazyView; } } @@ -984,15 +983,14 @@ function makeActionManager(env) { } /** - * Helper function to find the first mobile-friendly view, if any. - * * @private * @param {Array} views an array of views * @param {boolean} multiRecord true if we search for a multiRecord view - * @returns {Object|undefined} first mobile-friendly view found + * @param {string} viewType type of the view to search + * @returns {Object|undefined} the requested view if it could be found */ - function _findMobileView(views, multiRecord) { - return views.find((view) => view.isMobileFriendly && view.multiRecord === multiRecord); + function _findView(views, multiRecord, viewType) { + return views.find((v) => v.type === viewType && v.multiRecord == multiRecord); } // --------------------------------------------------------------------------- diff --git a/addons/web/static/tests/mobile/webclient/window_action_tests.js b/addons/web/static/tests/mobile/webclient/window_action_tests.js new file mode 100644 index 00000000000..d809e5c3194 --- /dev/null +++ b/addons/web/static/tests/mobile/webclient/window_action_tests.js @@ -0,0 +1,67 @@ +/** @odoo-module **/ + +import { getFixture } from "@web/../tests/helpers/utils"; +import { setupViewRegistries } from "@web/../tests/views/helpers"; +import { createWebClient, doAction } from "@web/../tests/webclient/helpers"; + +let serverData, target; + +QUnit.module("ActionManager", (hooks) => { + hooks.beforeEach(() => { + serverData = { + models: { + project: { + fields: { + foo: { string: "Foo", type: "boolean" }, + }, + records: [ + { + id: 1, + foo: true, + }, + { + id: 2, + foo: false, + }, + ], + }, + }, + views: { + "project,false,list": '', + "project,false,kanban": ` + + + +
+ +
+
+
+
+ `, + "project,false,search": "", + }, + }; + target = getFixture(); + setupViewRegistries(); + }); + + QUnit.module("Window Actions"); + + QUnit.test("execute a window action with mobile_view_mode", async (assert) => { + const webClient = await createWebClient({ serverData }); + await doAction(webClient, { + xml_id: "project.action", + name: "Project Action", + res_model: "project", + type: "ir.actions.act_window", + view_mode: "list,kanban", + mobile_view_mode: "list", + views: [ + [false, "kanban"], + [false, "list"], + ], + }); + assert.containsOnce(target, ".o_list_view"); + }); +}); diff --git a/addons/web/static/tests/webclient/helpers.js b/addons/web/static/tests/webclient/helpers.js index 5ebcc47a6bf..b93f8889a7d 100644 --- a/addons/web/static/tests/webclient/helpers.js +++ b/addons/web/static/tests/webclient/helpers.js @@ -174,6 +174,7 @@ export function getActionManagerServerData() { xml_id: "action_3", name: "Partners", res_model: "partner", + mobile_view_mode: "kanban", type: "ir.actions.act_window", views: [ [false, "list"], diff --git a/odoo/addons/base/models/ir_actions.py b/odoo/addons/base/models/ir_actions.py index 388b8fa5d42..bbe6cec211a 100644 --- a/odoo/addons/base/models/ir_actions.py +++ b/odoo/addons/base/models/ir_actions.py @@ -272,6 +272,7 @@ class IrActionsActWindow(models.Model): target = fields.Selection([('current', 'Current Window'), ('new', 'New Window'), ('inline', 'Inline Edit'), ('fullscreen', 'Full Screen'), ('main', 'Main action of Current Window')], default="current", string='Target Window') view_mode = fields.Char(required=True, default='tree,form', help="Comma-separated list of allowed view modes, such as 'form', 'tree', 'calendar', etc. (Default: tree,form)") + mobile_view_mode = fields.Char(default="kanban", help="First view mode in mobile and small screen environments (default='kanban'). If it can't be found among available view modes, the same mode as for wider screens is used)") usage = fields.Char(string='Action Usage', help="Used to filter menu and home actions from the user form.") view_ids = fields.One2many('ir.actions.act_window.view', 'act_window_id', string='No of Views') @@ -327,9 +328,8 @@ class IrActionsActWindow(models.Model): def _get_readable_fields(self): return super()._get_readable_fields() | { - "context", "domain", "filter", "groups_id", "limit", "res_id", - "res_model", "search_view_id", "target", "view_id", - "view_mode", "views", + "context", "mobile_view_mode", "domain", "filter", "groups_id", "limit", + "res_id", "res_model", "search_view_id", "target", "view_id", "view_mode", "views", # `flags` is not a real field of ir.actions.act_window but is used # to give the parameters to generate the action "flags" diff --git a/odoo/addons/base/views/ir_actions_views.xml b/odoo/addons/base/views/ir_actions_views.xml index a92e825344d..eca3223fda1 100644 --- a/odoo/addons/base/views/ir_actions_views.xml +++ b/odoo/addons/base/views/ir_actions_views.xml @@ -215,6 +215,7 @@ +