@adaptabletools/adaptable 20.0.3 → 20.0.4-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptabletools/adaptable",
3
- "version": "20.0.3",
3
+ "version": "20.0.4-canary.0",
4
4
  "description": "Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements",
5
5
  "keywords": [
6
6
  "web-components",
@@ -12,7 +12,14 @@ export type TableAggregationColumns = {
12
12
  /**
13
13
  * Defines an Aggregated Column in a Pivot Layout
14
14
  */
15
- export type PivotAggregationColumns = TableAggregationColumns;
15
+ export type PivotAggregationColumns = {
16
+ ColumnId: string;
17
+ AggFunc: AggregationColumnValue;
18
+ TotalColumn?: boolean | 'before' | 'after' | {
19
+ PivotColumnId: string;
20
+ ShowTotal?: boolean | 'before' | 'after';
21
+ }[];
22
+ }[];
16
23
  export declare const WEIGHTED_AVERAGE_AGG_FN_NAME = "weightedAvg";
17
24
  /**
18
25
  * Defines a Weighted Average Agg
@@ -16,7 +16,7 @@ export interface BaseContext {
16
16
  */
17
17
  adaptableId: string;
18
18
  /**
19
- * Custom applicaton Context provided in Adaptable Options
19
+ * Custom application Context provided in `AdaptableOptions.adaptableContext`
20
20
  */
21
21
  adaptableContext: any;
22
22
  /**
@@ -148,6 +148,18 @@ export interface PivotLayout extends LayoutBase {
148
148
  * Row Grouped Columns Columns - must NOT be provided
149
149
  */
150
150
  RowGroupedColumns?: never;
151
+ /**
152
+ * Display Grand Total Row at the top or bottom of the Pivot Table
153
+ */
154
+ GrandTotalRow?: 'top' | 'bottom' | boolean;
155
+ /**
156
+ * Display automatically calculated Totals of all Pivot Columns, in the position specified
157
+ */
158
+ GrandTotalColumn?: 'before' | 'after' | boolean;
159
+ /**
160
+ * Display automatically calculated Totals within EACH Pivot Column Group, in the position specified
161
+ */
162
+ PivotGroupTotalColumn?: 'before' | 'after' | boolean;
151
163
  }
152
164
  /**
153
165
  * Manages how (and which) Row Group values are stored
@@ -197,12 +197,16 @@ export const pivotLayoutToPivotLayoutModel = (pivotLayout) => {
197
197
  ColumnPinning: pivotLayout.ColumnPinning,
198
198
  PivotColumns: pivotLayout.PivotColumns,
199
199
  PivotExpandLevel: pivotLayout.PivotExpandLevel,
200
- PivotAggregationColumns: (pivotLayout.PivotAggregationColumns || []).map(({ ColumnId, AggFunc }) => {
200
+ PivotAggregationColumns: (pivotLayout.PivotAggregationColumns || []).map(({ ColumnId, AggFunc, TotalColumn }) => {
201
201
  return {
202
202
  ColumnId,
203
203
  AggFunc: toAggFunc(AggFunc),
204
+ TotalColumn,
204
205
  };
205
206
  }),
207
+ GrandTotalRow: pivotLayout.GrandTotalRow,
208
+ GrandTotalColumn: pivotLayout.GrandTotalColumn,
209
+ PivotGroupTotalColumn: pivotLayout.PivotGroupTotalColumn,
206
210
  RowGroupValues: pivotLayout.RowGroupValues
207
211
  ? pivotLayout.RowGroupValues.RowGroupDefaultBehavior === 'always-collapsed' ||
208
212
  pivotLayout.RowGroupValues.RowGroupDefaultBehavior === 'always-expanded'
@@ -326,10 +330,20 @@ export const pivotLayoutModelToPivotLayout = (layoutModel, defaults) => {
326
330
  else {
327
331
  delete pivotLayout.RowGroupValues;
328
332
  }
333
+ if (layoutModel.GrandTotalRow) {
334
+ pivotLayout.GrandTotalRow = layoutModel.GrandTotalRow;
335
+ }
336
+ if (layoutModel.GrandTotalColumn) {
337
+ pivotLayout.GrandTotalColumn = layoutModel.GrandTotalColumn;
338
+ }
339
+ if (layoutModel.PivotGroupTotalColumn) {
340
+ pivotLayout.PivotGroupTotalColumn = layoutModel.PivotGroupTotalColumn;
341
+ }
329
342
  if (layoutModel.PivotAggregationColumns) {
330
- pivotLayout.PivotAggregationColumns = (layoutModel.PivotAggregationColumns || []).map(({ ColumnId, AggFunc }) => ({
343
+ pivotLayout.PivotAggregationColumns = (layoutModel.PivotAggregationColumns || []).map(({ ColumnId, AggFunc, TotalColumn }) => ({
331
344
  ColumnId,
332
345
  AggFunc: toAggregationColumnValue(AggFunc),
346
+ TotalColumn,
333
347
  }));
334
348
  }
335
349
  else {
package/src/env.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export default {
2
2
  NEXT_PUBLIC_INFINITE_TABLE_LICENSE_KEY: "StartDate=2021-06-29|EndDate=2030-01-01|Owner=Adaptable|Type=distribution|TS=1624971462479|C=137829811,1004007071,2756196225,1839832928,3994409405,636616862" || '',
3
- PUBLISH_TIMESTAMP: 1743768026543 || Date.now(),
4
- VERSION: "20.0.3" || '--current-version--',
3
+ PUBLISH_TIMESTAMP: 1744377437477 || Date.now(),
4
+ VERSION: "20.0.4-canary.0" || '--current-version--',
5
5
  };
@@ -62,26 +62,17 @@ export type ColumnAggregationModel = {
62
62
  aggFunc: string | true;
63
63
  weightedColumnId?: string;
64
64
  };
65
- export type AggregationColumnsModel = {
65
+ export type AggregationColumnsModelItem = {
66
66
  ColumnId: string;
67
67
  AggFunc: ColumnAggregationModel;
68
- }[];
69
- type RowSummaryPosition = 'Top' | 'Bottom';
70
- export interface RowSummaryModel {
71
- /**
72
- * Where Row Summary appears - 'Top' or 'Bottom'
73
- */
74
- Position?: RowSummaryPosition;
75
- /**
76
- * Map of Columns with Summary Expressions
77
- */
78
- ColumnsMap: Record<string, string>;
79
- /**
80
- * Evaluates only currently filtered rows in the summary
81
- * @defaultValue true
82
- */
83
- IncludeOnlyFilteredRows?: boolean;
84
- }
68
+ };
69
+ export type AggregationColumnsModel = AggregationColumnsModelItem[];
70
+ export type PivotAggregationColumnsModel = (AggregationColumnsModelItem & {
71
+ TotalColumn?: boolean | 'before' | 'after' | {
72
+ PivotColumnId: string;
73
+ ShowTotal?: boolean | 'before' | 'after';
74
+ }[];
75
+ })[];
85
76
  export interface TableLayoutModel extends BaseLayoutModel {
86
77
  TableColumns: string[];
87
78
  /**
@@ -96,6 +87,7 @@ export interface TableLayoutModel extends BaseLayoutModel {
96
87
  * @defaultValue 'single'
97
88
  */
98
89
  RowGroupDisplayType?: 'single' | 'multi';
90
+ PivotAggregationColumns?: never;
99
91
  PivotColumns?: never;
100
92
  PivotGroupedColumns?: never;
101
93
  PivotExpandLevel?: never;
@@ -110,13 +102,24 @@ export interface PivotLayoutModel extends BaseLayoutModel {
110
102
  /**
111
103
  * Columns showing aggregated values in Group Rows; 1st value in record is Column name, 2nd is either aggfunc (e.g. sum, avg etc.) or 'true' (to use default aggfunc)
112
104
  */
113
- PivotAggregationColumns?: AggregationColumnsModel;
105
+ PivotAggregationColumns?: PivotAggregationColumnsModel;
114
106
  TableAggregationColumns?: never;
115
107
  /**
116
108
  * Columns which are row-grouped when the Layout is applied
117
109
  */
118
110
  PivotGroupedColumns?: string[];
119
111
  RowGroupedColumns?: never;
112
+ /**
113
+ * Display Grand Total Row at the top or bottom of the Pivot Table
114
+ */
115
+ GrandTotalRow?: 'top' | 'bottom' | boolean;
116
+ /**
117
+ * Display Total of all Pivot Columns before or after the Pivot Columns
118
+ */
119
+ GrandTotalColumn?: 'before' | 'after' | boolean;
120
+ /**
121
+ * Display automatically calculated Totals within EACH Pivot Column Group, in the position specified
122
+ */
123
+ PivotGroupTotalColumn?: 'before' | 'after' | boolean;
120
124
  }
121
125
  export type LayoutModel = TableLayoutModel | PivotLayoutModel;
122
- export {};
@@ -69,7 +69,12 @@ export declare class LayoutManager<DATA_TYPE = any> extends LMEmitter {
69
69
  private computeColumnOrderAndVisibility;
70
70
  autoSizeColumns(columnIds?: string[]): false | string[];
71
71
  private applyPivotLayout;
72
+ applyPivotTotals(layout: PivotLayoutModel): void;
72
73
  applyPivotExpandLevel(layout: PivotLayoutModel): void;
73
74
  private withSuppressColumnAnimation;
75
+ private setupPivotTotals;
76
+ private patchGrandTotalColumn;
77
+ private patchPivotTotalColumn;
78
+ private getPivotTotalColumnConfig;
74
79
  }
75
80
  export {};
@@ -3,7 +3,7 @@ import { isPivotLayoutModel } from './isPivotLayoutModel';
3
3
  import { LMEmitter } from './LMEmitter';
4
4
  import { GROUP_COLUMN_ID__MULTI_PREFIX, GROUP_COLUMN_ID__SINGLE, normalizeLayoutModel, normalizePivotLayoutModel, normalizeTableLayoutModel, } from './normalizeLayoutModel';
5
5
  import { isLayoutEqual } from './isLayoutEqual';
6
- import { simplifyTableLayoutModel, simplifyPivotLayoutModel, simplifyLayoutModel, } from './simplifyLayoutModel';
6
+ import { simplifyLayoutModel, simplifyPivotLayoutModel, simplifyTableLayoutModel, } from './simplifyLayoutModel';
7
7
  import { sortColumnIdsByOrder } from './sortColumnIdsByOrder';
8
8
  function flattenColDefs(colDefs) {
9
9
  const res = [];
@@ -117,8 +117,12 @@ export class LayoutManager extends LMEmitter {
117
117
  }).bind(this);
118
118
  }
119
119
  this.setOptions(options);
120
+ // this ensures the grand total columns are positioned correctly (before/after) even when changed at runtime
121
+ // see https://www.ag-grid.com/react-data-grid/pivoting-column-groups/#changing-data-filters-and-configurations
122
+ this.gridApi.setGridOption('enableStrictPivotColumnOrder', true);
120
123
  this.setupEvents();
121
124
  this.indexColumns();
125
+ this.setupPivotTotals();
122
126
  globalThis.layoutManager = this;
123
127
  }
124
128
  destroy() {
@@ -272,7 +276,7 @@ export class LayoutManager extends LMEmitter {
272
276
  let ColumnPinning = {};
273
277
  const gridState = this.gridApi.getState();
274
278
  const prevLayout = this.currentLayout;
275
- const prevAggColumns = prevLayout?.TableAggregationColumns;
279
+ const prevAggColumns = prevLayout?.TableAggregationColumns ?? prevLayout?.PivotAggregationColumns;
276
280
  const prevAggColumnsMap = prevAggColumns?.reduce((acc, agg) => {
277
281
  acc[agg.ColumnId] = agg;
278
282
  return acc;
@@ -983,6 +987,7 @@ export class LayoutManager extends LMEmitter {
983
987
  return columnIds;
984
988
  }
985
989
  applyPivotLayout(layout, options) {
990
+ this.applyPivotTotals(layout);
986
991
  const columnState = this.computeColumnStateForPivotLayout(layout);
987
992
  // by simply calling this.gridApi.applyColumnState(columnState)
988
993
  // the order of aggregations is not preserved/guaranteed by ag-grid
@@ -1010,6 +1015,50 @@ export class LayoutManager extends LMEmitter {
1010
1015
  this.applyRowGroupValues(layout.RowGroupValues);
1011
1016
  }
1012
1017
  }
1018
+ applyPivotTotals(layout) {
1019
+ /**
1020
+ * GrandTotalRow
1021
+ */
1022
+ if (layout.GrandTotalRow) {
1023
+ const grandTotalRow = layout.GrandTotalRow === true || layout.GrandTotalRow === 'top'
1024
+ ? 'top'
1025
+ : layout.GrandTotalRow === 'bottom'
1026
+ ? 'bottom'
1027
+ : null;
1028
+ this.gridApi.setGridOption('grandTotalRow', grandTotalRow);
1029
+ }
1030
+ else {
1031
+ this.gridApi.setGridOption('grandTotalRow', null);
1032
+ }
1033
+ /**
1034
+ * GrandTotalColumn
1035
+ */
1036
+ if (layout.GrandTotalColumn) {
1037
+ const grandTotalColumn = layout.GrandTotalColumn === true || layout.GrandTotalColumn === 'before'
1038
+ ? 'before'
1039
+ : layout.GrandTotalColumn === 'after'
1040
+ ? 'after'
1041
+ : null;
1042
+ this.gridApi.setGridOption('pivotRowTotals', grandTotalColumn);
1043
+ }
1044
+ else {
1045
+ this.gridApi.setGridOption('pivotRowTotals', null);
1046
+ }
1047
+ /**
1048
+ * PivotGroupTotalColumn
1049
+ */
1050
+ if (layout.PivotGroupTotalColumn) {
1051
+ const pivotGroupTotalColumn = layout.PivotGroupTotalColumn === true || layout.PivotGroupTotalColumn === 'before'
1052
+ ? 'before'
1053
+ : layout.PivotGroupTotalColumn === 'after'
1054
+ ? 'after'
1055
+ : null;
1056
+ this.gridApi.setGridOption('pivotColumnGroupTotals', pivotGroupTotalColumn);
1057
+ }
1058
+ else {
1059
+ this.gridApi.setGridOption('pivotColumnGroupTotals', null);
1060
+ }
1061
+ }
1013
1062
  applyPivotExpandLevel(layout) {
1014
1063
  const PivotExpandLevel = layout.PivotExpandLevel ?? -1;
1015
1064
  const allDisplayedColumnGroups = this.gridApi.getAllDisplayedColumnGroups();
@@ -1045,4 +1094,118 @@ export class LayoutManager extends LMEmitter {
1045
1094
  }
1046
1095
  return res;
1047
1096
  }
1097
+ setupPivotTotals() {
1098
+ const _original_processPivotResultColDef = this.gridApi.getGridOption('processPivotResultColDef');
1099
+ this.gridApi.setGridOption('processPivotResultColDef', (resulColDef) => {
1100
+ _original_processPivotResultColDef?.(resulColDef);
1101
+ if (!isPivotLayoutModel(this.currentLayout)) {
1102
+ return;
1103
+ }
1104
+ this.patchGrandTotalColumn(resulColDef);
1105
+ });
1106
+ const _original_processPivotResultColGroupDef = this.gridApi.getGridOption('processPivotResultColGroupDef');
1107
+ this.gridApi.setGridOption('processPivotResultColGroupDef', (colGroupDef) => {
1108
+ _original_processPivotResultColGroupDef?.(colGroupDef);
1109
+ if (!isPivotLayoutModel(this.currentLayout)) {
1110
+ return;
1111
+ }
1112
+ this.patchPivotTotalColumn(colGroupDef);
1113
+ });
1114
+ }
1115
+ patchGrandTotalColumn(resultColDef) {
1116
+ if (!isPivotLayoutModel(this.currentLayout) || !this.currentLayout.GrandTotalColumn) {
1117
+ return;
1118
+ }
1119
+ if (resultColDef.colId?.startsWith('PivotRowTotal_')) {
1120
+ resultColDef.headerName = `Grand Total ${resultColDef.headerName}`;
1121
+ }
1122
+ }
1123
+ patchPivotTotalColumn(colGroupDef) {
1124
+ const hasPivotTotalCols = (pivotLayout) => {
1125
+ return pivotLayout.PivotAggregationColumns?.some((aggCol) => !!aggCol.TotalColumn);
1126
+ };
1127
+ const isPivotTotalColDef = (colDef) => {
1128
+ return !!colDef.pivotTotalColumnIds?.length;
1129
+ };
1130
+ if (!isPivotLayoutModel(this.currentLayout) || !hasPivotTotalCols(this.currentLayout)) {
1131
+ return;
1132
+ }
1133
+ const pivotTotalColDefsBefore = [];
1134
+ const pivotTotalColDefsAfter = [];
1135
+ const normalColDefs = [];
1136
+ colGroupDef.children.forEach((colDef) => {
1137
+ if (isPivotTotalColDef(colDef)) {
1138
+ if (!colDef.colId.startsWith('pivot_')) {
1139
+ this.warn(`Pivot total column ${colDef.colId} is not prefixed with 'pivot_', skipping...`);
1140
+ return;
1141
+ }
1142
+ // we do this for all total cols, but we will hide the ones that are not visible
1143
+ colDef.columnGroupShow = undefined;
1144
+ colDef.headerName = `Total ${colDef.headerName}`;
1145
+ const totalColConfig = this.getPivotTotalColumnConfig(colDef, this.currentLayout);
1146
+ if (!totalColConfig.visible) {
1147
+ colDef.hide = true;
1148
+ }
1149
+ else {
1150
+ if (totalColConfig.position === 'after') {
1151
+ pivotTotalColDefsAfter.push(colDef);
1152
+ }
1153
+ else {
1154
+ pivotTotalColDefsBefore.push(colDef);
1155
+ }
1156
+ }
1157
+ }
1158
+ else {
1159
+ normalColDefs.push(colDef);
1160
+ }
1161
+ });
1162
+ colGroupDef.children = [
1163
+ ...pivotTotalColDefsBefore,
1164
+ ...normalColDefs,
1165
+ ...pivotTotalColDefsAfter,
1166
+ ];
1167
+ }
1168
+ getPivotTotalColumnConfig(colDef, currentPivotLayout) {
1169
+ const defaultHiddenConfig = {
1170
+ visible: false,
1171
+ };
1172
+ const colId = colDef.colId;
1173
+ // Split by underscore to get 4 parts
1174
+ const parts = colId.split('_');
1175
+ if (parts.length !== 4) {
1176
+ this.warn(`Unsupported format of pivot total column id: ${colId}`);
1177
+ return defaultHiddenConfig;
1178
+ }
1179
+ // e.g.
1180
+ // pivot_country-sport-year_United States-Basketball_gold
1181
+ // pivotColumnIds: ['country', 'sport', 'year']
1182
+ // pivotKeys: ['United States', 'Basketball']
1183
+ // aggregationColumnId: 'gold'
1184
+ const [_pivotPrefix, pivotColsTxt, pivotKeysTxt, aggregationColumnId] = parts;
1185
+ const pivotColumnIds = pivotColsTxt.split('-');
1186
+ const pivotKeys = pivotKeysTxt.split('-');
1187
+ const layoutAggCol = currentPivotLayout.PivotAggregationColumns?.find((col) => col.ColumnId === aggregationColumnId);
1188
+ if (!layoutAggCol) {
1189
+ this.warn(`Pivot Totals: could NOT find aggregation(value) column with id ${aggregationColumnId}`);
1190
+ return defaultHiddenConfig;
1191
+ }
1192
+ const layoutPivotTotalColumn = layoutAggCol.TotalColumn;
1193
+ if (!layoutPivotTotalColumn) {
1194
+ return defaultHiddenConfig;
1195
+ }
1196
+ const pivotColumnId = pivotColumnIds[pivotKeys.length - 1];
1197
+ if (Array.isArray(layoutPivotTotalColumn)) {
1198
+ const pivotSpecificConfig = layoutPivotTotalColumn.find((config) => config.PivotColumnId === pivotColumnId);
1199
+ return {
1200
+ visible: pivotSpecificConfig && pivotSpecificConfig.ShowTotal !== false,
1201
+ position: pivotSpecificConfig?.ShowTotal === 'after' ? 'after' : 'before',
1202
+ };
1203
+ }
1204
+ else {
1205
+ return {
1206
+ visible: !!layoutPivotTotalColumn,
1207
+ position: layoutPivotTotalColumn === 'after' ? 'after' : 'before',
1208
+ };
1209
+ }
1210
+ }
1048
1211
  }
@@ -139,6 +139,9 @@ export function normalizePivotLayoutModel(layout) {
139
139
  // make it an own property
140
140
  layout.SuppressAggFuncInHeader = undefined;
141
141
  }
142
+ if (!layout.GrandTotalRow) {
143
+ layout.GrandTotalRow = false;
144
+ }
142
145
  return layout;
143
146
  }
144
147
  export function normalizeLayoutModel(layout, options) {