Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import * as spreadsheet from "@odoo/o-spreadsheet";
import {Component, onWillStart, onWillUpdateProps, useState} from "@odoo/owl";
import {Component, onWillStart, onWillUpdateProps, useRef, useState} 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/l10n/translation";
import {formatDate} from "@web/core/l10n/dates";
import {useService} from "@web/core/utils/hooks";
import {ODOO_AGGREGATORS} from "@spreadsheet/pivot/pivot_helpers";

const {DateTime} = luxon;
const {PivotTitleSection, PivotLayoutConfigurator} = spreadsheet.components;
const {useLocalStore, PivotSidePanelStore} = spreadsheet.stores;
const {sidePanelRegistry, topbarMenuRegistry, pivotSidePanelRegistry} =
spreadsheet.registries;

Expand Down Expand Up @@ -37,9 +40,53 @@ topbarMenuRegistry.addChild("data_sources", ["data"], (env) => {
]);
});

export class PivotLayoutConfiguratorWithAggregators extends PivotLayoutConfigurator {
setup() {
super.setup();
this.AGGREGATORS = ODOO_AGGREGATORS;
}
}

export class PivotTitleSectionInsertion extends PivotTitleSection {
get cogWheelMenuItems() {
const res = super.cogWheelMenuItems;
res.push(
{
name: _t("Re-insert Dynamic"),
icon: "o-spreadsheet-Icon.INSERT_PIVOT",
execute: (env) => this.reinsertTable(env, "dynamic"),
},
{
name: _t("Re-insert Static"),
icon: "o-spreadsheet-Icon.INSERT_PIVOT",
execute: (env) => this.reinsertTable(env, "static"),
}
);
return res;
}
reinsertTable(env, mode) {
const zone = env.model.getters.getSelectedZone();
const table = env.model.getters
.getPivot(this.props.pivotId)
.getTableStructure()
.export();
env.model.dispatch("INSERT_PIVOT_WITH_TABLE", {
pivotId: this.props.pivotId,
table,
col: zone.left,
row: zone.top,
sheetId: env.model.getters.getActiveSheetId(),
pivotMode: mode,
});
env.model.dispatch("REFRESH_PIVOT", {id: this.props.pivotId});
}
}

export class PivotPanelDisplay extends Component {
setup() {
this.dialog = useService("dialog");
this.store = useLocalStore(PivotSidePanelStore, this.props.pivotId);
this.pivotPanelRef = useRef("pivotPanel");
onWillStart(this.modelData.bind(this));
onWillUpdateProps(this.modelData.bind(this));
}
Expand All @@ -48,20 +95,12 @@ export class PivotPanelDisplay extends Component {
this.modelLabel = await this.PivotDataSource.getModelLabel();
}
get domain() {
return new Domain(this.props.pivotDefinition.domain).toString();
}
get pivotDimensions() {
const {rows = [], columns = []} = this.props.pivotDefinition;
return [...rows, ...columns].map((dim) => {
const label = dim.displayName || dim.fieldName;
return dim.granularity ? `${label} (${dim.granularity})` : label;
});
return new Domain(this.store.definition.domain).toString();
}
get sortInformation() {
const sortedColumn = this.props.pivotDefinition.sortedColumn;
const sortedColumn = this.store.definition.sortedColumn;
const orderTranslate =
sortedColumn.order === "asc" ? _t("ascending") : _t("descending");

let label = null;
if (sortedColumn.measure) {
const measure = this.PivotDataSource.getMeasure(sortedColumn.measure);
Expand All @@ -80,84 +119,39 @@ export class PivotPanelDisplay extends Component {
}
editDomain() {
this.dialog.add(DomainSelectorDialog, {
resModel: this.props.pivotDefinition.model,
domain: this.domain,
resModel: this.store.definition.model,
domain: this.store.definition.domain,
readonly: false,
isDebugMode: Boolean(this.env.debug),
onConfirm: this.onSelectDomain.bind(this),
});
}
updateDimensions(dimensions) {
this.store.update(dimensions);
}
onSelectDomain(domain) {
this.env.model.dispatch("UPDATE_ODOO_PIVOT_DOMAIN", {
pivotId: this.props.pivotId,
domain: new Domain(domain).toList(),
});
this.store.update({domain});
}
async insertPivot() {
const pivotId = this.props.pivotId;
const {type} = this.env.model.getters.getPivotCoreDefinition(pivotId);
const position = this.env.model.getters.getActivePosition();
let table = null;
if (type === "ODOO") {
const dataSource = this.env.model.getters.getPivot(pivotId);
const model = await dataSource.copyModelWithOriginalDomain();
table = model.getTableStructure().export();
} else {
table = this.env.model.getters
.getPivot(pivotId)
.getTableStructure()
.export();
}
this.env.model.dispatch("INSERT_PIVOT_WITH_TABLE", {
...position,
pivotId,
table,
pivotMode: "static",
});
this.env.model.dispatch("REFRESH_PIVOT", {id: pivotId});
getScrollableContainerEl() {
return this.pivotPanelRef.el;
}
async insertDynamicPivot() {
const pivotId = this.props.pivotId;
const {type} = this.env.model.getters.getPivotCoreDefinition(pivotId);
const position = this.env.model.getters.getActivePosition();
let table = null;
if (type === "ODOO") {
const dataSource = this.env.model.getters.getPivot(this.props.pivotId);
const model = await dataSource.copyModelWithOriginalDomain();
table = model.getTableStructure().export();
} else {
table = this.env.model.getters
.getPivot(this.props.pivotId)
.getTableStructure()
.export();
}
this.env.model.dispatch("INSERT_PIVOT_WITH_TABLE", {
...position,
pivotId,
table,
pivotMode: "dynamic",
});
this.env.model.dispatch("REFRESH_PIVOT", {id: pivotId});
}
delete() {
this.env.askConfirmation(
_t("Are you sure you want to delete this pivot?"),
() => {
this.env.model.dispatch("REMOVE_PIVOT", {
pivotId: this.props.pivotId,
});
}
);
flipAxis() {
const dimensions = {
rows: this.store.definition.columns,
columns: this.store.definition.rows,
};
this.updateDimensions(dimensions);
}
}

PivotPanelDisplay.template = "spreadsheet_oca.PivotPanelDisplay";
PivotPanelDisplay.components = {
DomainSelector,
PivotTitleSectionInsertion,
PivotLayoutConfiguratorWithAggregators,
};
PivotPanelDisplay.properties = {
pivotId: String,
pivotDefinition: Object,
};

export class PivotPanel extends Component {
Expand All @@ -167,10 +161,6 @@ export class PivotPanel extends Component {
get pivotType() {
return this.env.model.getters.getPivotCoreDefinition(this.pivotId).type;
}
get pivotDefinition() {
const dataSource = this.env.model.getters.getPivot(this.pivotId);
return dataSource ? dataSource.definition || {} : {};
}
}

PivotPanel.template = "spreadsheet_oca.PivotPanel";
Expand Down
88 changes: 31 additions & 57 deletions spreadsheet_oca/static/src/spreadsheet/bundle/spreadsheet.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,79 +14,53 @@
</t>
<t t-name="spreadsheet_oca.PivotPanel" owl="1">
<t t-if="pivotId">
<PivotPanelDisplay pivotId="pivotId" pivotDefinition="pivotDefinition" />
<PivotPanelDisplay pivotId="pivotId" />
</t>
<t t-else="1" />
</t>
<t t-name="spreadsheet_oca.PivotPanelDisplay" owl="1">
<div class="o_spreadsheet_oca_datasource_panel">
<div class="o_spreadsheet_oca_datasource_panel_field">
<div
class="o_spreadsheet_oca_datasource_panel_field_title"
>Pivot name</div>
<span t-esc="env.model.getters.getPivotDisplayName(props.pivotId)" />
</div>
<div class="o_spreadsheet_oca_datasource_panel_field">
<div class="o_spreadsheet_oca_datasource_panel_field_title">Model</div>
<div><t t-esc="modelLabel" /> (<t
t-esc="props.pivotDefinition.model"
<div
class="h-100 position-relative overflow-x-hidden overflow-y-auto"
t-ref="pivotPanel"
>
<PivotTitleSectionInsertion
pivotId="props.pivotId"
flipAxis.bind="flipAxis"
/>
<t t-set="definition" t-value="store.definition" />
<div class="o-section">
<div class="o-section-title">Model</div>
<div class="o_model_name"><t t-esc="modelLabel" /> (<t
t-esc="definition.model"
/>)</div>
</div>
<div class="o_spreadsheet_oca_datasource_panel_field">
<div class="o_spreadsheet_oca_datasource_panel_field_title">Domain</div>
<div class="o-section">
<div class="o-section-title">Domain</div>
<DomainSelector
resModel="props.pivotDefinition.model"
resModel="definition.model"
domain="domain"
t-key="'pivot_' + props.pivotId"
/>
<div class="btn btn-link" t-on-click="editDomain">
Edit domain
</div>
</div>
<div class="o_spreadsheet_oca_datasource_panel_field">
<div
class="o_spreadsheet_oca_datasource_panel_field_title"
>Dimensions</div>
<t t-foreach="pivotDimensions" t-as="dimension" t-key="dimension">
<div t-esc="dimension" />
</t>
</div>
<div
class="o_spreadsheet_oca_datasource_panel_field"
t-if="props.pivotDefinition.sortedColumn"
>
<div
class="o_spreadsheet_oca_datasource_panel_field_title"
>Sorting</div>
<PivotLayoutConfiguratorWithAggregators
unusedGroupableFields="store.unusedGroupableFields"
measureFields="store.measureFields"
unusedGranularities="store.unusedGranularities"
dateGranularities="store.dateGranularities"
datetimeGranularities="store.datetimeGranularities"
definition="definition"
onDimensionsUpdated.bind="updateDimensions"
getScrollableContainerEl.bind="getScrollableContainerEl"
pivotId="props.pivotId"
/>
<div class="o-section" t-if="definition.sortedColumn">
<div class="o-section-title">Sorting</div>
<div t-esc="sortInformation" />
</div>
<div class="o_spreadsheet_oca_datasource_panel_field">
<div
class="o_spreadsheet_oca_datasource_panel_field_title"
>Measures</div>
<t
t-foreach="props.pivotDefinition.measures"
t-as="measure"
t-key="measure.id"
>
<div t-esc="measure.displayName" />
</t>
</div>
<div class="o_spreadsheet_oca_datasource_panel_field o-sidePanelButtons">
<button
t-on-click="insertPivot"
class="btn btn-info"
>Insert pivot</button>
<button
t-on-click="insertDynamicPivot"
class="btn btn-success"
>Insert dynamic pivot</button>
<button
t-on-click="() => this.delete()"
class="btn btn-danger"
>Delete</button>
</div>
<div class="o_spreadsheet_oca_pivot_panel_info">
<div class="o-section o_spreadsheet_oca_pivot_panel_info">
Last updated at <t t-esc="lastUpdate" />
</div>
</div>
Expand Down