mirror of
https://github.com/bringout/oca-ocb-report.git
synced 2026-04-19 23:22:03 +02:00
Initial commit: Report packages
This commit is contained in:
commit
bc5e1e9efa
604 changed files with 474102 additions and 0 deletions
|
|
@ -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);
|
||||
});
|
||||
|
|
@ -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"
|
||||
);
|
||||
});
|
||||
|
|
@ -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"]);
|
||||
});
|
||||
|
|
@ -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"]);
|
||||
});
|
||||
|
|
@ -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"
|
||||
);
|
||||
});
|
||||
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -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: {},
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue