diff --git a/addons/spreadsheet/static/src/list/list_data_source.js b/addons/spreadsheet/static/src/list/list_data_source.js index e41cc567baf..9a1c6036766 100644 --- a/addons/spreadsheet/static/src/list/list_data_source.js +++ b/addons/spreadsheet/static/src/list/list_data_source.js @@ -35,13 +35,22 @@ export default class ListDataSource extends OdooViewsDataSource { */ constructor(services, params) { super(services, params); - this.limit = params.limit; + this.maxPosition = params.limit; + this.maxPositionFetched = 0; this.data = []; } + /** + * Increase the max position of the list + * @param {number} position + */ + increaseMaxPosition(position) { + this.maxPosition = Math.max(this.maxPosition, position); + } + async _load() { await super._load(); - if (this.limit === 0) { + if (this.maxPosition === 0) { this.data = []; return; } @@ -52,10 +61,11 @@ export default class ListDataSource extends OdooViewsDataSource { this._getFieldsToFetch(), { order: orderByToString(orderBy), - limit: this.limit, + limit: this.maxPosition, context, } ); + this.maxPositionFetched = this.maxPosition; } /** @@ -99,8 +109,8 @@ export default class ListDataSource extends OdooViewsDataSource { */ getListCellValue(position, fieldName) { this._assertDataIsLoaded(); - if (position >= this.limit) { - this.limit = position + 1; + if (position >= this.maxPositionFetched) { + this.increaseMaxPosition(position + 1); // A reload is needed because the asked position is not already loaded. this._triggerFetching(); throw new LoadingDataError(); diff --git a/addons/spreadsheet/static/src/list/plugins/list_core_plugin.js b/addons/spreadsheet/static/src/list/plugins/list_core_plugin.js index 685134bf975..d862af5aaf2 100644 --- a/addons/spreadsheet/static/src/list/plugins/list_core_plugin.js +++ b/addons/spreadsheet/static/src/list/plugins/list_core_plugin.js @@ -9,6 +9,7 @@ import { _t } from "@web/core/l10n/translation"; import { globalFiltersFieldMatchers } from "@spreadsheet/global_filters/plugins/global_filters_core_plugin"; import { sprintf } from "@web/core/utils/strings"; import { checkFilterFieldMatching } from "@spreadsheet/global_filters/helpers"; +import { getFirstListFunction, getNumberOfListFormulas } from "../list_helpers"; /** * @typedef {Object} ListDefinition @@ -143,9 +144,51 @@ export default class ListCorePlugin extends CorePlugin { case "REMOVE_GLOBAL_FILTER": this._onFilterDeletion(cmd.id); break; + + case "START": + for (const sheetId of this.getters.getSheetIds()) { + const cells = this.getters.getCells(sheetId); + for (const cell of Object.values(cells)) { + if (cell.isFormula) { + this._addListPositionToDataSource(cell.content); + } + } + } + break; + case "UPDATE_CELL": + if (cmd.content) { + this._addListPositionToDataSource(cmd.content); + } + break; } } + /** + * Extract the position of the records asked in the given formula and + * increase the max position of the corresponding data source. + * + * @param {string} content Odoo list formula + */ + _addListPositionToDataSource(content) { + if (getNumberOfListFormulas(content) !== 1) { + return; + } + const { functionName, args } = getFirstListFunction(content); + if (functionName !== "ODOO.LIST") { + return; + } + const [listId, positionArg] = args.map((arg) => arg.value.toString()); + if (!(listId in this.lists)) { + return; + } + const position = parseInt(positionArg, 10); + if (isNaN(position)) { + return; + } + const dataSourceId = this.lists[listId].dataSourceId; + this.dataSources.get(dataSourceId).increaseMaxPosition(position); + } + // ------------------------------------------------------------------------- // Getters // ------------------------------------------------------------------------- diff --git a/addons/spreadsheet/static/tests/lists/list_plugin_test.js b/addons/spreadsheet/static/tests/lists/list_plugin_test.js index b6329bdbda2..b5fb44cdba7 100644 --- a/addons/spreadsheet/static/tests/lists/list_plugin_test.js +++ b/addons/spreadsheet/static/tests/lists/list_plugin_test.js @@ -137,7 +137,7 @@ QUnit.module("spreadsheet > list plugin", {}, () => { const { model } = await createSpreadsheetWithList({ linesNumber: 2 }); const [listId] = model.getters.getListIds(); const dataSource = model.getters.getListDataSource(listId); - assert.strictEqual(dataSource.limit, 2); + assert.strictEqual(dataSource.maxPosition, 2); }); QUnit.test("can select a List from cell formula within a formula", async function (assert) { @@ -246,13 +246,9 @@ QUnit.module("spreadsheet > list plugin", {}, () => { model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: "sheet1", sheetIdTo: "sheet2" }); /* * Ask a first time the value => It will trigger a loading of the data source. - * As the list index limit is to 0, there is loading. */ assert.equal(getCellValue(model, "A1"), "Loading..."); await nextTick(); - // Ask a second time the value => The list index limit is raised => reload - assert.equal(getCellValue(model, "A1"), "Loading..."); - await nextTick(); assert.equal(getCellValue(model, "A1"), 12); assert.verifySteps(["partner/fields_get", "partner/search_read"]); }); @@ -508,6 +504,42 @@ QUnit.module("spreadsheet > list plugin", {}, () => { }); }); + QUnit.test( + "List record limit is computed during the import and UPDATE_CELL", + async function (assert) { + const spreadsheetData = { + sheets: [ + { + id: "sheet1", + cells: { + A1: { content: `=ODOO.LIST("1", "1", "foo")` }, + }, + }, + ], + lists: { + 1: { + id: 1, + columns: ["foo", "contact_name"], + domain: [], + model: "partner", + orderBy: [], + context: {}, + }, + }, + }; + const model = await createModelWithDataSource({ spreadsheetData }); + const ds = model.getters.getListDataSource("1"); + assert.strictEqual(ds.maxPosition, 1); + assert.strictEqual(ds.maxPositionFetched, 0); + setCellContent(model, "A1", `=ODOO.LIST("1", "42", "foo", 2)`); + assert.strictEqual(ds.maxPosition, 42); + assert.strictEqual(ds.maxPositionFetched, 0); + await waitForDataSourcesLoaded(model); + assert.strictEqual(ds.maxPosition, 42); + assert.strictEqual(ds.maxPositionFetched, 42); + } + ); + QUnit.test( "Load list spreadsheet with models that cannot be accessed", async function (assert) {