Skip to content

Commit 1cc7478

Browse files
hokolomopopro-odoo
authored andcommitted
[IMP] pivot: add pivot design panel
This commit adds a new tab "Design" in the pivot side panel, allowing users to customize the appearance of pivot tables. At the moment the panel only allow for the same customization as the arguments of the `=PIVOT()` function. The user can easily edit those settings in the side panel, and can override them in the formula if needed. closes #7286 Task: 5150320 Signed-off-by: Pierre Rousseau (pro) <[email protected]>
1 parent a11279d commit 1cc7478

File tree

22 files changed

+1080
-321
lines changed

22 files changed

+1080
-321
lines changed

packages/o-spreadsheet-engine/src/functions/helpers.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ export function toNumber(
9898
}
9999
}
100100

101+
/** Convert the data to a number, ignoring undefined values */
102+
export function toNumberIgnoreUndefined(
103+
data: FunctionResultObject | CellValue | undefined,
104+
locale: Locale
105+
): number | undefined {
106+
return data === undefined ? undefined : toNumber(data, locale);
107+
}
108+
101109
export function tryToNumber(
102110
value: string | number | boolean | null | undefined,
103111
locale: Locale
@@ -220,6 +228,13 @@ export function toBoolean(data: FunctionResultObject | CellValue | undefined): b
220228
}
221229
}
222230

231+
/** Convert the data to a boolean, ignoring undefined values */
232+
export function toBooleanIgnoreUndefined(
233+
data: FunctionResultObject | CellValue | undefined
234+
): boolean | undefined {
235+
return data === undefined ? undefined : toBoolean(data);
236+
}
237+
223238
function strictToBoolean(data: FunctionResultObject | CellValue | undefined): boolean {
224239
const value = toValue(data);
225240
if (value === "") {

packages/o-spreadsheet-engine/src/functions/module_lookup.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import { PIVOT_MAX_NUMBER_OF_CELLS } from "../constants";
33
import { getFullReference, splitReference } from "../helpers/";
44
import { toXC } from "../helpers/coordinates";
55
import { range } from "../helpers/misc";
6-
import { addAlignFormatToPivotHeader } from "../helpers/pivot/pivot_helpers";
6+
import {
7+
addAlignFormatToPivotHeader,
8+
getPivotStyleFromFnArgs,
9+
} from "../helpers/pivot/pivot_helpers";
710
import { toZone } from "../helpers/zones";
811
import { _t } from "../translation";
912
import { CellErrorType, EvaluationError, InvalidReferenceError } from "../types/errors";
1013
import { AddFunctionDescription } from "../types/functions";
1114
import { Arg, FunctionResultObject, Matrix, Maybe, Zone } from "../types/misc";
12-
import { PivotVisibilityOptions } from "../types/pivot";
1315
import { arg } from "./arguments";
1416
import { expectNumberGreaterThanOrEqualToOne } from "./helper_assert";
1517
import {
@@ -19,12 +21,12 @@ import {
1921
getPivotId,
2022
} from "./helper_lookup";
2123
import {
22-
LinearSearchMode,
2324
dichotomicSearch,
2425
expectNumberRangeError,
2526
generateMatrix,
2627
isEvaluationError,
2728
linearSearch,
29+
LinearSearchMode,
2830
strictToInteger,
2931
toBoolean,
3032
toMatrix,
@@ -907,30 +909,34 @@ export const PIVOT = {
907909
],
908910
compute: function (
909911
pivotFormulaId: Maybe<FunctionResultObject>,
910-
rowCount: Maybe<FunctionResultObject> = { value: 10000 },
911-
includeTotal: Maybe<FunctionResultObject> = { value: true },
912-
includeColumnHeaders: Maybe<FunctionResultObject> = { value: true },
913-
columnCount: Maybe<FunctionResultObject> = { value: Number.MAX_VALUE },
914-
includeMeasureTitles: Maybe<FunctionResultObject> = { value: true }
912+
rowCount: Maybe<FunctionResultObject>,
913+
includeTotal: Maybe<FunctionResultObject>,
914+
includeColumnHeaders: Maybe<FunctionResultObject>,
915+
columnCount: Maybe<FunctionResultObject>,
916+
includeMeasureTitles: Maybe<FunctionResultObject>
915917
) {
916918
const _pivotFormulaId = toString(pivotFormulaId);
917-
const _rowCount = toNumber(rowCount, this.locale);
918-
if (_rowCount < 0) {
919+
const pivotId = getPivotId(_pivotFormulaId, this.getters);
920+
const pivot = this.getters.getPivot(pivotId);
921+
const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
922+
923+
const pivotStyle = getPivotStyleFromFnArgs(
924+
coreDefinition,
925+
rowCount,
926+
includeTotal,
927+
includeColumnHeaders,
928+
columnCount,
929+
includeMeasureTitles,
930+
this.locale
931+
);
932+
933+
if (pivotStyle.numberOfRows < 0) {
919934
return new EvaluationError(_t("The number of rows must be positive."));
920935
}
921-
const _columnCount = toNumber(columnCount, this.locale);
922-
if (_columnCount < 0) {
936+
if (pivotStyle.numberOfColumns < 0) {
923937
return new EvaluationError(_t("The number of columns must be positive."));
924938
}
925-
const visibilityOptions: PivotVisibilityOptions = {
926-
displayColumnHeaders: toBoolean(includeColumnHeaders),
927-
displayTotals: toBoolean(includeTotal),
928-
displayMeasuresRow: toBoolean(includeMeasureTitles),
929-
};
930939

931-
const pivotId = getPivotId(_pivotFormulaId, this.getters);
932-
const pivot = this.getters.getPivot(pivotId);
933-
const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
934940
addPivotDependencies(this, coreDefinition, coreDefinition.measures);
935941
pivot.init({ reload: pivot.needsReevaluation });
936942
const error = pivot.assertIsValid({ throwOnError: false });
@@ -941,21 +947,21 @@ export const PIVOT = {
941947
if (table.numberOfCells > PIVOT_MAX_NUMBER_OF_CELLS) {
942948
return new EvaluationError(getPivotTooBigErrorMessage(table.numberOfCells, this.locale));
943949
}
944-
const cells = table.getPivotCells(visibilityOptions);
950+
const cells = table.getPivotCells(pivotStyle);
945951

946952
let headerRows = 0;
947-
if (visibilityOptions.displayColumnHeaders) {
953+
if (pivotStyle.displayColumnHeaders) {
948954
headerRows = table.columns.length - 1;
949955
}
950-
if (visibilityOptions.displayMeasuresRow) {
956+
if (pivotStyle.displayMeasuresRow) {
951957
headerRows++;
952958
}
953959
const pivotTitle = this.getters.getPivotName(pivotId);
954-
const tableHeight = Math.min(headerRows + _rowCount, cells[0].length);
960+
const tableHeight = Math.min(headerRows + pivotStyle.numberOfRows, cells[0].length);
955961
if (tableHeight === 0) {
956962
return [[{ value: pivotTitle }]];
957963
}
958-
const tableWidth = Math.min(1 + _columnCount, cells.length);
964+
const tableWidth = Math.min(1 + pivotStyle.numberOfColumns, cells.length);
959965
const result: Matrix<FunctionResultObject> = [];
960966
for (const col of range(0, tableWidth)) {
961967
result[col] = [];
@@ -978,7 +984,7 @@ export const PIVOT = {
978984
}
979985
}
980986
}
981-
if (visibilityOptions.displayColumnHeaders || visibilityOptions.displayMeasuresRow) {
987+
if (pivotStyle.displayColumnHeaders || pivotStyle.displayMeasuresRow) {
982988
result[0][0] = { value: pivotTitle };
983989
}
984990
return result;

packages/o-spreadsheet-engine/src/helpers/pivot/pivot_helpers.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
PivotField,
2626
PivotFields,
2727
PivotSortedColumn,
28+
PivotStyle,
2829
PivotTableCell,
2930
} from "../../types/pivot";
3031
import { Pivot } from "../../types/pivot_runtime";
@@ -33,6 +34,14 @@ import { deepEquals, getUniqueText, isDefined } from "../misc";
3334
import { PivotRuntimeDefinition } from "./pivot_runtime_definition";
3435
import { pivotTimeAdapter } from "./pivot_time_adapter";
3536

37+
export const DEFAULT_PIVOT_STYLE: Required<PivotStyle> = {
38+
displayTotals: true,
39+
displayColumnHeaders: true,
40+
displayMeasuresRow: true,
41+
numberOfRows: Number.MAX_VALUE,
42+
numberOfColumns: Number.MAX_VALUE,
43+
};
44+
3645
const AGGREGATOR_NAMES = {
3746
count: _t("Count"),
3847
count_distinct: _t("Count Distinct"),
@@ -446,3 +455,39 @@ export function togglePivotCollapse(position: CellPosition, env: SpreadsheetChil
446455
pivot: { ...definition, collapsedDomains: newDomains },
447456
});
448457
}
458+
459+
export function getPivotStyleFromFnArgs(
460+
definition: PivotCoreDefinition,
461+
rowCountArg: Maybe<FunctionResultObject | CellValue>,
462+
includeTotalArg: Maybe<FunctionResultObject | CellValue>,
463+
includeColumnHeadersArg: Maybe<FunctionResultObject | CellValue>,
464+
columnCountArg: Maybe<FunctionResultObject | CellValue>,
465+
includeMeasuresRowArg: Maybe<FunctionResultObject | CellValue>,
466+
locale: Locale
467+
): Required<PivotStyle> {
468+
const style = definition.style;
469+
470+
const numberOfRows =
471+
rowCountArg !== undefined
472+
? toNumber(rowCountArg, locale)
473+
: style?.numberOfRows ?? DEFAULT_PIVOT_STYLE.numberOfRows;
474+
const numberOfColumns =
475+
columnCountArg !== undefined
476+
? toNumber(columnCountArg, locale)
477+
: style?.numberOfColumns ?? DEFAULT_PIVOT_STYLE.numberOfColumns;
478+
479+
const displayTotals =
480+
includeTotalArg !== undefined
481+
? toBoolean(includeTotalArg)
482+
: style?.displayTotals ?? DEFAULT_PIVOT_STYLE.displayTotals;
483+
const displayColumnHeaders =
484+
includeColumnHeadersArg !== undefined
485+
? toBoolean(includeColumnHeadersArg)
486+
: style?.displayColumnHeaders ?? DEFAULT_PIVOT_STYLE.displayColumnHeaders;
487+
const displayMeasuresRow =
488+
includeMeasuresRowArg !== undefined
489+
? toBoolean(includeMeasuresRowArg)
490+
: style?.displayMeasuresRow ?? DEFAULT_PIVOT_STYLE.displayMeasuresRow;
491+
492+
return { numberOfRows, numberOfColumns, displayTotals, displayColumnHeaders, displayMeasuresRow };
493+
}

packages/o-spreadsheet-engine/src/helpers/pivot/table_spreadsheet_pivot.ts

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import {
55
PivotCollapsedDomains,
66
PivotDomain,
77
PivotSortedColumn,
8+
PivotStyle,
89
PivotTableCell,
910
PivotTableColumn,
1011
PivotTableRow,
11-
PivotVisibilityOptions,
1212
} from "../../types/pivot";
1313
import { deepEquals, lazy } from "../misc";
1414
import { isParentDomain, sortPivotTree } from "./pivot_domain_helpers";
15-
import { parseDimension, toNormalizedPivotValue } from "./pivot_helpers";
15+
import { DEFAULT_PIVOT_STYLE, parseDimension, toNormalizedPivotValue } from "./pivot_helpers";
1616

1717
interface CollapsiblePivotTableColumn extends PivotTableColumn {
1818
collapsedHeader?: boolean;
@@ -157,29 +157,23 @@ export class SpreadsheetPivotTable {
157157
return this.columns.at(-1)?.length || 0;
158158
}
159159

160-
private getSkippedRows(visibilityOptions: PivotVisibilityOptions) {
160+
private getSkippedRows(pivotStyle: Required<PivotStyle>) {
161161
const skippedRows: Set<number> = new Set();
162-
if (!visibilityOptions.displayColumnHeaders) {
162+
if (!pivotStyle.displayColumnHeaders) {
163163
for (let i = 0; i < this.columns.length - 1; i++) {
164164
skippedRows.add(i);
165165
}
166166
}
167-
if (!visibilityOptions.displayMeasuresRow) {
167+
if (!pivotStyle.displayMeasuresRow) {
168168
skippedRows.add(this.columns.length - 1);
169169
}
170170
return skippedRows;
171171
}
172172

173-
getPivotCells(
174-
visibilityOptions: PivotVisibilityOptions = {
175-
displayColumnHeaders: true,
176-
displayTotals: true,
177-
displayMeasuresRow: true,
178-
}
179-
): PivotTableCell[][] {
180-
const key = JSON.stringify(visibilityOptions);
173+
getPivotCells(pivotStyle: Required<PivotStyle> = DEFAULT_PIVOT_STYLE): PivotTableCell[][] {
174+
const key = JSON.stringify(pivotStyle);
181175
if (!this.pivotCells[key]) {
182-
const { displayTotals } = visibilityOptions;
176+
const { displayTotals } = pivotStyle;
183177
const numberOfDataRows = this.rows.length;
184178
const numberOfDataColumns = this.getNumberOfDataColumns();
185179
let pivotHeight = this.columns.length + numberOfDataRows;
@@ -191,7 +185,7 @@ export class SpreadsheetPivotTable {
191185
pivotWidth -= this.measures.length;
192186
}
193187
const domainArray: PivotTableCell[][] = [];
194-
const skippedRows = this.getSkippedRows(visibilityOptions);
188+
const skippedRows = this.getSkippedRows(pivotStyle);
195189
for (let col = 0; col < pivotWidth; col++) {
196190
domainArray.push([]);
197191
for (let row = 0; row < pivotHeight; row++) {

packages/o-spreadsheet-engine/src/plugins/ui_core_views/pivot_ui.ts

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { astToFormula } from "../../formulas/formula_formatter";
22
import { Token } from "../../formulas/tokenizer";
33
import { toScalar } from "../../functions/helper_matrices";
4-
import { toBoolean } from "../../functions/helpers";
54
import { deepEquals, getUniqueText } from "../../helpers/misc";
65
import {
76
getFirstPivotFunction,
87
getNumberOfPivotFunctions,
98
} from "../../helpers/pivot/pivot_composer_helpers";
109
import { domainToColRowDomain } from "../../helpers/pivot/pivot_domain_helpers";
10+
import { getPivotStyleFromFnArgs } from "../../helpers/pivot/pivot_helpers";
1111
import withPivotPresentationLayer from "../../helpers/pivot/pivot_presentation";
1212
import { pivotRegistry } from "../../helpers/pivot/pivot_registry";
1313
import { resetMapValueDimensionDate } from "../../helpers/pivot/spreadsheet_pivot/date_spreadsheet_pivot";
@@ -21,7 +21,7 @@ import {
2121
UpdatePivotCommand,
2222
} from "../../types/commands";
2323
import { CellPosition, FunctionResultObject, isMatrix, SortDirection, UID } from "../../types/misc";
24-
import { PivotCoreMeasure, PivotTableCell, PivotVisibilityOptions } from "../../types/pivot";
24+
import { PivotCoreMeasure, PivotTableCell } from "../../types/pivot";
2525
import { Pivot } from "../../types/pivot_runtime";
2626
import { CoreViewPlugin, CoreViewPluginConfig } from "../core_view_plugin";
2727
import { UIPluginConfig } from "../ui_plugin";
@@ -219,20 +219,16 @@ export class PivotUIPlugin extends CoreViewPlugin {
219219
return EMPTY_PIVOT_CELL;
220220
}
221221
if (functionName === "PIVOT") {
222-
const includeTotal = toScalar(args[2]);
223-
const shouldIncludeTotal = includeTotal === undefined ? true : toBoolean(includeTotal);
224-
const includeColumnHeaders = toScalar(args[3]);
225-
const includeMeasures = toScalar(args[5]);
226-
const shouldIncludeMeasures =
227-
includeMeasures === undefined ? true : toBoolean(includeMeasures);
228-
const shouldIncludeColumnHeaders =
229-
includeColumnHeaders === undefined ? true : toBoolean(includeColumnHeaders);
230-
const visibilityOptions: PivotVisibilityOptions = {
231-
displayColumnHeaders: shouldIncludeColumnHeaders,
232-
displayTotals: shouldIncludeTotal,
233-
displayMeasuresRow: shouldIncludeMeasures,
234-
};
235-
const pivotCells = pivot.getCollapsedTableStructure().getPivotCells(visibilityOptions);
222+
const pivotStyle = getPivotStyleFromFnArgs(
223+
this.getters.getPivotCoreDefinition(pivotId),
224+
toScalar(args[1]),
225+
toScalar(args[2]),
226+
toScalar(args[3]),
227+
toScalar(args[4]),
228+
toScalar(args[5]),
229+
this.getters.getLocale()
230+
);
231+
const pivotCells = pivot.getCollapsedTableStructure().getPivotCells(pivotStyle);
236232
const pivotCol = position.col - mainPosition.col;
237233
const pivotRow = position.row - mainPosition.row;
238234
return pivotCells[pivotCol][pivotRow];

packages/o-spreadsheet-engine/src/types/pivot.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export interface CommonPivotCoreDefinition {
6262
sortedColumn?: PivotSortedColumn;
6363
collapsedDomains?: PivotCollapsedDomains;
6464
customFields?: Record<string, PivotCustomGroupedField>;
65+
style?: PivotStyle;
6566
}
6667

6768
export interface PivotSortedColumn {
@@ -239,8 +240,10 @@ export interface DimensionTreeNode {
239240

240241
export type DimensionTree = DimensionTreeNode[];
241242

242-
export interface PivotVisibilityOptions {
243-
displayColumnHeaders: boolean;
244-
displayTotals: boolean;
245-
displayMeasuresRow: boolean;
243+
export interface PivotStyle {
244+
numberOfRows?: number;
245+
numberOfColumns?: number;
246+
displayTotals?: boolean;
247+
displayColumnHeaders?: boolean;
248+
displayMeasuresRow?: boolean;
246249
}

src/components/side_panel/chart/main_chart_panel/main_chart_panel.css

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)