diff --git a/addons/web/static/src/core/commands/command_category.js b/addons/web/static/src/core/commands/command_category.js index 0481e1535db..691f104eeb6 100644 --- a/addons/web/static/src/core/commands/command_category.js +++ b/addons/web/static/src/core/commands/command_category.js @@ -8,5 +8,6 @@ commandCategoryRegistry .add("smart_action", {}, { sequence: 15 }) .add("actions", {}, { sequence: 30 }) .add("navbar", {}, { sequence: 40 }) + .add("view_switcher", {}, { sequence: 50 }) .add("default", {}, { sequence: 100 }) .add("debug", {}, { sequence: 110 }); diff --git a/addons/web/static/src/search/control_panel/control_panel.js b/addons/web/static/src/search/control_panel/control_panel.js index 4ba141f1a34..248e7cc49bf 100644 --- a/addons/web/static/src/search/control_panel/control_panel.js +++ b/addons/web/static/src/search/control_panel/control_panel.js @@ -10,6 +10,8 @@ import { FilterMenu } from "../filter_menu/filter_menu"; import { GroupByMenu } from "../group_by_menu/group_by_menu"; import { SearchBar } from "../search_bar/search_bar"; import { Dropdown } from "@web/core/dropdown/dropdown"; +import { useCommand } from "@web/core/commands/command_hook"; +import { sprintf } from "@web/core/utils/strings"; import { Component, useState, onMounted, useExternalListener, useRef, useEffect } from "@odoo/owl"; @@ -40,6 +42,18 @@ export class ControlPanel extends Component { this.onScrollThrottledBound = this.onScrollThrottled.bind(this); + const { viewSwitcherEntries, viewType } = this.env.config; + for (const view of viewSwitcherEntries || []) { + useCommand( + sprintf(this.env._t("Show %s view"), view.name), + () => this.onViewClicked(view.type), + { + category: "view_switcher", + isAvailable: () => view.type !== viewType, + } + ); + } + useExternalListener(window, "click", this.onWindowClick); useEffect(() => { if ( diff --git a/addons/web/static/tests/search/helpers.js b/addons/web/static/tests/search/helpers.js index aa826c3cb28..a1b6e14017d 100644 --- a/addons/web/static/tests/search/helpers.js +++ b/addons/web/static/tests/search/helpers.js @@ -12,6 +12,7 @@ import { } from "@web/../tests/helpers/utils"; import { dialogService } from "@web/core/dialog/dialog_service"; import { Component, xml } from "@odoo/owl"; +import { commandService } from "@web/core/commands/command_service"; import { hotkeyService } from "@web/core/hotkeys/hotkey_service"; import { notificationService } from "@web/core/notifications/notification_service"; import { ormService } from "@web/core/orm_service"; @@ -32,6 +33,7 @@ export function setupControlPanelServiceRegistry() { serviceRegistry.add("notification", notificationService); serviceRegistry.add("orm", ormService); serviceRegistry.add("view", viewService); + serviceRegistry.add("command", commandService); } export function setupControlPanelFavoriteMenuRegistry() { diff --git a/addons/web/static/tests/views/helpers.js b/addons/web/static/tests/views/helpers.js index a38a152e113..eedd7a05d5c 100644 --- a/addons/web/static/tests/views/helpers.js +++ b/addons/web/static/tests/views/helpers.js @@ -1,25 +1,24 @@ /** @odoo-module **/ -import { Dialog } from "@web/core/dialog/dialog"; -import { registry } from "@web/core/registry"; import { makeTestEnv } from "@web/../tests/helpers/mock_env"; import { getFixture, mount, nextTick } from "@web/../tests/helpers/utils"; -import { getDefaultConfig, View } from "@web/views/view"; +import { createDebugContext } from "@web/core/debug/debug_context"; +import { Dialog } from "@web/core/dialog/dialog"; import { MainComponentsContainer } from "@web/core/main_components_container"; -import { - setupControlPanelFavoriteMenuRegistry, - setupControlPanelServiceRegistry, -} from "../search/helpers"; -import { addLegacyMockEnvironment } from "../webclient/helpers"; +import { popoverService } from "@web/core/popover/popover_service"; +import { registry } from "@web/core/registry"; +import { getDefaultConfig, View } from "@web/views/view"; import { fakeCompanyService, makeFakeLocalizationService, makeFakeRouterService, - makeFakeUserService, + makeFakeUserService } from "../helpers/mock_services"; -import { commandService } from "@web/core/commands/command_service"; -import { popoverService } from "@web/core/popover/popover_service"; -import { createDebugContext } from "@web/core/debug/debug_context"; +import { + setupControlPanelFavoriteMenuRegistry, + setupControlPanelServiceRegistry +} from "../search/helpers"; +import { addLegacyMockEnvironment } from "../webclient/helpers"; import { Component, useSubEnv, xml } from "@odoo/owl"; @@ -150,7 +149,6 @@ export function setupViewRegistries() { serviceRegistry.add("localization", makeFakeLocalizationService()), { force: true }; serviceRegistry.add("popover", popoverService), { force: true }; serviceRegistry.add("company", fakeCompanyService); - serviceRegistry.add("command", commandService); } /** diff --git a/addons/web/static/tests/views/list_view_tests.js b/addons/web/static/tests/views/list_view_tests.js index 9a3124fd012..1e8b2c2aedc 100644 --- a/addons/web/static/tests/views/list_view_tests.js +++ b/addons/web/static/tests/views/list_view_tests.js @@ -6149,6 +6149,55 @@ QUnit.module("Views", (hooks) => { await click(target, ".o_back_button"); }); + QUnit.test( + "Navigate between the list and kanban view using the command palette", + async (assert) => { + serverData.views = { + "foo,false,search": ``, + "foo,false,list": ``, + "foo,false,kanban": ` + + +
+ +
+
+
`, + }; + registry.category("command_categories").add("view_switcher", {}); + + const wc = await createWebClient({ serverData }); + await doAction(wc, { + res_model: "foo", + type: "ir.actions.act_window", + views: [ + [false, "list"], + [false, "kanban"], + ], + }); + assert.containsOnce(target, ".o_cp_switch_buttons"); + assert.containsN(target, ".o_switch_view", 2); + assert.containsOnce(target, ".o_list_view"); + + triggerHotkey("control+k"); + await nextTick(); + assert.containsOnce(target.querySelector(".o_command_category"), ".o_command"); + let command = target.querySelector(".o_command_category .o_command"); + assert.strictEqual(command.textContent, "Show Kanban view"); + + await click(command); + assert.containsOnce(target, ".o_kanban_view"); + + triggerHotkey("control+k"); + await nextTick(); + assert.containsOnce(target.querySelector(".o_command_category"), ".o_command"); + command = target.querySelector(".o_command_category .o_command"); + assert.strictEqual(command.textContent, "Show List view"); + await click(command); + assert.containsOnce(target, ".o_list_view"); + } + ); + QUnit.test("can sort records when clicking on header", async function (assert) { serverData.models.foo.fields.foo.sortable = true;