diff --git a/addons/web/static/src/core/debug/debug_context.js b/addons/web/static/src/core/debug/debug_context.js index d8f6987bcf4..a7593ec6131 100644 --- a/addons/web/static/src/core/debug/debug_context.js +++ b/addons/web/static/src/core/debug/debug_context.js @@ -1,4 +1,5 @@ /** @odoo-module **/ + import { registry } from "../registry"; import { memoize } from "../utils/functions"; import { useEffect } from "@web/core/utils/hooks"; @@ -78,9 +79,12 @@ export function useEnvDebugContext() { } export function useDebugCategory(category, context = {}) { - const debugContext = useEnvDebugContext(); - useEffect( - () => debugContext.activateCategory(category, context), - () => [] - ); + const env = useEnv(); + if (env.debug) { + const debugContext = useEnvDebugContext(); + useEffect( + () => debugContext.activateCategory(category, context), + () => [] + ); + } } diff --git a/addons/web/static/src/core/debug/debug_menu_items.js b/addons/web/static/src/core/debug/debug_menu_items.js index 6ef2c887d35..b01286079c9 100644 --- a/addons/web/static/src/core/debug/debug_menu_items.js +++ b/addons/web/static/src/core/debug/debug_menu_items.js @@ -1,8 +1,8 @@ /** @odoo-module **/ -import { browser } from "../browser/browser"; -import { routeToUrl } from "../browser/router_service"; -import { registry } from "../registry"; +import { browser } from "@web/core/browser/browser"; +import { routeToUrl } from "@web/core/browser/router_service"; +import { registry } from "@web/core/registry"; function activateAssetsDebugging({ env }) { return { diff --git a/addons/web/static/src/core/debug/debug_utils.js b/addons/web/static/src/core/debug/debug_utils.js new file mode 100644 index 00000000000..bd91c81db55 --- /dev/null +++ b/addons/web/static/src/core/debug/debug_utils.js @@ -0,0 +1,14 @@ +/** @odoo-module **/ + +export function editModelDebug(env, title, model, id) { + return env.services.action.doAction({ + res_model: model, + res_id: id, + name: title, + type: "ir.actions.act_window", + views: [[false, "form"]], + view_mode: "form", + target: "new", + flags: { action_buttons: true, headless: true }, + }); +} diff --git a/addons/web/static/src/legacy/debug_manager.js b/addons/web/static/src/legacy/debug_manager.js index 090892acad7..1264ca824e6 100644 --- a/addons/web/static/src/legacy/debug_manager.js +++ b/addons/web/static/src/legacy/debug_manager.js @@ -1,212 +1,15 @@ /** @odoo-module **/ -import { Dialog } from "../core/dialog/dialog"; -import { formatDateTime, parseDateTime } from "../core/l10n/dates"; -import { _lt } from "../core/l10n/translation"; -import { registry } from "../core/registry"; +import { _lt } from "@web/core/l10n/translation"; +import { Dialog } from "@web/core/dialog/dialog"; +import { formatDateTime, parseDateTime } from "@web/core/l10n/dates"; import { formatMany2one } from "@web/fields/formatters"; +import { registry } from "@web/core/registry"; -const { hooks, tags } = owl; +const { hooks } = owl; const { useState } = hooks; -function editModelDebug(env, title, model, id) { - return env.services.action.doAction({ - res_model: model, - res_id: id, - name: title, - type: "ir.actions.act_window", - views: [[false, "form"]], - view_mode: "form", - target: "new", - flags: { action_buttons: true, headless: true }, - }); -} - -// Action items - -function actionSeparator() { - return { - type: "separator", - sequence: 100, - }; -} - -function accessSeparator({ accessRights, action }) { - const { canSeeModelAccess, canSeeRecordRules } = accessRights; - if (!action.res_model || (!canSeeModelAccess && !canSeeRecordRules)) { - return null; - } - return { - type: "separator", - sequence: 200, - }; -} - -function editAction({ action, env }) { - if (!action.id) { - return null; - } - const description = env._t("Edit Action"); - return { - type: "item", - description, - callback: () => { - editModelDebug(env, description, action.type, action.id); - }, - sequence: 110, - }; -} - -function viewFields({ action, env }) { - if (!action.res_model) { - return null; - } - const description = env._t("View Fields"); - return { - type: "item", - description, - callback: async () => { - const modelId = ( - await env.services.orm.search("ir.model", [["model", "=", action.res_model]], { - limit: 1, - }) - )[0]; - env.services.action.doAction({ - res_model: "ir.model.fields", - name: description, - views: [ - [false, "list"], - [false, "form"], - ], - domain: [["model_id", "=", modelId]], - type: "ir.actions.act_window", - context: { - default_model_id: modelId, - }, - }); - }, - sequence: 120, - }; -} - -function manageFilters({ action, env }) { - if (!action.res_model) { - return null; - } - const description = env._t("Manage Filters"); - return { - type: "item", - description, - callback: () => { - // manage_filters - env.services.action.doAction({ - res_model: "ir.filters", - name: description, - views: [ - [false, "list"], - [false, "form"], - ], - type: "ir.actions.act_window", - context: { - search_default_my_filters: true, - search_default_model_id: action.res_model, - }, - }); - }, - sequence: 130, - }; -} - -function technicalTranslation({ action, env }) { - if (!action.res_model) { - return null; - } - return { - type: "item", - description: env._t("Technical Translation"), - callback: async () => { - const result = await env.services.orm.call( - "ir.translation", - "get_technical_translations", - [action.res_model] - ); - env.services.action.doAction(result); - }, - sequence: 140, - }; -} - -function viewAccessRights({ accessRights, action, env }) { - if (!action.res_model || !accessRights.canSeeModelAccess) { - return null; - } - const description = env._t("View Access Rights"); - return { - type: "item", - description, - callback: async () => { - const modelId = ( - await env.services.orm.search("ir.model", [["model", "=", action.res_model]], { - limit: 1, - }) - )[0]; - env.services.action.doAction({ - res_model: "ir.model.access", - name: description, - views: [ - [false, "list"], - [false, "form"], - ], - domain: [["model_id", "=", modelId]], - type: "ir.actions.act_window", - context: { - default_model_id: modelId, - }, - }); - }, - sequence: 210, - }; -} - -function viewRecordRules({ accessRights, action, env }) { - if (!action.res_model || !accessRights.canSeeRecordRules) { - return null; - } - const description = env._t("Model Record Rules"); - return { - type: "item", - description: env._t("View Record Rules"), - callback: async () => { - const modelId = ( - await env.services.orm.search("ir.model", [["model", "=", action.res_model]], { - limit: 1, - }) - )[0]; - env.services.action.doAction({ - res_model: "ir.rule", - name: description, - views: [ - [false, "list"], - [false, "form"], - ], - domain: [["model_id", "=", modelId]], - type: "ir.actions.act_window", - context: { - default_model_id: modelId, - }, - }); - }, - sequence: 220, - }; -} - -class FieldViewGetDialog extends Dialog {} -FieldViewGetDialog.props = Object.assign({}, Dialog.props, { - arch: { type: String }, - close: Function, -}); -FieldViewGetDialog.bodyTemplate = tags.xml`
`;
-FieldViewGetDialog.title = _lt("Fields View Get");
+const debugRegistry = registry.category("debug");
 
 class GetMetadataDialog extends Dialog {
     setup() {
@@ -243,7 +46,6 @@ class GetMetadataDialog extends Dialog {
 }
 GetMetadataDialog.bodyTemplate = "web.DebugMenu.getMetadataBody";
 GetMetadataDialog.title = _lt("View Metadata");
-
 class SetDefaultDialog extends Dialog {
     setup() {
         super.setup();
@@ -389,66 +191,7 @@ SetDefaultDialog.bodyTemplate = "web.DebugMenu.setDefaultBody";
 SetDefaultDialog.footerTemplate = "web.DebugMenu.SetDefaultFooter";
 SetDefaultDialog.title = _lt("Set Default");
 
-function viewSeparator() {
-    return {
-        type: "separator",
-        sequence: 300,
-    };
-}
-
-function fieldsViewGet({ component, env }) {
-    return {
-        type: "item",
-        description: env._t("Fields View Get"),
-        callback: () => {
-            const props = {
-                arch: component.props.viewInfo.arch,
-            };
-            env.services.dialog.add(FieldViewGetDialog, props);
-        },
-        sequence: 340,
-    };
-}
-
-export function editView({ accessRights, action, component, env }) {
-    if (!accessRights.canEditView) {
-        return null;
-    }
-    let { view_id: viewId, type: viewType } = component.props.viewInfo;
-    viewType = viewType === "tree" ? "list" : viewType;
-    const displayName = action.views.find((v) => v.type === viewType).name.toString();
-    const description = env._t("Edit View: ") + displayName;
-    return {
-        type: "item",
-        description,
-        callback: () => {
-            editModelDebug(env, description, "ir.ui.view", viewId);
-        },
-        sequence: 350,
-    };
-}
-
-export function editSearchView({ accessRights, component, env }) {
-    if (!accessRights.canEditView) {
-        return null;
-    }
-    const description = env._t("Edit SearchView");
-    return {
-        type: "item",
-        description,
-        callback: () => {
-            editModelDebug(
-                env,
-                description,
-                "ir.ui.view",
-                component.props.viewParams.controlPanelFieldsView.view_id
-            );
-        },
-        sequence: 360,
-    };
-}
-
-// Form view itemss
+// Form view items
 
 function setDefaults({ action, component, env }) {
     return {
@@ -515,26 +258,6 @@ function manageAttachments({ action, component, env }) {
     };
 }
 
-const debugRegistry = registry.category("debug");
-
-debugRegistry
-    .category("action")
-    .add("actionSeparator", actionSeparator)
-    .add("editAction", editAction)
-    .add("viewFields", viewFields)
-    .add("manageFilters", manageFilters)
-    .add("technicalTranslation", technicalTranslation)
-    .add("accessSeparator", accessSeparator)
-    .add("viewAccessRights", viewAccessRights)
-    .add("viewRecordRules", viewRecordRules);
-
-debugRegistry
-    .category("view")
-    .add("viewSeparator", viewSeparator)
-    .add("fieldsViewGet", fieldsViewGet)
-    .add("editView", editView)
-    .add("editSearchView", editSearchView);
-
 debugRegistry
     .category("form")
     .add("setDefaults", setDefaults)
diff --git a/addons/web/static/src/views/debug_items.js b/addons/web/static/src/views/debug_items.js
new file mode 100644
index 00000000000..0a37e9f64d3
--- /dev/null
+++ b/addons/web/static/src/views/debug_items.js
@@ -0,0 +1,94 @@
+/** @odoo-module **/
+
+import { _lt } from "@web/core/l10n/translation";
+import { Dialog } from "@web/core/dialog/dialog";
+import { editModelDebug } from "@web/core/debug/debug_utils";
+import { registry } from "@web/core/registry";
+
+const { tags } = owl;
+
+const debugRegistry = registry.category("debug");
+
+class FieldViewGetDialog extends Dialog {}
+FieldViewGetDialog.props = Object.assign({}, Dialog.props, {
+    arch: { type: String },
+    close: Function,
+});
+FieldViewGetDialog.bodyTemplate = tags.xml`
`;
+FieldViewGetDialog.title = _lt("Fields View Get");
+
+function viewSeparator() {
+    return {
+        type: "separator",
+        sequence: 300,
+    };
+}
+
+function fieldsViewGet({ component, env }) {
+    let { arch } = component.props;
+    if ("viewInfo" in component.props) {
+        //legacy
+        arch = component.props.viewInfo.arch;
+    }
+    return {
+        type: "item",
+        description: env._t("Fields View Get"),
+        callback: () => {
+            env.services.dialog.add(FieldViewGetDialog, { arch });
+        },
+        sequence: 340,
+    };
+}
+
+export function editView({ accessRights, component, env }) {
+    if (!accessRights.canEditView) {
+        return null;
+    }
+    let type;
+    let { viewId } = component.props.info || {}; // fallback is there for legacy
+    if ("viewInfo" in component.props) {
+        // legacy
+        viewId = component.props.viewInfo.view_id;
+        type = component.props.viewInfo.type;
+        type = type === "tree" ? "list" : type;
+    } else {
+        type = component.constructor.type;
+    }
+    const displayName = type[0].toUpperCase() + type.slice(1);
+    const description = env._t("Edit View: ") + displayName;
+    return {
+        type: "item",
+        description,
+        callback: () => {
+            editModelDebug(env, description, "ir.ui.view", viewId);
+        },
+        sequence: 350,
+    };
+}
+
+export function editSearchView({ accessRights, component, env }) {
+    if (!accessRights.canEditView) {
+        return null;
+    }
+    let { searchViewId } = component.props.info || {}; // fallback is there for legacy
+    if ("viewParams" in component.props) {
+        //legacy
+        searchViewId = component.props.viewParams.action.controlPanelFieldsView.view_id;
+    }
+    const description = env._t("Edit ControlPanelView");
+    return {
+        type: "item",
+        description,
+        callback: () => {
+            editModelDebug(env, description, "ir.ui.view", searchViewId);
+        },
+        sequence: 360,
+    };
+}
+
+debugRegistry
+    .category("view")
+    .add("viewSeparator", viewSeparator)
+    .add("fieldsViewGet", fieldsViewGet)
+    .add("editView", editView)
+    .add("editSearchView", editSearchView);
diff --git a/addons/web/static/src/webclient/actions/action_service.js b/addons/web/static/src/webclient/actions/action_service.js
index 7a063912cd2..c7795644ed0 100644
--- a/addons/web/static/src/webclient/actions/action_service.js
+++ b/addons/web/static/src/webclient/actions/action_service.js
@@ -9,6 +9,7 @@ import { evaluateExpr } from "@web/core/py_js/py";
 import { registry } from "@web/core/registry";
 import { KeepLast } from "@web/core/utils/concurrency";
 import { sprintf } from "@web/core/utils/strings";
+import { useDebugCategory } from "@web/core/debug/debug_context";
 import { ActionDialog } from "./action_dialog";
 
 /** @typedef {number|false} ActionId */
@@ -465,7 +466,7 @@ function makeActionManager(env) {
             setup() {
                 this.Component = controller.Component;
                 this.componentRef = hooks.useRef("component");
-                this.registerCallback = null;
+                useDebugCategory("action", { action });
                 if (action.target !== "new") {
                     let beforeLeaveFn;
                     this.registerCallback = (type, fn) => {
diff --git a/addons/web/static/src/webclient/actions/debug_items.js b/addons/web/static/src/webclient/actions/debug_items.js
new file mode 100644
index 00000000000..87ab7ec8b7b
--- /dev/null
+++ b/addons/web/static/src/webclient/actions/debug_items.js
@@ -0,0 +1,196 @@
+/** @odoo-module **/
+
+import { editModelDebug } from "@web/core/debug/debug_utils";
+import { registry } from "@web/core/registry";
+
+const debugRegistry = registry.category("debug");
+
+function actionSeparator({ action }) {
+    if (!action.id || !action.res_model) {
+        return null;
+    }
+    return {
+        type: "separator",
+        sequence: 100,
+    };
+}
+
+function accessSeparator({ accessRights, action }) {
+    const { canSeeModelAccess, canSeeRecordRules } = accessRights;
+    if (!action.res_model || (!canSeeModelAccess && !canSeeRecordRules)) {
+        return null;
+    }
+    return {
+        type: "separator",
+        sequence: 200,
+    };
+}
+
+function editAction({ action, env }) {
+    if (!action.id) {
+        return null;
+    }
+    const description = env._t("Edit Action");
+    return {
+        type: "item",
+        description,
+        callback: () => {
+            editModelDebug(env, description, action.type, action.id);
+        },
+        sequence: 110,
+    };
+}
+
+function viewFields({ action, env }) {
+    if (!action.res_model) {
+        return null;
+    }
+    const description = env._t("View Fields");
+    return {
+        type: "item",
+        description,
+        callback: async () => {
+            const modelId = (
+                await env.services.orm.search("ir.model", [["model", "=", action.res_model]], {
+                    limit: 1,
+                })
+            )[0];
+            env.services.action.doAction({
+                res_model: "ir.model.fields",
+                name: description,
+                views: [
+                    [false, "list"],
+                    [false, "form"],
+                ],
+                domain: [["model_id", "=", modelId]],
+                type: "ir.actions.act_window",
+                context: {
+                    default_model_id: modelId,
+                },
+            });
+        },
+        sequence: 120,
+    };
+}
+
+function manageFilters({ action, env }) {
+    if (!action.res_model) {
+        return null;
+    }
+    const description = env._t("Manage Filters");
+    return {
+        type: "item",
+        description,
+        callback: () => {
+            // manage_filters
+            env.services.action.doAction({
+                res_model: "ir.filters",
+                name: description,
+                views: [
+                    [false, "list"],
+                    [false, "form"],
+                ],
+                type: "ir.actions.act_window",
+                context: {
+                    search_default_my_filters: true,
+                    search_default_model_id: action.res_model,
+                },
+            });
+        },
+        sequence: 130,
+    };
+}
+
+function technicalTranslation({ action, env }) {
+    if (!action.res_model) {
+        return null;
+    }
+    return {
+        type: "item",
+        description: env._t("Technical Translation"),
+        callback: async () => {
+            const result = await env.services.orm.call(
+                "ir.translation",
+                "get_technical_translations",
+                [action.res_model]
+            );
+            env.services.action.doAction(result);
+        },
+        sequence: 140,
+    };
+}
+
+function viewAccessRights({ accessRights, action, env }) {
+    if (!action.res_model || !accessRights.canSeeModelAccess) {
+        return null;
+    }
+    const description = env._t("View Access Rights");
+    return {
+        type: "item",
+        description,
+        callback: async () => {
+            const modelId = (
+                await env.services.orm.search("ir.model", [["model", "=", action.res_model]], {
+                    limit: 1,
+                })
+            )[0];
+            env.services.action.doAction({
+                res_model: "ir.model.access",
+                name: description,
+                views: [
+                    [false, "list"],
+                    [false, "form"],
+                ],
+                domain: [["model_id", "=", modelId]],
+                type: "ir.actions.act_window",
+                context: {
+                    default_model_id: modelId,
+                },
+            });
+        },
+        sequence: 210,
+    };
+}
+
+function viewRecordRules({ accessRights, action, env }) {
+    if (!action.res_model || !accessRights.canSeeRecordRules) {
+        return null;
+    }
+    const description = env._t("Model Record Rules");
+    return {
+        type: "item",
+        description: env._t("View Record Rules"),
+        callback: async () => {
+            const modelId = (
+                await env.services.orm.search("ir.model", [["model", "=", action.res_model]], {
+                    limit: 1,
+                })
+            )[0];
+            env.services.action.doAction({
+                res_model: "ir.rule",
+                name: description,
+                views: [
+                    [false, "list"],
+                    [false, "form"],
+                ],
+                domain: [["model_id", "=", modelId]],
+                type: "ir.actions.act_window",
+                context: {
+                    default_model_id: modelId,
+                },
+            });
+        },
+        sequence: 220,
+    };
+}
+
+debugRegistry
+    .category("action")
+    .add("actionSeparator", actionSeparator)
+    .add("editAction", editAction)
+    .add("viewFields", viewFields)
+    .add("manageFilters", manageFilters)
+    .add("technicalTranslation", technicalTranslation)
+    .add("accessSeparator", accessSeparator)
+    .add("viewAccessRights", viewAccessRights)
+    .add("viewRecordRules", viewRecordRules);
diff --git a/addons/web/static/tests/core/debug/debug_manager_tests.js b/addons/web/static/tests/core/debug/debug_manager_tests.js
index 4d09b8f31d8..3d725c4112e 100644
--- a/addons/web/static/tests/core/debug/debug_manager_tests.js
+++ b/addons/web/static/tests/core/debug/debug_manager_tests.js
@@ -19,7 +19,7 @@ import {
 import { click, getFixture, legacyExtraNextTick, patchWithCleanup } from "../../helpers/utils";
 import { createWebClient, doAction, getActionManagerServerData } from "../../webclient/helpers";
 import { openViewItem } from "@web/webclient/debug_items";
-import { editView, editSearchView } from "@web/legacy/debug_manager";
+import { editSearchView, editView } from "@web/views/debug_items";
 
 const { Component, mount, tags } = owl;
 const { xml } = tags;
diff --git a/addons/web/static/tests/webclient/actions/window_action_tests.js b/addons/web/static/tests/webclient/actions/window_action_tests.js
index 81066885e67..a0fb9733bbf 100644
--- a/addons/web/static/tests/webclient/actions/window_action_tests.js
+++ b/addons/web/static/tests/webclient/actions/window_action_tests.js
@@ -2,7 +2,7 @@
 
 import { browser } from "@web/core/browser/browser";
 import { registry } from "@web/core/registry";
-import { editView } from "@web/legacy/debug_manager";
+import { editView } from "@web/views/debug_items";
 import { clearUncommittedChanges } from "@web/webclient/actions/action_service";
 import AbstractView from "web.AbstractView";
 import FormView from "web.FormView";