diff --git a/addons/spreadsheet/static/src/chart/odoo_menu/figure_component.js b/addons/spreadsheet/static/src/chart/odoo_menu/figure_component.js index acb94540798..096c962e38f 100644 --- a/addons/spreadsheet/static/src/chart/odoo_menu/figure_component.js +++ b/addons/spreadsheet/static/src/chart/odoo_menu/figure_component.js @@ -3,18 +3,29 @@ import { patch } from "@web/core/utils/patch"; import * as spreadsheet from "@odoo/o-spreadsheet"; import { useService } from "@web/core/utils/hooks"; +import { _t } from "@web/core/l10n/translation"; patch(spreadsheet.components.FigureComponent.prototype, { setup() { super.setup(); this.menuService = useService("menu"); this.actionService = useService("action"); + this.notificationService = useService("notification"); }, async navigateToOdooMenu() { const menu = this.env.model.getters.getChartOdooMenu(this.props.figure.id); if (!menu) { throw new Error(`Cannot find any menu associated with the chart`); } + if (!menu.actionID) { + this.notificationService.add( + _t( + "The menu linked to this chart doesn't have an corresponding action. Please link the chart to another menu." + ), + { type: "danger" } + ); + return; + } await this.actionService.doAction(menu.actionID); }, get hasOdooMenu() { diff --git a/addons/spreadsheet/static/tests/charts/ui/link_chart_figure_test.js b/addons/spreadsheet/static/tests/charts/ui/link_chart_figure_test.js index bc701e3ce06..ac303c78ddc 100644 --- a/addons/spreadsheet/static/tests/charts/ui/link_chart_figure_test.js +++ b/addons/spreadsheet/static/tests/charts/ui/link_chart_figure_test.js @@ -9,6 +9,7 @@ import { menuService } from "@web/webclient/menus/menu_service"; import { actionService } from "@web/webclient/actions/action_service"; import { mountSpreadsheet } from "@spreadsheet/../tests/utils/ui"; import { createModelWithDataSource } from "@spreadsheet/../tests/utils/model"; +import { makeFakeNotificationService } from "@web/../tests/helpers/mock_services"; const chartId = "uuid1"; @@ -80,6 +81,13 @@ QUnit.module( appID: 1, actionID: "menuAction2", }, + 3: { + id: 3, + children: [], + name: "test menu 2", + xmlid: "documents_spreadsheet.test.menu_without_action", + appID: 1, + }, }; this.serverData.actions = { menuAction: { @@ -328,5 +336,41 @@ QUnit.module( assert.verifySteps(["doAction"]); }); + + QUnit.test( + "Trying to open a menu without an action sends a notification to the user", + async function (assert) { + mockActionService(assert, "doAction"); + const notificationMock = (message) => { + assert.step(message); + return () => {}; + }; + const notificationService = makeFakeNotificationService(notificationMock); + registry.category("services").add("notification", notificationService, { + force: true, + }); + + const model = await createModelWithDataSource({ + serverData: this.serverData, + }); + const fixture = await mountSpreadsheet(model); + + createBasicChart(model, chartId); + model.dispatch("LINK_ODOO_MENU_TO_CHART", { + chartId, + odooMenuId: "documents_spreadsheet.test.menu_without_action", + }); + await nextTick(); + + await clickChartExternalLink(fixture); + + const expectedNotificationMessage = + "The menu linked to this chart doesn't have an corresponding action. Please link the chart to another menu."; + assert.verifySteps( + [expectedNotificationMessage], + "Notification was send and doAction wasn't called" + ); + } + ); } ); diff --git a/addons/spreadsheet/tests/validate_spreadsheet_data.py b/addons/spreadsheet/tests/validate_spreadsheet_data.py index 265370bb792..e2ad23dba48 100644 --- a/addons/spreadsheet/tests/validate_spreadsheet_data.py +++ b/addons/spreadsheet/tests/validate_spreadsheet_data.py @@ -182,7 +182,7 @@ def fields_in_spreadsheet(data): return dict(fields_by_model) -def xml_ids_in_spreadsheet(data): +def menus_xml_ids_in_spreadsheet(data): return set(data.get("chartOdooMenusReferences", {}).values()) | { url[len(xml_id_url_prefix):] @@ -212,9 +212,14 @@ class ValidateSpreadsheetData(TransactionCase): if field.relational: field_model = field.comodel_name - for xml_id in xml_ids_in_spreadsheet(data): + for xml_id in menus_xml_ids_in_spreadsheet(data): record = self.env.ref(xml_id, raise_if_not_found=False) if not record: raise AssertionError( f"xml id '{xml_id}' used in spreadsheet '{spreadsheet_name}' does not exist" ) + # check that the menu has an action. Root menus always have an action. + if not record.action and record.parent_id.id: + raise AssertionError( + f"menu with xml id '{xml_id}' used in spreadsheet '{spreadsheet_name}' does not have an action" + )