[FIX] spreadsheet, spreadsheet_dashboard: adapt to spreadsheet last update

closes odoo/odoo#102358

Related: odoo/enterprise#32366
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
This commit is contained in:
Pierre Rousseau
2022-10-06 17:00:21 +02:00
parent 7578cfa109
commit 347294a8d2
18 changed files with 75 additions and 237 deletions
+8 -2
View File
@@ -37,8 +37,14 @@ readonlyAllowedCommands.add("ADD_LIST_DOMAIN");
cellMenuRegistry.add("list_see_record", {
name: _lt("See record"),
sequence: 200,
action: SEE_RECORD_LIST,
isVisible: SEE_RECORD_LIST_VISIBLE,
action: async (env) => {
const cell = env.model.getters.getActiveCell();
await SEE_RECORD_LIST(cell, env);
},
isVisible: (env) => {
const cell = env.model.getters.getActiveCell();
return SEE_RECORD_LIST_VISIBLE(cell);
},
});
inverseCommandRegistry
@@ -5,8 +5,7 @@ import { getFirstListFunction, getNumberOfListFormulas } from "./list_helpers";
const { astToFormula } = spreadsheet;
export const SEE_RECORD_LIST = async (env) => {
const cell = env.model.getters.getActiveCell();
export const SEE_RECORD_LIST = async (cell, env) => {
const { col, row, sheetId } = env.model.getters.getCellPosition(cell.id);
if (!cell) {
return;
@@ -31,7 +30,12 @@ export const SEE_RECORD_LIST = async (env) => {
});
};
export const SEE_RECORD_LIST_VISIBLE = (env) => {
const cell = env.model.getters.getActiveCell();
return cell && getNumberOfListFormulas(cell.content) === 1;
export const SEE_RECORD_LIST_VISIBLE = (cell) => {
return (
cell &&
cell.evaluated.value !== "" &&
!cell.evaluated.error &&
getNumberOfListFormulas(cell.content) === 1 &&
getFirstListFunction(cell.content).functionName === "ODOO.LIST"
);
};
@@ -14,47 +14,9 @@ export default class ListUIPlugin extends spreadsheet.UIPlugin {
super(getters, history, dispatch, config, selection);
/** @type {string} */
this.selectedListId = undefined;
this.selection.observe(this, {
handleEvent: this.handleEvent.bind(this),
});
this.env = config.evalContext.env;
}
handleEvent(event) {
switch (event.type) {
case "ZonesSelected":
if (this.getters.isDashboard()) {
const sheetId = this.getters.getActiveSheetId();
const { col, row } = event.anchor.cell;
const cell = this.getters.getCell(sheetId, col, row);
if (cell && cell.content.startsWith("=ODOO.LIST(")) {
const { args } = getFirstListFunction(cell.content);
const evaluatedArgs = args
.map(astToFormula)
.map((arg) => this.getters.evaluateFormula(arg));
if (evaluatedArgs.length < 3) {
return;
}
const listId = this.getters.getListIdFromPosition(sheetId, col, row);
const { model } = this.getters.getListDefinition(listId);
const dataSource = this.getters.getListDataSource(listId);
const recordId = dataSource.getIdFromPosition(evaluatedArgs[1] - 1);
if (!recordId) {
return;
}
this.env.services.action.doAction({
type: "ir.actions.act_window",
res_model: model,
res_id: recordId,
views: [[false, "form"]],
view_mode: "form",
});
}
}
break;
}
}
/**
* Handle a spreadsheet command
* @param {Object} cmd Command
+8 -2
View File
@@ -36,8 +36,14 @@ readonlyAllowedCommands.add("ADD_PIVOT_DOMAIN");
cellMenuRegistry.add("pivot_see_records", {
name: _lt("See records"),
sequence: 175,
action: SEE_RECORDS_PIVOT,
isVisible: SEE_RECORDS_PIVOT_VISIBLE,
action: async (env) => {
const cell = env.model.getters.getActiveCell();
await SEE_RECORDS_PIVOT(cell, env);
},
isVisible: (env) => {
const cell = env.model.getters.getActiveCell();
return SEE_RECORDS_PIVOT_VISIBLE(cell);
},
});
inverseCommandRegistry
@@ -4,8 +4,7 @@ import { getFirstPivotFunction, getNumberOfPivotFormulas } from "./pivot_helpers
const { astToFormula } = spreadsheet;
export const SEE_RECORDS_PIVOT = async (env) => {
const cell = env.model.getters.getActiveCell();
export const SEE_RECORDS_PIVOT = async (cell, env) => {
const { col, row, sheetId } = env.model.getters.getCellPosition(cell.id);
const { args, functionName } = getFirstPivotFunction(cell.content);
const evaluatedArgs = args
@@ -36,8 +35,7 @@ export const SEE_RECORDS_PIVOT = async (env) => {
});
};
export const SEE_RECORDS_PIVOT_VISIBLE = (env) => {
const cell = env.model.getters.getActiveCell();
export const SEE_RECORDS_PIVOT_VISIBLE = (cell) => {
return (
cell &&
cell.evaluated.value !== "" &&
@@ -415,25 +415,6 @@ QUnit.module("spreadsheet > list plugin", {}, () => {
assert.deepEqual(model.exportData().lists["1"].domain, [["foo", "in", [55]]]);
});
QUnit.test("Can see record of a list in dashboard mode", async function (assert) {
const fakeActionService = {
dependencies: [],
start: (env) => ({
doAction: (params) => {
assert.step(params.res_model);
assert.step(params.res_id.toString());
},
}),
};
registry.category("services").add("action", fakeActionService);
const { model } = await createSpreadsheetWithList();
model.updateMode("dashboard");
const listId = model.getters.getListIds()[0];
const dataSource = model.getters.getListDataSource(listId);
selectCell(model, "A2");
assert.verifySteps(["partner", dataSource.getIdFromPosition(0).toString()]);
});
QUnit.test(
"Cannot see record of a list in dashboard mode if wrong list formula",
async function (assert) {
@@ -76,13 +76,6 @@ export class SpreadsheetDashboardAction extends Component {
this.state = useState({ activeDashboard: undefined });
}
getStyle(model) {
const sheetId = model.getters.getActiveSheetId();
const { right } = model.getters.getSheetZone(sheetId);
const { end } = model.getters.getColDimensions(sheetId, right);
return `max-width: ${end}px;`;
}
/**
* @returns {number | undefined}
*/
@@ -26,11 +26,14 @@
.o_renderer {
height: 100%;
margin: auto;
.o-spreadsheet {
height: 100%;
.o-grid {
background-color: white;
}
canvas {
border-top: 0px;
}
@@ -50,7 +50,7 @@
</div>
<t t-else="">
<MobileFigureContainer t-if="env.isSmall" spreadsheetModel="dashboard.model" t-key="dashboard.id"/>
<div t-else="" class="o_renderer" t-att-style="getStyle(dashboard.model)">
<div t-else="" class="o_renderer">
<Spreadsheet
model="dashboard.model"
t-key="dashboard.id"/>
@@ -1,90 +0,0 @@
/** @odoo-module */
import { getNumberOfListFormulas } from "@spreadsheet/list/list_helpers";
import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
import { getNumberOfPivotFormulas } from "@spreadsheet/pivot/pivot_helpers";
import { patch } from "@web/core/utils/patch";
const { Grid } = spreadsheet.components;
function positionToZone(position) {
return { left: position.col, right: position.col, top: position.row, bottom: position.row };
}
/**
* @typedef ClickableCell
* @property {number} left Left position of the cell
* @property {number} top Top position of the cell
* @property {number} width Width of the cell
* @property {number} height Height of the cell
* @property {number} key Unique identifier
*/
/* Used for t-key */
let key = 0;
patch(Grid.prototype, "spreadsheet_dashboard_grid_cursor", {
getCellClickableStyle(coordinates) {
return `
top: ${coordinates.top}px;
left: ${coordinates.left}px;
width: ${coordinates.width}px;
height: ${coordinates.height}px;
`;
},
/**
* Get all the boxes for the cell in the sheet view that are clickable.
* This function is used to render an overlay over each clickable cell in
* order to display a pointer cursor.
*
* @returns {Array<ClickableCell>}
*/
getClickableCells() {
const cells = [];
const sheetId = this.env.model.getters.getActiveSheetId();
for (const col of this.env.model.getters.getSheetViewVisibleCols()) {
for (const row of this.env.model.getters.getSheetViewVisibleRows()) {
const cell = this.env.model.getters.getCell(sheetId, col, row);
if (this.isClickable(cell)) {
let zone;
if (this.env.model.getters.isInMerge(sheetId, col, row)) {
zone = this.env.model.getters.getMerge(sheetId, col, row);
} else {
zone = positionToZone({ col, row });
}
const rect = this.env.model.getters.getVisibleRect(zone);
cells.push({
left: rect.x,
top: rect.y,
width: rect.width,
height: rect.height,
key: ++key,
});
}
}
}
return cells;
},
isClickable(cell) {
if (!cell) {
return false;
}
// Links
if (cell.isLink()) {
return true;
}
// Pivot / Lists
if (
cell.isFormula() &&
cell.evaluated.value !== "" &&
!cell.evaluated.error &&
(getNumberOfPivotFormulas(cell.content) === 1 ||
getNumberOfListFormulas(cell.content) === 1)
) {
return true;
}
return false;
},
});
@@ -1,4 +0,0 @@
.o-dashboard-clickable-cell {
position: absolute;
cursor: pointer;
}
@@ -1,12 +0,0 @@
<odoo>
<t t-name="spreadsheet_dashboard.o-spreadsheet-Grid" t-inherit="spreadsheet.o-spreadsheet-Grid" t-inherit-mode="extension" owl="1">
<xpath expr="//div[hasclass('o-grid-overlay')]" position="inside">
<div t-if="env.model.getters.isDashboard()"
t-foreach="getClickableCells()"
t-as="cell"
class="o-dashboard-clickable-cell"
t-att-style="getCellClickableStyle(cell)"
t-key="cell.key"/>
</xpath>
</t>
</odoo>
@@ -0,0 +1,12 @@
/** @odoo-module */
import { SEE_RECORD_LIST, SEE_RECORD_LIST_VISIBLE } from "@spreadsheet/list/list_actions";
import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
const { clickableCellRegistry } = spreadsheet.registries;
clickableCellRegistry.add("list", {
condition: SEE_RECORD_LIST_VISIBLE,
action: SEE_RECORD_LIST,
sequence: 10,
});
@@ -1,15 +0,0 @@
/** @odoo-module */
import { _lt } from "@web/core/l10n/translation";
import { SEE_RECORD_LIST, SEE_RECORD_LIST_VISIBLE } from "@spreadsheet/list/list_actions";
import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
const { dashboardMenuRegistry } = spreadsheet.registries;
dashboardMenuRegistry.add("see_records_list", {
name: _lt("See record"),
sequence: 20,
action: SEE_RECORD_LIST,
isReadonlyAllowed: true,
isVisible: SEE_RECORD_LIST_VISIBLE,
});
@@ -0,0 +1,28 @@
/** @odoo-module */
import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
import { SEE_RECORDS_PIVOT, SEE_RECORDS_PIVOT_VISIBLE } from "@spreadsheet/pivot/pivot_actions";
import { getFirstPivotFunction } from "@spreadsheet/pivot/pivot_helpers";
const { clickableCellRegistry } = spreadsheet.registries;
clickableCellRegistry.add("pivot", {
condition: SEE_RECORDS_PIVOT_VISIBLE,
action: SEE_RECORDS_PIVOT,
sequence: 3,
});
clickableCellRegistry.add("pivot_set_filter_matching", {
condition: (cell, env) => {
return (
SEE_RECORDS_PIVOT_VISIBLE(cell) &&
getFirstPivotFunction(cell.content).functionName === "ODOO.PIVOT.HEADER" &&
env.model.getters.getFiltersMatchingPivot(cell.content).length > 0
);
},
action: (cell, env) => {
const filters = env.model.getters.getFiltersMatchingPivot(cell.content);
env.model.dispatch("SET_MANY_GLOBAL_FILTER_VALUE", { filters });
},
sequence: 2,
});
@@ -1,15 +0,0 @@
/** @odoo-module */
import { _lt } from "@web/core/l10n/translation";
import { SEE_RECORDS_PIVOT, SEE_RECORDS_PIVOT_VISIBLE } from "@spreadsheet/pivot/pivot_actions";
import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
const { dashboardMenuRegistry } = spreadsheet.registries;
dashboardMenuRegistry.add("see_records_pivot", {
name: _lt("See records"),
sequence: 10,
action: SEE_RECORDS_PIVOT,
isReadonlyAllowed: true,
isVisible: SEE_RECORDS_PIVOT_VISIBLE,
});
@@ -24,7 +24,7 @@ async function createDashboardWithModel(model) {
return getFixture();
}
QUnit.module("spreadsheet_dashboard > grid cursor");
QUnit.module("spreadsheet_dashboard > clickable cells");
QUnit.test("A link in a dashboard should be clickable", async (assert) => {
const data = {
@@ -1,13 +1,10 @@
/** @odoo-module */
import { getFixture, click, triggerEvent, legacyExtraNextTick } from "@web/../tests/helpers/utils";
import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
import { getFixture, click, legacyExtraNextTick } from "@web/../tests/helpers/utils";
import { getDashboardServerData } from "../utils/data";
import { getBasicData, getBasicListArchs } from "@spreadsheet/../tests/utils/data";
import { createSpreadsheetDashboard } from "../utils/dashboard_action";
const { dashboardMenuRegistry } = spreadsheet.registries;
QUnit.module("spreadsheet_dashboard > Dashboard > Dashboard action");
QUnit.test("display available spreadsheets", async (assert) => {
@@ -90,15 +87,6 @@ QUnit.test("display error message", async (assert) => {
assert.containsNone(fixture, ".o_renderer .error", "It should not display an error");
});
QUnit.test("Dashboard registry contains see records of pivots and lists", (assert) => {
const records = dashboardMenuRegistry.getAll();
assert.strictEqual(records.length, 2);
assert.strictEqual(records[0].id, "see_records_pivot");
assert.ok(records[0].isReadonlyAllowed);
assert.strictEqual(records[1].id, "see_records_list");
assert.ok(records[1].isReadonlyAllowed);
});
QUnit.test(
"Last selected spreadsheet is kept when go back from breadcrumb",
async function (assert) {
@@ -145,14 +133,7 @@ QUnit.test(
const fixture = getFixture();
await createSpreadsheetDashboard({ serverData });
await click(fixture, ".o_search_panel li:last-child");
const rect = fixture
.querySelector(".o-spreadsheet .o-grid-overlay")
.getBoundingClientRect();
await triggerEvent(fixture, ".o-spreadsheet .o-grid-overlay", "contextmenu", {
pageX: 5 + rect.left,
pageY: 5 + rect.top,
});
await click(fixture, ".o-menu-item[data-name='see_records_pivot']");
await click(fixture, ".o-dashboard-clickable-cell");
await legacyExtraNextTick();
assert.containsOnce(fixture, ".o_list_view");
await click(document.body.querySelector(".o_back_button"));