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";