[REF] spreadsheet: move list dataSources to UI

Before this commit, the list's dataSources were managed by the core plugin
`ListCorePlugin`. This didn't make sense since dataSources aren't core data:

- they are neither exported nor imported
- they can be different for each user (their ids were generated via uuidv4
at import)
- managing them required to handle local command in the core plugin

Moved the dataSources management to the UI plugin `ListUIPlugin` and moved
the relevant getters inside this plugin. Changed the ids of the dataSources
to be the same as the list's id + a prefix, to avoid having to maintain a
mapping `listId` <=> `dataSourceId` .

This commit also removes the dataSourceId from the INSERT_ODOO_LIST
command, which have no place here since this is a core command and the
dataSources are now a pure UI concept.

Task: 3293491
Part-of: odoo/odoo#120136
This commit is contained in:
Adrien Minne (adrm)
2023-05-05 17:06:45 +02:00
parent c313f5912f
commit d70da3f734
3 changed files with 142 additions and 107 deletions
@@ -3,13 +3,11 @@
import * as spreadsheet from "@odoo/o-spreadsheet";
import CommandResult from "../../o_spreadsheet/cancelled_reason";
import { getMaxObjectId } from "../../helpers/helpers";
import ListDataSource from "../list_data_source";
import { TOP_LEVEL_STYLE } from "../../helpers/constants";
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
@@ -35,7 +33,6 @@ const { CorePlugin } = spreadsheet;
export default class ListCorePlugin extends CorePlugin {
constructor(config) {
super(config);
this.dataSources = config.custom.dataSources;
this.nextId = 1;
/** @type {Object.<string, List>} */
@@ -46,9 +43,7 @@ export default class ListCorePlugin extends CorePlugin {
getDisplayName: (listId) => this.getters.getListName(listId),
getTag: (listId) => sprintf(_t("List #%s"), listId),
getFieldMatching: (listId, filterId) => this.getListFieldMatching(listId, filterId),
waitForReady: () => this.getListsWaitForReady(),
getModel: (listId) => this.getListDefinition(listId).model,
getFields: (listId) => this.getListDataSource(listId).getFields(),
};
}
@@ -87,10 +82,9 @@ export default class ListCorePlugin extends CorePlugin {
handle(cmd) {
switch (cmd.type) {
case "INSERT_ODOO_LIST": {
const { sheetId, col, row, id, definition, dataSourceId, linesNumber, columns } =
cmd;
const { sheetId, col, row, id, definition, linesNumber, columns } = cmd;
const anchor = [col, row];
this._addList(id, definition, dataSourceId, linesNumber);
this._addList(id, definition);
this._insertList(sheetId, anchor, id, linesNumber, columns);
this.history.update("nextId", parseInt(id, 10) + 1);
break;
@@ -120,19 +114,6 @@ export default class ListCorePlugin extends CorePlugin {
"domain",
cmd.domain
);
const list = this.lists[cmd.listId];
this.dataSources.add(list.dataSourceId, ListDataSource, list.definition);
break;
}
case "UNDO":
case "REDO": {
const domainEditionCommands = cmd.commands.filter(
(cmd) => cmd.type === "UPDATE_ODOO_LIST_DOMAIN"
);
for (const cmd of domainEditionCommands) {
const list = this.lists[cmd.listId];
this.dataSources.add(list.dataSourceId, ListDataSource, list.definition);
}
break;
}
case "ADD_GLOBAL_FILTER":
@@ -144,64 +125,13 @@ 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
// -------------------------------------------------------------------------
/**
* @param {string} id
* @returns {import("@spreadsheet/list/list_data_source").default|undefined}
*/
getListDataSource(id) {
const dataSourceId = this.lists[id].dataSourceId;
return this.dataSources.get(dataSourceId);
}
/**
* @param {string} id
* @returns {string}
@@ -226,16 +156,6 @@ export default class ListCorePlugin extends CorePlugin {
return this.lists[id].fieldMatching;
}
/**
* @param {string} id
* @returns {Promise<import("@spreadsheet/list/list_data_source").default>}
*/
async getAsyncListDataSource(id) {
const dataSourceId = this.lists[id].dataSourceId;
await this.dataSources.load(dataSourceId);
return this.getListDataSource(id);
}
/**
* Retrieve all the list ids
*
@@ -271,6 +191,10 @@ export default class ListCorePlugin extends CorePlugin {
};
}
getListModelDefinition(id) {
return this.lists[id].definition;
}
/**
* Check if an id is an id of an existing list
*
@@ -286,14 +210,6 @@ export default class ListCorePlugin extends CorePlugin {
// Private
// ---------------------------------------------------------------------
/**
*
* @return {Promise[]}
*/
getListsWaitForReady() {
return this.getListIds().map((ListId) => this.getListDataSource(ListId).loadMetadata());
}
/**
* Get the current FieldMatching on a list
*
@@ -325,21 +241,14 @@ export default class ListCorePlugin extends CorePlugin {
}
}
_addList(id, definition, dataSourceId, limit, fieldMatching = {}) {
_addList(id, definition, fieldMatching = {}) {
const lists = { ...this.lists };
lists[id] = {
id,
definition,
dataSourceId,
fieldMatching,
};
if (!this.dataSources.contains(dataSourceId)) {
this.dataSources.add(dataSourceId, ListDataSource, {
...definition,
limit,
});
}
this.history.update("lists", lists);
}
@@ -471,7 +380,7 @@ export default class ListCorePlugin extends CorePlugin {
},
name: list.name,
};
this._addList(id, definition, this.uuidGenerator.uuidv4(), 0, list.fieldMatching);
this._addList(id, definition, list.fieldMatching);
}
}
this.nextId = data.listNextId || getMaxObjectId(this.lists) + 1;
@@ -492,10 +401,9 @@ export default class ListCorePlugin extends CorePlugin {
}
ListCorePlugin.getters = [
"getListDataSource",
"getListDisplayName",
"getAsyncListDataSource",
"getListDefinition",
"getListModelDefinition",
"getListIds",
"getListName",
"getNextListId",
@@ -1,8 +1,10 @@
/** @odoo-module */
import * as spreadsheet from "@odoo/o-spreadsheet";
import { getFirstListFunction } from "../list_helpers";
import { getFirstListFunction, getNumberOfListFormulas } from "../list_helpers";
import { Domain } from "@web/core/domain";
import ListDataSource from "../list_data_source";
import { globalFiltersFieldMatchers } from "@spreadsheet/global_filters/plugins/global_filters_core_plugin";
const { astToFormula } = spreadsheet;
@@ -16,11 +18,23 @@ export default class ListUIPlugin extends spreadsheet.UIPlugin {
/** @type {string} */
this.selectedListId = undefined;
this.env = config.custom.env;
this.dataSources = config.custom.dataSources;
globalFiltersFieldMatchers["list"] = {
...globalFiltersFieldMatchers["list"],
getFields: (listId) => this.getListDataSource(listId).getFields(),
waitForReady: () => this.getListsWaitForReady(),
};
}
beforeHandle(cmd) {
switch (cmd.type) {
case "START":
for (const listId of this.getters.getListIds()) {
this._setupListDataSource(listId, 0);
}
// make sure the domains are correctly set before
// any evaluation
this._addDomains();
@@ -34,6 +48,21 @@ export default class ListUIPlugin extends spreadsheet.UIPlugin {
*/
handle(cmd) {
switch (cmd.type) {
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 "INSERT_ODOO_LIST": {
const { id, linesNumber } = cmd;
this._setupListDataSource(id, linesNumber);
break;
}
case "SELECT_ODOO_LIST":
this._selectList(cmd.listId);
break;
@@ -50,8 +79,19 @@ export default class ListUIPlugin extends spreadsheet.UIPlugin {
case "CLEAR_GLOBAL_FILTER_VALUE":
this._addDomains();
break;
case "UPDATE_ODOO_LIST_DOMAIN": {
const listDefinition = this.getters.getListModelDefinition(cmd.listId);
const dataSourceId = this._getListDataSourceId(cmd.listId);
this.dataSources.add(dataSourceId, ListDataSource, listDefinition);
break;
}
case "UPDATE_CELL":
if (cmd.content) {
this._addListPositionToDataSource(cmd.content);
}
break;
case "UNDO":
case "REDO":
case "REDO": {
if (
cmd.commands.find((command) =>
[
@@ -63,7 +103,22 @@ export default class ListUIPlugin extends spreadsheet.UIPlugin {
) {
this._addDomains();
}
const domainEditionCommands = cmd.commands.filter(
(cmd) =>
cmd.type === "UPDATE_ODOO_LIST_DOMAIN" || cmd.type === "INSERT_ODOO_LIST"
);
for (const cmd of domainEditionCommands) {
if (!this.getters.isExistingList(cmd.listId)) {
continue;
}
const listDefinition = this.getters.getListModelDefinition(cmd.listId);
const dataSourceId = this._getListDataSourceId(cmd.listId);
this.dataSources.add(dataSourceId, ListDataSource, listDefinition);
}
break;
}
}
}
@@ -71,6 +126,17 @@ export default class ListUIPlugin extends spreadsheet.UIPlugin {
// Handlers
// -------------------------------------------------------------------------
_setupListDataSource(listId, limit, definition) {
const dataSourceId = this._getListDataSourceId(listId);
definition = definition || this.getters.getListModelDefinition(listId);
if (!this.dataSources.contains(dataSourceId)) {
this.dataSources.add(dataSourceId, ListDataSource, {
...definition,
limit,
});
}
}
/**
* Add an additional domain to a list
*
@@ -128,6 +194,40 @@ export default class ListUIPlugin extends spreadsheet.UIPlugin {
this.selectedListId = listId;
}
_getListDataSourceId(listId) {
return `list-${listId}`;
}
/**
* 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 (!this.getters.getListIds().includes(listId)) {
return;
}
const position = parseInt(positionArg, 10);
if (isNaN(position)) {
return;
}
const dataSourceId = this._getListDataSourceId(listId);
if (!this.dataSources.get(dataSourceId)) {
this._setupListDataSource(listId, 0);
}
this.dataSources.get(dataSourceId).increaseMaxPosition(position);
}
// -------------------------------------------------------------------------
// Getters
// -------------------------------------------------------------------------
@@ -191,6 +291,35 @@ export default class ListUIPlugin extends spreadsheet.UIPlugin {
getSelectedListId() {
return this.selectedListId;
}
/**
* @param {string} id
* @returns {import("@spreadsheet/list/list_data_source").default|undefined}
*/
getListDataSource(id) {
const dataSourceId = this._getListDataSourceId(id);
return this.dataSources.get(dataSourceId);
}
/**
* @param {string} id
* @returns {Promise<import("@spreadsheet/list/list_data_source").default>}
*/
async getAsyncListDataSource(id) {
const dataSourceId = this._getListDataSourceId(id);
await this.dataSources.load(dataSourceId);
return this.getListDataSource(id);
}
/**
*
* @return {Promise[]}
*/
getListsWaitForReady() {
return this.getters
.getListIds()
.map((listId) => this.getListDataSource(listId).loadMetadata());
}
}
ListUIPlugin.getters = [
@@ -199,4 +328,6 @@ ListUIPlugin.getters = [
"getListIdFromPosition",
"getListCellValue",
"getSelectedListId",
"getListDataSource",
"getAsyncListDataSource",
];
@@ -1,11 +1,8 @@
/** @odoo-module */
import * as spreadsheet from "@odoo/o-spreadsheet";
import { generateListDefinition } from "./data";
import { createModelWithDataSource, waitForDataSourcesLoaded } from "./model";
const uuidGenerator = new spreadsheet.helpers.UuidGenerator();
/** @typedef {import("@spreadsheet/o_spreadsheet/o_spreadsheet").Model} Model */
/**
@@ -31,7 +28,6 @@ export function insertListInSpreadsheet(model, params) {
id: model.getters.getNextListId(),
col,
row,
dataSourceId: uuidGenerator.uuidv4(),
});
}