Initial commit: Report packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:51 +02:00
commit bc5e1e9efa
604 changed files with 474102 additions and 0 deletions

View file

@ -0,0 +1,96 @@
/** @odoo-module */
import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
import { getFixture } from "@web/../tests/helpers/utils";
import { getDashboardServerData } from "../utils/data";
import { createSpreadsheetDashboard } from "../utils/dashboard_action";
import { getBasicData } from "@spreadsheet/../tests/utils/data";
const { Model } = spreadsheet;
async function createDashboardWithModel(model) {
return createDashboardWithData(model.exportData());
}
async function createDashboardWithData(spreadsheetData) {
const serverData = getDashboardServerData();
const json = JSON.stringify(spreadsheetData);
const dashboard = serverData.models["spreadsheet.dashboard"].records[0];
dashboard.raw = json;
dashboard.json_data = json;
serverData.models = {
...serverData.models,
...getBasicData(),
};
await createSpreadsheetDashboard({ serverData, spreadsheetId: dashboard.id });
return getFixture();
}
QUnit.module("spreadsheet_dashboard > clickable cells");
QUnit.test("A link in a dashboard should be clickable", async (assert) => {
const data = {
sheets: [
{
cells: { A1: { content: "[Odoo](https://odoo.com)" } },
},
],
};
const model = new Model(data, { mode: "dashboard" });
const target = await createDashboardWithModel(model);
assert.containsOnce(target, ".o-dashboard-clickable-cell");
});
QUnit.test("Invalid pivot/list formulas should not be clickable", async (assert) => {
const data = {
sheets: [
{
cells: {
A1: { content: `=ODOO.PIVOT("1", "measure")` },
A2: { content: `=ODOO.LIST("1", 1, "name")` },
},
},
],
};
const model = new Model(data, { mode: "dashboard" });
const target = await createDashboardWithModel(model);
assert.containsNone(target, ".o-dashboard-clickable-cell");
});
QUnit.test("pivot/list formulas should be clickable", async (assert) => {
const data = {
sheets: [
{
cells: {
A1: { content: '=ODOO.PIVOT(1,"probability")' },
A2: { content: '=ODOO.LIST(1, 1, "foo")' },
},
},
],
pivots: {
1: {
id: 1,
colGroupBys: [],
domain: [],
measures: [{ field: "probability", operator: "avg" }],
model: "partner",
rowGroupBys: [],
context: {},
fieldMatching: {},
},
},
lists: {
1: {
id: 1,
columns: ["foo", "contact_name"],
domain: [],
model: "partner",
orderBy: [],
context: {},
fieldMatching: {},
},
},
};
const target = await createDashboardWithData(data);
assert.containsN(target, ".o-dashboard-clickable-cell", 2);
});

View file

@ -0,0 +1,254 @@
/** @odoo-module */
import {
getFixture,
click,
legacyExtraNextTick,
nextTick,
editInput,
} from "@web/../tests/helpers/utils";
import { getDashboardServerData } from "../utils/data";
import { getBasicData, getBasicListArchs } from "@spreadsheet/../tests/utils/data";
import { createSpreadsheetDashboard } from "../utils/dashboard_action";
import { registry } from "@web/core/registry";
import { errorService } from "@web/core/errors/error_service";
import { RPCError } from "@web/core/network/rpc_service";
QUnit.module("spreadsheet_dashboard > Dashboard > Dashboard action");
function getServerData(spreadsheetData) {
const serverData = getDashboardServerData();
serverData.models = {
...serverData.models,
...getBasicData(),
};
serverData.views = getBasicListArchs();
serverData.models["spreadsheet.dashboard.group"].records = [
{
dashboard_ids: [789],
id: 1,
name: "Pivot",
},
];
serverData.models["spreadsheet.dashboard"].records = [
{
id: 789,
name: "Spreadsheet with Pivot",
json_data: JSON.stringify(spreadsheetData),
raw: JSON.stringify(spreadsheetData),
dashboard_group_id: 1,
},
];
return serverData;
}
QUnit.test("display available spreadsheets", async (assert) => {
await createSpreadsheetDashboard();
assert.containsN(getFixture(), ".o_search_panel section", 2);
assert.containsN(getFixture(), ".o_search_panel li", 3);
});
QUnit.test("display the active spreadsheet", async (assert) => {
await createSpreadsheetDashboard();
assert.containsOnce(
getFixture(),
".o_search_panel li.active",
"It should have one active element"
);
assert.containsOnce(getFixture(), ".o-spreadsheet", "It should display the spreadsheet");
});
QUnit.test("load action with specific dashboard", async (assert) => {
await createSpreadsheetDashboard({ spreadsheetId: 3 });
const active = getFixture().querySelector(".o_search_panel li.active");
assert.strictEqual(active.innerText, "Dashboard Accounting 1");
});
QUnit.test("can switch spreadsheet", async (assert) => {
await createSpreadsheetDashboard();
const fixture = getFixture();
const spreadsheets = fixture.querySelectorAll(".o_search_panel li");
assert.ok(spreadsheets[0].className.includes("active"));
assert.notOk(spreadsheets[1].className.includes("active"));
assert.notOk(spreadsheets[2].className.includes("active"));
await click(spreadsheets[1]);
assert.notOk(spreadsheets[0].className.includes("active"));
assert.ok(spreadsheets[1].className.includes("active"));
assert.notOk(spreadsheets[2].className.includes("active"));
});
QUnit.test("display no dashboard message", async (assert) => {
await createSpreadsheetDashboard({
mockRPC: function (route, { model, method, args }) {
if (method === "search_read" && model === "spreadsheet.dashboard.group") {
return [];
}
},
});
const fixture = getFixture();
assert.containsNone(fixture, ".o_search_panel li", "It should not display any spreadsheet");
assert.strictEqual(
fixture.querySelector(".dashboard-loading-status").innerText,
"No available dashboard",
"It should display no dashboard message"
);
});
QUnit.test("display error message", async (assert) => {
registry.category("services").add("error", errorService);
await createSpreadsheetDashboard({
mockRPC: function (route, args) {
if (
args.model === "spreadsheet.dashboard" &&
((args.method === "read" && args.args[0][0] === 2 && args.args[1][0] === "raw") ||
// this is not correct from a module dependency POV but it's required for the test
// to pass when `spreadsheet_dashboard_edition` module is installed
(args.method === "join_spreadsheet_session" && args.args[0] === 2))
) {
const error = new RPCError();
error.data = {};
throw error;
}
},
});
const fixture = getFixture();
const spreadsheets = fixture.querySelectorAll(".o_search_panel li");
assert.containsOnce(fixture, ".o-spreadsheet", "It should display the spreadsheet");
await click(spreadsheets[1]);
assert.containsOnce(
fixture,
".o_spreadsheet_dashboard_action .dashboard-loading-status.error",
"It should display an error"
);
await click(spreadsheets[0]);
assert.containsOnce(fixture, ".o-spreadsheet", "It should display the spreadsheet");
assert.containsNone(fixture, ".o_renderer .error", "It should not display an error");
});
QUnit.test("load dashboard that doesn't exist", async (assert) => {
registry.category("services").add("error", errorService);
await createSpreadsheetDashboard({
spreadsheetId: 999,
});
const fixture = getFixture();
assert.containsOnce(
fixture,
".o_spreadsheet_dashboard_action .dashboard-loading-status.error",
"It should display an error"
);
});
QUnit.test(
"Last selected spreadsheet is kept when go back from breadcrumb",
async function (assert) {
const spreadsheetData = {
sheets: [
{
id: "sheet1",
cells: { A1: { content: `=PIVOT("1", "probability")` } },
},
],
pivots: {
1: {
id: 1,
colGroupBys: ["foo"],
domain: [],
measures: [{ field: "probability", operator: "avg" }],
model: "partner",
rowGroupBys: ["bar"],
},
},
};
const serverData = getServerData(spreadsheetData);
const fixture = getFixture();
await createSpreadsheetDashboard({ serverData });
await click(fixture, ".o_search_panel li:last-child");
await click(fixture, ".o-dashboard-clickable-cell");
await legacyExtraNextTick();
assert.containsOnce(fixture, ".o_list_view");
await click(document.body.querySelector(".o_back_button"));
await legacyExtraNextTick();
assert.hasClass(fixture.querySelector(".o_search_panel li:last-child"), "active");
}
);
QUnit.test(
"Can clear filter date filter value that defaults to current period",
async function (assert) {
const spreadsheetData = {
globalFilters: [
{
id: "1",
type: "date",
label: "Date Filter",
rangeType: "year",
defaultValue: {},
defaultsToCurrentPeriod: true,
pivotFields: {},
},
],
};
const serverData = getServerData(spreadsheetData);
const fixture = getFixture();
await createSpreadsheetDashboard({ serverData });
const year = fixture.querySelector(".o_cp_top_right input.o_datepicker_input");
const this_year = luxon.DateTime.local().year;
assert.equal(year.value, String(this_year));
const input = fixture.querySelector(
"input.o_datepicker_input.o_input.datetimepicker-input"
);
await click(input);
await editInput(input, null, String(this_year - 1));
await nextTick();
assert.equal(year.value, String(this_year - 1));
assert.containsOnce(fixture, ".o_cp_top_right .fa-times");
await click(fixture.querySelector(".o_cp_top_right .fa-times"));
assert.containsNone(fixture, ".o_cp_top_right .fa-times");
assert.equal(year.value, "");
}
);
QUnit.test("Global filter with same id is not shared between dashboards", async function (assert) {
const spreadsheetData = {
globalFilters: [
{
id: "1",
type: "relation",
label: "Relation Filter",
modelName: "product",
},
],
};
const serverData = getServerData(spreadsheetData);
serverData.models["spreadsheet.dashboard"].records.push({
id: 790,
name: "Spreadsheet dup. with Pivot",
json_data: JSON.stringify(spreadsheetData),
raw: JSON.stringify(spreadsheetData),
dashboard_group_id: 1,
});
serverData.models["spreadsheet.dashboard.group"].records[0].dashboard_ids = [789, 790];
const fixture = getFixture();
await createSpreadsheetDashboard({ serverData });
assert.containsNone(
fixture,
".o-filter-value .o_tag_badge_text",
"It should not display any filter value"
);
await click(fixture.querySelector(".o-autocomplete--input.o_input"));
await click(fixture.querySelector(".dropdown-item"));
assert.containsN(
fixture,
".o-filter-value .o_tag_badge_text",
1,
"It should not display any filter value"
);
await click(fixture.querySelector(".o_search_panel li:last-child"));
assert.containsNone(
fixture,
".o-filter-value .o_tag_badge_text",
"It should not display any filter value"
);
});

View file

@ -0,0 +1,259 @@
/** @odoo-module */
import { ormService } from "@web/core/orm_service";
import { registry } from "@web/core/registry";
import { makeTestEnv } from "@web/../tests/helpers/mock_env";
import {
DashboardLoader,
Status,
} from "@spreadsheet_dashboard/bundle/dashboard_action/dashboard_loader";
import { nextTick, patchWithCleanup } from "@web/../tests/helpers/utils";
import { getDashboardServerData } from "../utils/data";
import { waitForDataSourcesLoaded } from "@spreadsheet/../tests/utils/model";
import { getCellValue } from "@spreadsheet/../tests/utils/getters";
import { RPCError } from "@web/core/network/rpc_service";
/**
* @param {object} [params]
* @param {object} [params.serverData]
* @param {function} [params.mockRPC]
* @returns {Promise<DashboardLoader>}
*/
async function createDashboardLoader(params = {}) {
registry.category("services").add("orm", ormService);
const env = await makeTestEnv({
serverData: params.serverData || getDashboardServerData(),
mockRPC: params.mockRPC,
});
return new DashboardLoader(env, env.services.orm, async (dashboardId) => {
const [record] = await env.services.orm.read(
"spreadsheet.dashboard",
[dashboardId],
["raw"]
);
return { data: record.raw, revisions: [] };
});
}
QUnit.module("spreadsheet_dashboard > Dashboard loader");
QUnit.test("load all dashboards of all containers", async (assert) => {
const loader = await createDashboardLoader();
loader.load();
assert.deepEqual(loader.getDashboardGroups(), []);
await nextTick();
assert.deepEqual(loader.getDashboardGroups(), [
{
id: 1,
name: "Container 1",
dashboards: [
{
id: 1,
displayName: "Dashboard CRM 1",
status: Status.NotLoaded,
},
{
id: 2,
displayName: "Dashboard CRM 2",
status: Status.NotLoaded,
},
],
},
{
id: 2,
name: "Container 2",
dashboards: [
{
id: 3,
displayName: "Dashboard Accounting 1",
status: Status.NotLoaded,
},
],
},
]);
});
QUnit.test("load twice does not duplicate spreadsheets", async (assert) => {
const loader = await createDashboardLoader();
await loader.load();
assert.deepEqual(loader.getDashboardGroups()[1].dashboards, [
{ id: 3, displayName: "Dashboard Accounting 1", status: Status.NotLoaded },
]);
await loader.load();
assert.deepEqual(loader.getDashboardGroups()[1].dashboards, [
{ id: 3, displayName: "Dashboard Accounting 1", status: Status.NotLoaded },
]);
});
QUnit.test("load spreadsheet data", async (assert) => {
const loader = await createDashboardLoader();
await loader.load();
const result = loader.getDashboard(3);
assert.strictEqual(result.status, Status.Loading);
await nextTick();
assert.strictEqual(result.status, Status.Loaded);
assert.ok(result.model);
});
QUnit.test("load spreadsheet data only once", async (assert) => {
const loader = await createDashboardLoader({
mockRPC: function (route, args) {
if (args.method === "read") {
assert.step(`spreadsheet ${args.args[0]} loaded`);
}
},
});
await loader.load();
let result = loader.getDashboard(3);
await nextTick();
assert.strictEqual(result.status, Status.Loaded);
assert.verifySteps(["spreadsheet 1,2,3 loaded", "spreadsheet 3 loaded"]);
result = loader.getDashboard(3);
await nextTick();
assert.strictEqual(result.status, Status.Loaded);
assert.verifySteps([]);
});
QUnit.test("don't return empty dashboard group", async (assert) => {
const loader = await createDashboardLoader({
mockRPC: async function (route, args) {
if (args.method === "search_read" && args.model === "spreadsheet.dashboard.group") {
return [
{
id: 45,
name: "Group A",
dashboard_ids: [1],
},
{
id: 46,
name: "Group B",
dashboard_ids: [],
},
];
}
},
});
await loader.load();
assert.deepEqual(loader.getDashboardGroups(), [
{
id: 45,
name: "Group A",
dashboards: [
{
id: 1,
displayName: "Dashboard CRM 1",
status: Status.NotLoaded,
},
],
},
]);
});
QUnit.test("load multiple spreadsheets", async (assert) => {
const loader = await createDashboardLoader({
mockRPC: function (route, args) {
if (args.method === "read") {
assert.step(`spreadsheet ${args.args[0]} loaded`);
}
},
});
await loader.load();
assert.verifySteps(["spreadsheet 1,2,3 loaded"]);
loader.getDashboard(1);
await nextTick();
assert.verifySteps(["spreadsheet 1 loaded"]);
loader.getDashboard(2);
await nextTick();
assert.verifySteps(["spreadsheet 2 loaded"]);
loader.getDashboard(1);
await nextTick();
assert.verifySteps([]);
});
QUnit.test("load spreadsheet data with error", async (assert) => {
const loader = await createDashboardLoader({
mockRPC: function (route, args) {
if (
args.method === "read" &&
args.model === "spreadsheet.dashboard" &&
args.args[1][0] === "raw"
) {
const error = new RPCError();
error.data = { message: "Bip" };
throw error;
}
},
});
await loader.load();
const result = loader.getDashboard(3);
assert.strictEqual(result.status, Status.Loading);
await result.promise.catch(() => assert.step("error"));
assert.strictEqual(result.status, Status.Error);
assert.strictEqual(result.error.data.message, "Bip");
assert.verifySteps(["error"], "error is thrown");
});
QUnit.test("async formulas are correctly evaluated", async (assert) => {
const spreadsheetData = {
sheets: [
{
id: "sheet1",
cells: {
A1: { content: `=ODOO.CURRENCY.RATE("EUR","USD")` }, // an async formula
},
},
],
};
const serverData = getDashboardServerData();
const dashboardId = 15;
serverData.models["spreadsheet.dashboard"].records = [
{
id: dashboardId,
raw: JSON.stringify(spreadsheetData),
json_data: JSON.stringify(spreadsheetData),
name: "Dashboard Accounting 1",
dashboard_group_id: 2,
},
];
serverData.models["spreadsheet.dashboard.group"].records = [
{ id: 1, name: "Container 1", dashboard_ids: [dashboardId] },
];
const loader = await createDashboardLoader({
serverData,
mockRPC: function (route, args) {
if (args.method === "get_rates_for_spreadsheet") {
const info = args.args[0][0];
return [{ ...info, rate: 0.9 }];
}
},
});
await loader.load();
loader.getDashboard(dashboardId);
await nextTick();
const { model } = loader.getDashboard(dashboardId);
await waitForDataSourcesLoaded(model);
assert.strictEqual(await getCellValue(model, "A1"), 0.9);
});
QUnit.test("Model is in dashboard mode", async (assert) => {
const loader = await createDashboardLoader();
await loader.load();
loader.getDashboard(3);
await nextTick();
const { model } = loader.getDashboard(3);
assert.strictEqual(model.config.mode, "dashboard");
});
QUnit.test("Model is in dashboard mode", async (assert) => {
patchWithCleanup(DashboardLoader.prototype, {
_activateFirstSheet: () => {
assert.step("activate sheet");
},
});
const loader = await createDashboardLoader();
await loader.load();
loader.getDashboard(3);
await nextTick();
assert.verifySteps(["activate sheet"]);
});

View file

@ -0,0 +1,113 @@
/** @odoo-module */
import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
import { registry } from "@web/core/registry";
import { actionService } from "@web/webclient/actions/action_service";
import { menuService } from "@web/webclient/menus/menu_service";
import { spreadsheetLinkMenuCellService } from "@spreadsheet/ir_ui_menu/index";
import { makeTestEnv } from "@web/../tests/helpers/mock_env";
import { selectCell } from "@spreadsheet/../tests/utils/commands";
import { viewService } from "@web/views/view_service";
import { ormService } from "@web/core/orm_service";
import { getMenuServerData } from "@spreadsheet/../tests/links/menu_data_utils";
import { patchWithCleanup } from "@web/../tests/helpers/utils";
const { Model } = spreadsheet;
function beforeEach() {
registry
.category("services")
.add("menu", menuService)
.add("action", actionService)
.add("spreadsheetLinkMenuCell", spreadsheetLinkMenuCellService);
registry.category("services").add("view", viewService, { force: true }); // #action-serv-leg-compat-js-class
registry.category("services").add("orm", ormService, { force: true }); // #action-serv-leg-compat-js-class
}
QUnit.module("spreadsheet_dashboard > link", { beforeEach });
QUnit.test("click a web link", async (assert) => {
patchWithCleanup(window, {
open: (href) => {
assert.step(href.toString());
},
});
const env = await makeTestEnv();
const data = {
sheets: [
{
cells: { A1: { content: "[Odoo](https://odoo.com)" } },
},
],
};
const model = new Model(data, { mode: "dashboard", evalContext: { env } });
selectCell(model, "A1");
assert.verifySteps(["https://odoo.com"]);
});
QUnit.test("click a menu link", async (assert) => {
const fakeActionService = {
name: "action",
start() {
return {
doAction(action) {
assert.step(action);
},
};
},
};
registry.category("services").add("action", fakeActionService, { force: true });
const env = await makeTestEnv({ serverData: getMenuServerData() });
const data = {
sheets: [
{
cells: { A1: { content: "[label](odoo://ir_menu_xml_id/test_menu)" } },
},
],
};
const model = new Model(data, { mode: "dashboard", evalContext: { env } });
selectCell(model, "A1");
assert.verifySteps(["action1"]);
});
QUnit.test("click a menu link", async (assert) => {
const fakeActionService = {
name: "action",
start() {
return {
doAction(action) {
assert.step("do-action");
assert.deepEqual(action, {
context: undefined,
domain: undefined,
name: "an odoo view",
res_model: "partner",
target: "current",
type: "ir.actions.act_window",
views: [[false, "list"]],
});
},
};
},
};
registry.category("services").add("action", fakeActionService, { force: true });
const env = await makeTestEnv({ serverData: getMenuServerData() });
const view = {
name: "an odoo view",
viewType: "list",
action: {
modelName: "partner",
views: [[false, "list"]],
},
};
const data = {
sheets: [
{
cells: { A1: { content: `[a view](odoo://view/${JSON.stringify(view)})` } },
},
],
};
const model = new Model(data, { mode: "dashboard", evalContext: { env } });
selectCell(model, "A1");
assert.verifySteps(["do-action"]);
});

View file

@ -0,0 +1,115 @@
/** @odoo-module */
import { click, getFixture } from "@web/../tests/helpers/utils";
import { createSpreadsheetDashboard } from "../utils/dashboard_action";
import { getDashboardServerData } from "../utils/data";
QUnit.module("spreadsheet_dashboard > Mobile Dashboard action");
QUnit.test("is empty with no figures", async (assert) => {
await createSpreadsheetDashboard();
const fixture = getFixture();
assert.containsOnce(fixture, ".o_mobile_dashboard");
const content = fixture.querySelector(".o_mobile_dashboard");
assert.deepEqual(content.innerText.split("\n"), [
"Dashboard CRM 1",
"Only chart figures are displayed in small screens but this dashboard doesn't contain any",
]);
});
QUnit.test("with no available dashboard", async (assert) => {
const serverData = getDashboardServerData();
serverData.models["spreadsheet.dashboard"].records = [];
serverData.models["spreadsheet.dashboard.group"].records = [];
await createSpreadsheetDashboard({ serverData });
const fixture = getFixture();
const content = fixture.querySelector(".o_mobile_dashboard");
assert.deepEqual(content.innerText, "No available dashboard");
});
QUnit.test("displays figures in first sheet", async (assert) => {
const figure = {
tag: "chart",
height: 500,
width: 500,
x: 100,
y: 100,
data: {
type: "line",
dataSetsHaveTitle: false,
dataSets: ["A1"],
legendPosition: "top",
verticalAxisPosition: "left",
title: "",
},
};
const spreadsheetData = {
sheets: [
{
id: "sheet1",
figures: [{ ...figure, id: "figure1" }],
},
{
id: "sheet2",
figures: [{ ...figure, id: "figure2" }],
},
],
};
const serverData = getDashboardServerData();
serverData.models["spreadsheet.dashboard.group"].records = [
{
dashboard_ids: [789],
id: 1,
name: "Chart",
},
];
serverData.models["spreadsheet.dashboard"].records = [
{
id: 789,
name: "Spreadsheet with chart figure",
json_data: JSON.stringify(spreadsheetData),
raw: JSON.stringify(spreadsheetData),
dashboard_group_id: 1,
},
];
const fixture = getFixture();
await createSpreadsheetDashboard({ serverData });
assert.containsOnce(fixture, ".o-chart-container");
});
QUnit.test("can switch dashboard", async (assert) => {
await createSpreadsheetDashboard();
const fixture = getFixture();
assert.strictEqual(
fixture.querySelector(".o_search_panel_summary").innerText,
"Dashboard CRM 1"
);
await click(fixture, ".o_search_panel_current_selection");
const dashboardElements = [...document.querySelectorAll("section header.list-group-item")];
assert.strictEqual(dashboardElements[0].classList.contains("active"), true);
assert.deepEqual(
dashboardElements.map((el) => el.innerText),
["Dashboard CRM 1", "Dashboard CRM 2", "Dashboard Accounting 1"]
);
await click(dashboardElements[1]);
assert.strictEqual(
fixture.querySelector(".o_search_panel_summary").innerText,
"Dashboard CRM 2"
);
});
QUnit.test("can go back from dashboard selection", async (assert) => {
await createSpreadsheetDashboard();
const fixture = getFixture();
assert.containsOnce(fixture, ".o_mobile_dashboard");
assert.strictEqual(
fixture.querySelector(".o_search_panel_summary").innerText,
"Dashboard CRM 1"
);
await click(fixture, ".o_search_panel_current_selection");
await click(document, ".o_mobile_search_button");
assert.strictEqual(
fixture.querySelector(".o_search_panel_summary").innerText,
"Dashboard CRM 1"
);
});

View file

@ -0,0 +1,25 @@
/** @odoo-module */
import { createWebClient, doAction } from "@web/../tests/webclient/helpers";
import { getDashboardServerData } from "./data";
/**
* @param {object} params
* @param {object} [params.serverData]
* @param {function} [params.mockRPC]
* @param {number} [params.spreadsheetId]
* @returns {Promise}
*/
export async function createSpreadsheetDashboard(params = {}) {
const webClient = await createWebClient({
serverData: params.serverData || getDashboardServerData(),
mockRPC: params.mockRPC,
});
return await doAction(webClient, {
type: "ir.actions.client",
tag: "action_spreadsheet_dashboard",
params: {
dashboard_id: params.spreadsheetId,
},
});
}

View file

@ -0,0 +1,57 @@
/** @odoo-module */
export function getDashboardServerData() {
return {
models: {
"spreadsheet.dashboard": {
fields: {
json_data: { type: "char" },
raw: { type: "char " },
name: { type: "char" },
dashboard_group_id: {
type: "many2one",
relation: "spreadsheet.dashboard.group",
},
},
records: [
{
id: 1,
raw: "{}",
json_data: "{}",
name: "Dashboard CRM 1",
dashboard_group_id: 1,
},
{
id: 2,
raw: "{}",
json_data: "{}",
name: "Dashboard CRM 2",
dashboard_group_id: 1,
},
{
id: 3,
raw: "{}",
json_data: "{}",
name: "Dashboard Accounting 1",
dashboard_group_id: 2,
},
],
},
"spreadsheet.dashboard.group": {
fields: {
name: { type: "char" },
dashboard_ids: {
type: "one2many",
relation: "spreadsheet.dashboard",
relation_field: "dashboard_group_id",
},
},
records: [
{ id: 1, name: "Container 1", dashboard_ids: [1, 2] },
{ id: 2, name: "Container 2", dashboard_ids: [3] },
],
},
},
views: {},
};
}