diff --git a/spreadsheet_oca/__manifest__.py b/spreadsheet_oca/__manifest__.py
index 0469625d..ca7f90ab 100644
--- a/spreadsheet_oca/__manifest__.py
+++ b/spreadsheet_oca/__manifest__.py
@@ -24,10 +24,13 @@
"spreadsheet_oca/static/src/spreadsheet/spreadsheet_action.esm.js",
"spreadsheet_oca/static/src/spreadsheet/pivot_controller.esm.js",
"spreadsheet_oca/static/src/spreadsheet/graph_controller.esm.js",
+ "spreadsheet_oca/static/src/spreadsheet/list_controller.esm.js",
+ "spreadsheet_oca/static/src/spreadsheet/list_renderer.esm.js",
],
"spreadsheet.o_spreadsheet": [
"spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet.xml",
"spreadsheet_oca/static/src/spreadsheet/bundle/filter.esm.js",
+ "spreadsheet_oca/static/src/spreadsheet/bundle/filter_panel_datasources.esm.js",
"spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet_renderer.esm.js",
"spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet_controlpanel.esm.js",
"spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet_action.esm.js",
diff --git a/spreadsheet_oca/static/src/spreadsheet/bundle/filter.esm.js b/spreadsheet_oca/static/src/spreadsheet/bundle/filter.esm.js
index f7bb6e3d..c4e41e2c 100644
--- a/spreadsheet_oca/static/src/spreadsheet/bundle/filter.esm.js
+++ b/spreadsheet_oca/static/src/spreadsheet/bundle/filter.esm.js
@@ -86,12 +86,12 @@ export class EditFilterPanel extends Component {
objectClass.getFieldMatching(objectId, this.props.filter.id) ||
{},
fields: fields,
+ type: objectType,
model: objectClass.getModel(objectId),
};
ModelFields.push(fields);
}
}
- console.log(this.state.objects);
this.models = [
...new Set(
ModelFields.map((field_items) => Object.values(field_items))
@@ -133,7 +133,6 @@ export class EditFilterPanel extends Component {
? "EDIT_GLOBAL_FILTER"
: "ADD_GLOBAL_FILTER";
this.env.openSidePanel("FilterPanel", {});
-
var filter = {
id: this.props.filter.id || uuidGenerator.uuidv4(),
type: this.state.type,
@@ -146,7 +145,7 @@ export class EditFilterPanel extends Component {
var filterMatching = {};
Object.values(this.state.objects).forEach((object) => {
filterMatching[object.type] = filterMatching[object.type] || {};
- filterMatching[object.type][object.id] = {...object.fieldMatch};
+ filterMatching[object.type][object.objectId] = {...object.fieldMatch};
});
this.env.model.dispatch(action, {id: filter.id, filter, ...filterMatching});
@@ -162,7 +161,7 @@ export class EditFilterPanel extends Component {
this.env.openSidePanel("FilterPanel", {});
}
onFieldMatchUpdate(object, name) {
- this.state.objects[object.id].fieldMatch.chain = name.chain;
+ this.state.objects[object.id].fieldMatch.chain = name;
}
}
diff --git a/spreadsheet_oca/static/src/spreadsheet/bundle/filter_panel_datasources.esm.js b/spreadsheet_oca/static/src/spreadsheet/bundle/filter_panel_datasources.esm.js
new file mode 100644
index 00000000..8b5e9388
--- /dev/null
+++ b/spreadsheet_oca/static/src/spreadsheet/bundle/filter_panel_datasources.esm.js
@@ -0,0 +1,217 @@
+/** @odoo-module **/
+
+import {Component, onWillStart, onWillUpdateProps} from "@odoo/owl";
+import {Domain} from "@web/core/domain";
+import {DomainSelector} from "@web/core/domain_selector/domain_selector";
+import {DomainSelectorDialog} from "@web/core/domain_selector_dialog/domain_selector_dialog";
+import {_t} from "web.core";
+import spreadsheet from "@spreadsheet/o_spreadsheet/o_spreadsheet_extended";
+import {time_to_str} from "web.time";
+import {useService} from "@web/core/utils/hooks";
+
+const {sidePanelRegistry, topbarMenuRegistry} = spreadsheet.registries;
+const {createFullMenuItem} = spreadsheet.helpers;
+
+topbarMenuRegistry.addChild("data_sources", ["data"], (env) => {
+ const children = env.model.getters.getPivotIds().map((pivotId, index) =>
+ createFullMenuItem(`data_source_pivot_ ${pivotId}`, {
+ name: env.model.getters.getPivotDisplayName(pivotId),
+ sequence: 100,
+ action: (child_env) => {
+ child_env.model.dispatch("SELECT_PIVOT", {
+ pivotId: pivotId,
+ });
+ child_env.openSidePanel("PivotPanel", {});
+ },
+ icon: "fa fa-table",
+ separator: index === env.model.getters.getPivotIds().length - 1,
+ })
+ );
+ const lists = env.model.getters.getListIds().map((listId, index) => {
+ return createFullMenuItem(`data_source_list_${listId}`, {
+ name: env.model.getters.getListDisplayName(listId),
+ sequence: 1010,
+ action: (child_env) => {
+ child_env.model.dispatch("SELECT_ODOO_LIST", {listId: listId});
+ child_env.openSidePanel("ListPanel", {});
+ },
+ icon: "fa fa-list",
+ separator: index === env.model.getters.getListIds().length - 1,
+ });
+ });
+ return children.concat(lists).concat([
+ createFullMenuItem(`refresh_all_data`, {
+ name: _t("Refresh all data"),
+ sequence: 110,
+ action: (child_env) => {
+ child_env.model.dispatch("REFRESH_ALL_DATA_SOURCES");
+ },
+ separator: true,
+ }),
+ ]);
+});
+
+export class PivotPanelDisplay extends Component {
+ setup() {
+ this.dialog = useService("dialog");
+ onWillStart(this.modelData.bind(this));
+ onWillUpdateProps(this.modelData.bind(this));
+ }
+ async modelData() {
+ this.PivotDataSource = await this.env.model.getters.getAsyncPivotDataSource(
+ this.props.pivotId
+ );
+ this.modelLabel = await this.PivotDataSource.getModelLabel();
+ }
+ get domain() {
+ return new Domain(this.props.pivotDefinition.domain).toString();
+ }
+ get pivotDimensions() {
+ return [
+ ...this.props.pivotDefinition.rowGroupBys,
+ ...this.props.pivotDefinition.colGroupBys,
+ ].map((fieldName) => this.PivotDataSource.getFormattedGroupBy(fieldName));
+ }
+ get sortInformation() {
+ const sortedColumn = this.props.pivotDefinition.sortedColumn;
+ const orderTranslate =
+ sortedColumn.order === "asc" ? _t("ascending") : _t("descending");
+ const GroupByDisplayLabel = this.PivotDataSource.getGroupByDisplayLabel(
+ "measure",
+ sortedColumn.measure
+ );
+ return `${GroupByDisplayLabel} (${orderTranslate})`;
+ }
+ get lastUpdate() {
+ const lastUpdate = this.PivotDataSource.lastUpdate;
+ if (lastUpdate) {
+ return time_to_str(new Date(lastUpdate));
+ }
+ return _t("not updated");
+ }
+ editDomain() {
+ this.dialog.add(DomainSelectorDialog, {
+ resModel: this.props.pivotDefinition.model,
+ initialValue: this.domain,
+ readonly: false,
+ isDebugMode: Boolean(this.env.debug),
+ onSelected: this.onSelectDomain.bind(this),
+ });
+ }
+ onSelectDomain(domain) {
+ this.env.model.dispatch("UPDATE_ODOO_PIVOT_DOMAIN", {
+ pivotId: this.props.pivotId,
+ domain: new Domain(domain).toList(),
+ });
+ }
+ async insertPivot() {
+ const datasourceModel = await this.env.model.getters
+ .getPivotDataSource(this.props.pivotId)
+ .copyModelWithOriginalDomain();
+ const tableStructure = datasourceModel.getTableStructure().export();
+ const selectedZone = this.env.model.getters.getSelectedZone();
+ this.env.model.dispatch("RE_INSERT_PIVOT", {
+ id: this.props.pivotId,
+ col: selectedZone.left,
+ row: selectedZone.top,
+ sheetId: this.env.model.getters.getActiveSheetId(),
+ table: tableStructure,
+ });
+ this.env.model.dispatch("REFRESH_PIVOT", {id: this.props.pivotId});
+ }
+}
+
+PivotPanelDisplay.template = "spreadsheet_oca.PivotPanelDisplay";
+PivotPanelDisplay.components = {
+ DomainSelector,
+};
+PivotPanelDisplay.properties = {
+ pivotId: String,
+ pivotDefinition: Object,
+};
+
+export class PivotPanel extends Component {
+ get pivotId() {
+ return this.env.model.getters.getSelectedPivotId();
+ }
+ get pivotDefinition() {
+ return this.env.model.getters.getPivotDefinition(this.pivotId);
+ }
+}
+
+PivotPanel.template = "spreadsheet_oca.PivotPanel";
+PivotPanel.components = {
+ PivotPanelDisplay,
+};
+
+sidePanelRegistry.add("PivotPanel", {
+ title: "Pivot table information",
+ Body: PivotPanel,
+});
+
+export class ListPanelDisplay extends Component {
+ setup() {
+ this.dialog = useService("dialog");
+ onWillStart(this.modelData.bind(this));
+ onWillUpdateProps(this.modelData.bind(this));
+ }
+ async modelData() {
+ this.ListDataSource = await this.env.model.getters.getAsyncListDataSource(
+ this.props.listId
+ );
+ this.modelLabel = await this.ListDataSource.getModelLabel();
+ }
+ get domain() {
+ return new Domain(this.props.listDefinition.domain).toString();
+ }
+ get lastUpdate() {
+ const lastUpdate = this.ListDataSource.lastUpdate;
+ if (lastUpdate) {
+ return time_to_str(new Date(lastUpdate));
+ }
+ return _t("not updated");
+ }
+ editDomain() {
+ this.dialog.add(DomainSelectorDialog, {
+ resModel: this.props.listDefinition.model,
+ initialValue: this.domain,
+ readonly: false,
+ isDebugMode: Boolean(this.env.debug),
+ onSelected: this.onSelectDomain.bind(this),
+ });
+ }
+ onSelectDomain(domain) {
+ this.env.model.dispatch("UPDATE_ODOO_LIST_DOMAIN", {
+ listId: this.props.listId,
+ domain: new Domain(domain).toList(),
+ });
+ }
+}
+
+ListPanelDisplay.template = "spreadsheet_oca.ListPanelDisplay";
+ListPanelDisplay.components = {
+ DomainSelector,
+};
+ListPanelDisplay.properties = {
+ listId: String,
+ listDefinition: Object,
+};
+
+export class ListPanel extends Component {
+ get listId() {
+ return this.env.model.getters.getSelectedListId();
+ }
+ get listDefinition() {
+ return this.env.model.getters.getListDefinition(this.listId);
+ }
+}
+
+ListPanel.template = "spreadsheet_oca.ListPanel";
+ListPanel.components = {
+ ListPanelDisplay,
+};
+
+sidePanelRegistry.add("ListPanel", {
+ title: "List information",
+ Body: ListPanel,
+});
diff --git a/spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet.xml b/spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet.xml
index bb6d1cfe..9bd67783 100644
--- a/spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet.xml
+++ b/spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet.xml
@@ -12,6 +12,110 @@
/>
+
+
+
+
+
+
+
+
+
Domain
+
+
+ Edit domain
+
+
+
+
+
+
+ Last updated at
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Domain
+
+
+ Edit domain
+
+
+
+ Last updated at
+
+
+
+
diff --git a/spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet_action.esm.js b/spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet_action.esm.js
index 8b461110..71805fc1 100644
--- a/spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet_action.esm.js
+++ b/spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet_action.esm.js
@@ -1,5 +1,6 @@
/** @odoo-module **/
+import ListDataSource from "@spreadsheet/list/list_data_source";
import PivotDataSource from "@spreadsheet/pivot/pivot_data_source";
import {SpreadsheetControlPanel} from "./spreadsheet_controlpanel.esm";
import {SpreadsheetRenderer} from "./spreadsheet_renderer.esm";
@@ -91,7 +92,7 @@ export class ActionSpreadsheetOca extends Component {
definition,
});
}
- async importDataPivot(spreadsheet_model) {
+ importCreateOrReuseSheet(spreadsheet_model) {
var sheetId = spreadsheet_model.getters.getActiveSheetId();
var row = 0;
if (this.import_data.new === undefined && this.import_data.new_sheet) {
@@ -128,6 +129,48 @@ export class ActionSpreadsheetOca extends Component {
}
row += 1;
}
+ return {sheetId, row};
+ }
+ async importDataList(spreadsheet_model) {
+ var {sheetId, row} = this.importCreateOrReuseSheet(spreadsheet_model);
+ const dataSourceId = uuidGenerator.uuidv4();
+ var list_info = {
+ metaData: {
+ resModel: this.import_data.metaData.model,
+ columns: this.import_data.metaData.columns.map((column) => column.name),
+ fields: this.import_data.metaData.fields,
+ },
+ searchParams: {
+ domain: this.import_data.metaData.domain,
+ context: this.import_data.metaData.context,
+ orderBy: this.import_data.metaData.orderBy,
+ },
+ name: this.import_data.metaData.name,
+ };
+ const dataSource = spreadsheet_model.config.dataSources.add(
+ dataSourceId,
+ ListDataSource,
+ list_info
+ );
+ await dataSource.load();
+ spreadsheet_model.dispatch("INSERT_ODOO_LIST", {
+ sheetId,
+ col: 0,
+ row: row,
+ id: spreadsheet_model.getters.getNextListId(),
+ dataSourceId,
+ definition: list_info,
+ linesNumber: this.import_data.metaData.threshold,
+ columns: this.import_data.metaData.columns,
+ });
+ const columns = [];
+ for (let col = 0; col < this.import_data.metaData.columns.length; col++) {
+ columns.push(col);
+ }
+ spreadsheet_model.dispatch("AUTORESIZE_COLUMNS", {sheetId, cols: columns});
+ }
+ async importDataPivot(spreadsheet_model) {
+ var {sheetId, row} = this.importCreateOrReuseSheet(spreadsheet_model);
const dataSourceId = uuidGenerator.uuidv4();
const pivot_info = {
metaData: {
@@ -167,6 +210,9 @@ export class ActionSpreadsheetOca extends Component {
if (this.import_data.mode === "graph") {
await this.importDataGraph(spreadsheet_model);
}
+ if (this.import_data.mode === "list") {
+ await this.importDataList(spreadsheet_model);
+ }
}
}
ActionSpreadsheetOca.template = "spreadsheet_oca.ActionSpreadsheetOca";
diff --git a/spreadsheet_oca/static/src/spreadsheet/list_controller.esm.js b/spreadsheet_oca/static/src/spreadsheet/list_controller.esm.js
new file mode 100644
index 00000000..0229b2dc
--- /dev/null
+++ b/spreadsheet_oca/static/src/spreadsheet/list_controller.esm.js
@@ -0,0 +1,14 @@
+/** @odoo-module **/
+import {ListController} from "@web/views/list/list_controller";
+
+import {patch} from "web.utils";
+
+patch(
+ ListController.prototype,
+ "spreadsheet_oca/static/src/spreadsheet/list_controller.esm.js",
+ {
+ onSpreadsheetButtonClicked() {
+ this.env.bus.trigger("addListOnSpreadsheet");
+ },
+ }
+);
diff --git a/spreadsheet_oca/static/src/spreadsheet/list_renderer.esm.js b/spreadsheet_oca/static/src/spreadsheet/list_renderer.esm.js
new file mode 100644
index 00000000..b123e8f7
--- /dev/null
+++ b/spreadsheet_oca/static/src/spreadsheet/list_renderer.esm.js
@@ -0,0 +1,58 @@
+/** @odoo-module **/
+import {useBus, useService} from "@web/core/utils/hooks";
+import {ListRenderer} from "@web/views/list/list_renderer";
+import {omit} from "@web/core/utils/objects";
+import {patch} from "web.utils";
+
+patch(
+ ListRenderer.prototype,
+ "spreadsheet_oca/static/src/spreadsheet/list_renderer.esm.js",
+ {
+ setup() {
+ this._super(...arguments);
+ this.userService = useService("user");
+ this.actionService = useService("action");
+ useBus(
+ this.env.bus,
+ "addListOnSpreadsheet",
+ this.onAddListOnSpreadsheet.bind(this)
+ );
+ },
+ onAddListOnSpreadsheet() {
+ const model = this.env.model.root;
+ this.actionService.doAction(
+ "spreadsheet_oca.spreadsheet_spreadsheet_import_act_window",
+ {
+ additionalContext: {
+ default_name: this.env.config.getDisplayName(),
+ default_import_data: {
+ mode: "list",
+ metaData: {
+ model: model.resModel,
+ domain: model.domain,
+ orderBy: model.orderBy,
+ context: omit(
+ model.context,
+ ...Object.keys(this.userService.context)
+ ),
+ columns: this.getSpreadsheetColumns(),
+ fields: model.fields,
+ name: this.env.config.getDisplayName(),
+ threshold: Math.min(model.count, model.limit),
+ },
+ },
+ },
+ }
+ );
+ },
+ getSpreadsheetColumns() {
+ const fields = this.env.model.root.fields;
+ return this.state.columns
+ .filter(
+ (col) => col.type === "field" && fields[col.name].type !== "binary"
+ // We want to avoid binary fields
+ )
+ .map((col) => ({name: col.name, type: fields[col.name].type}));
+ },
+ }
+);
diff --git a/spreadsheet_oca/static/src/spreadsheet/spreadsheet.scss b/spreadsheet_oca/static/src/spreadsheet/spreadsheet.scss
index a36e2732..eecba723 100644
--- a/spreadsheet_oca/static/src/spreadsheet/spreadsheet.scss
+++ b/spreadsheet_oca/static/src/spreadsheet/spreadsheet.scss
@@ -20,6 +20,19 @@
.o_spreadsheet_oca_name_warning {
font-size: 0.8em;
}
+
+ .o_spreadsheet_oca_datasource_panel {
+ padding: 16px;
+ .o_spreadsheet_oca_datasource_panel_field {
+ .o_spreadsheet_oca_datasource_panel_field_title {
+ font-weight: bold;
+ }
+ }
+ }
+ .o_spreadsheet_oca_pivot_panel_info {
+ font-style: italic;
+ color: $o-gray-600;
+ }
.o_spreadsheet_oca_filter {
padding: 16px;
.spreadsheet_oca_filter_label {
diff --git a/spreadsheet_oca/static/src/spreadsheet/spreadsheet.xml b/spreadsheet_oca/static/src/spreadsheet/spreadsheet.xml
index 92f977c6..04f3d337 100644
--- a/spreadsheet_oca/static/src/spreadsheet/spreadsheet.xml
+++ b/spreadsheet_oca/static/src/spreadsheet/spreadsheet.xml
@@ -14,6 +14,21 @@
+
+
+
+
+
+
+
+
+