[IMP] web: support explicit mobile view mode on window actions
Up until this commit, which view was displayed by default on mobile was somewhat of a lottery. Initially, only kanban views were considered as 'more adapted to mobile devices' and used as a main fallback to display records who had a kanban view in the window action definition. The the concept of 'mobile-friendly view' was extended to map and grid so that these views could take precedence over the kanban view in specific circumstances (indsutry_fsm and timesheet_grid, both of which are enterprise edition apps) - basically they were marked as mobile-friendly not because they *are*, but because it was the only way to override the kanban override. But this comes with its lot of problems and limitations, namely that the mobile friendly view will be found based on the order of view modes for a window action, so if you have a window action with the view modes `kanban,map,tree,form`, you will never be able to have e.g. the kanban view shown on desktop by default and the map view on mobile. This commit introduces the notion of a 'default mobile view' on window actions so that one may decide on an *arbitrary* view mode to use on mobile for an action - without impacting the ordering of views on other models, etc. Task-3460374 closes odoo/odoo#133608 Related: odoo/enterprise#46562 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -12,7 +12,6 @@ export const kanbanView = {
|
||||
|
||||
display_name: "Kanban",
|
||||
icon: "oi oi-view-kanban",
|
||||
isMobileFriendly: true,
|
||||
multiRecord: true,
|
||||
|
||||
ArchParser: KanbanArchParser,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -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": '<list><field name="foo"/></list>',
|
||||
"project,false,kanban": `
|
||||
<kanban>
|
||||
<templates>
|
||||
<t t-name='kanban-box'>
|
||||
<div class='oe_kanban_card'>
|
||||
<field name='foo' />
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
`,
|
||||
"project,false,search": "<search></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");
|
||||
});
|
||||
});
|
||||
@@ -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"],
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -215,6 +215,7 @@
|
||||
<group>
|
||||
<group name="views" string="Views">
|
||||
<field name="view_mode"/>
|
||||
<field name="mobile_view_mode"/>
|
||||
<field name="view_id"/>
|
||||
<field name="search_view_id"/>
|
||||
</group>
|
||||
|
||||
Reference in New Issue
Block a user