@adaptabletools/adaptable 20.0.7-canary.1 → 20.0.7-canary.2

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.
Files changed (39) hide show
  1. package/agGrid.d.ts +37 -0
  2. package/agGrid.js +38 -0
  3. package/base.css +19 -3
  4. package/base.css.map +1 -1
  5. package/index.css +17 -3
  6. package/index.css.map +1 -1
  7. package/package.json +3 -3
  8. package/src/AdaptableOptions/LayoutOptions.d.ts +3 -6
  9. package/src/AdaptableState/Common/AdaptableColumn.d.ts +10 -5
  10. package/src/AdaptableState/Common/AdaptableColumn.js +26 -0
  11. package/src/AdaptableState/Common/AggregationColumns.d.ts +10 -0
  12. package/src/AdaptableState/Common/AggregationColumns.js +11 -0
  13. package/src/Api/Implementation/ColumnApiImpl.d.ts +2 -2
  14. package/src/Api/Implementation/ColumnApiImpl.js +30 -2
  15. package/src/Api/Internal/ColumnInternalApi.js +3 -3
  16. package/src/View/Alert/Wizard/AlertButtonsEditor.js +9 -10
  17. package/src/View/Alert/Wizard/AlertNotificationWizardSection.js +26 -25
  18. package/src/View/Components/ColumnFilter/ColumnFilter.js +1 -1
  19. package/src/View/Components/FilterForm/ListBoxFilterForm.js +6 -3
  20. package/src/View/Components/NewScopeComponent.js +2 -1
  21. package/src/View/Layout/Wizard/LayoutWizard.js +2 -2
  22. package/src/View/Layout/Wizard/sections/AggregationsSection.js +1 -1
  23. package/src/View/Layout/Wizard/sections/PivotAggregationsSection.d.ts +2 -2
  24. package/src/View/Layout/Wizard/sections/PivotAggregationsSection.js +219 -43
  25. package/src/components/Select/Select.js +15 -3
  26. package/src/env.js +2 -2
  27. package/src/layout-manager/src/index.d.ts +1 -1
  28. package/src/layout-manager/src/index.js +26 -6
  29. package/src/layout-manager/src/isPivotAggTotalColumn.d.ts +2 -0
  30. package/src/layout-manager/src/{isPivotTotalColumn.js → isPivotAggTotalColumn.js} +1 -1
  31. package/src/layout-manager/src/isPivotGrandTotalColumn.d.ts +2 -0
  32. package/src/layout-manager/src/isPivotGrandTotalColumn.js +3 -0
  33. package/src/layout-manager/src/isPivotGroupTotalColumn.d.ts +1 -2
  34. package/src/layout-manager/src/isPivotGroupTotalColumn.js +2 -2
  35. package/src/metamodel/adaptable.metamodel.d.ts +8 -2
  36. package/src/metamodel/adaptable.metamodel.js +1 -1
  37. package/src/types.d.ts +1 -1
  38. package/tsconfig.esm.tsbuildinfo +1 -1
  39. package/src/layout-manager/src/isPivotTotalColumn.d.ts +0 -2
@@ -64,31 +64,32 @@ export const AlertNotificationWizardSection = (props) => {
64
64
  React.createElement(Tabs, { "data-name": "display-options", mt: 2, mb: 3, autoFocus: false },
65
65
  React.createElement(Tabs.Tab, null, "Notification Options"),
66
66
  React.createElement(Tabs.Content, null,
67
- React.createElement(CheckBox, { checked: data.AlertProperties?.DisplayNotification, onChange: (DisplayNotification) => {
68
- const newAlertDefinition = {
69
- ...data,
70
- AlertProperties: {
71
- ...data.AlertProperties,
72
- DisplayNotification,
73
- },
74
- };
75
- if (!DisplayNotification && typeof newAlertDefinition.AlertForm === 'object') {
76
- delete newAlertDefinition.AlertForm.Buttons;
77
- }
78
- if (DisplayNotification && newAlertDefinition.AlertForm == undefined) {
79
- newAlertDefinition.AlertForm =
80
- api.alertApi.internalApi.getDefaultAlertNotificationForm();
81
- }
82
- // make sure we have at least one button
83
- if (typeof newAlertDefinition.AlertForm === 'object' &&
84
- (!newAlertDefinition.AlertForm?.Buttons ||
85
- newAlertDefinition.AlertForm?.Buttons?.length === 0)) {
86
- newAlertDefinition.AlertForm.Buttons = [
87
- api.alertApi.internalApi.getDefaultButton(),
88
- ];
89
- }
90
- props.onChange(newAlertDefinition);
91
- } }, "Display a Notification when Alert is triggered (with action buttons)"),
67
+ React.createElement("div", null,
68
+ React.createElement(CheckBox, { checked: data.AlertProperties?.DisplayNotification, onChange: (DisplayNotification) => {
69
+ const newAlertDefinition = {
70
+ ...data,
71
+ AlertProperties: {
72
+ ...data.AlertProperties,
73
+ DisplayNotification,
74
+ },
75
+ };
76
+ if (!DisplayNotification && typeof newAlertDefinition.AlertForm === 'object') {
77
+ delete newAlertDefinition.AlertForm.Buttons;
78
+ }
79
+ if (DisplayNotification && newAlertDefinition.AlertForm == undefined) {
80
+ newAlertDefinition.AlertForm =
81
+ api.alertApi.internalApi.getDefaultAlertNotificationForm();
82
+ }
83
+ // make sure we have at least one button
84
+ if (typeof newAlertDefinition.AlertForm === 'object' &&
85
+ (!newAlertDefinition.AlertForm?.Buttons ||
86
+ newAlertDefinition.AlertForm?.Buttons?.length === 0)) {
87
+ newAlertDefinition.AlertForm.Buttons = [
88
+ api.alertApi.internalApi.getDefaultButton(),
89
+ ];
90
+ }
91
+ props.onChange(newAlertDefinition);
92
+ } }, "Display a Notification when Alert is triggered (with action buttons)")),
92
93
  data.AlertProperties?.DisplayNotification ? (typeof data.AlertForm === 'string' ? (React.createElement(Text, { fontSize: 2 }, "Alert buttons cannot be customized because form is dynamically driven")) : (React.createElement(AlertButtonsEditor, { alertType: props.alertType, AlertButtons: data.AlertForm?.Buttons, api: api, adaptableAlert: adaptableAlert, onChange: (buttons) => {
93
94
  props.onChange({
94
95
  ...data,
@@ -18,7 +18,7 @@ const ColumnFilterPredicateDropdown = (props) => {
18
18
  });
19
19
  const operator = props.predicate?.operator;
20
20
  const isAndOr = operator === 'AND' || operator === 'OR';
21
- return (React.createElement(Box, { display: 'flex', alignItems: "center", style: {
21
+ return (React.createElement(Box, { display: 'flex', alignItems: "center", className: "ab-ColumnFilterPredicateDropdown", style: {
22
22
  //@ts-ignore ignore
23
23
  '--ab-cmp-input__background': 'var(--ab-color-primary)',
24
24
  } },
@@ -24,9 +24,12 @@ export const ColumnValuesSelect = (props) => {
24
24
  }
25
25
  return true;
26
26
  });
27
- const component = (React.createElement(Select, { isMulti: true, showHeaderSelectionCheckbox: true, searchable: true, closeMenuOnSelect: false, menuStyle: {
28
- minWidth: `var(--ab-cmp-select-column-menu-${column.columnId}__min-width, var(--ab-cmp-select-column-menu__min-width, 260px))`,
29
- }, ...props.selectProps, options: options, value: value, isLoading: props.isLoading, onChange: props.onChange }));
27
+ const menuStyle = React.useMemo(() => {
28
+ return {
29
+ minWidth: `var(--ab-cmp-select-column-menu-${column.columnId}__min-width, var(--ab-cmp-select-column-menu__min-width, 160px))`,
30
+ };
31
+ }, [column.columnId]);
32
+ const component = (React.createElement(Select, { isMulti: true, showHeaderSelectionCheckbox: true, searchable: true, closeMenuOnSelect: false, menuStyle: menuStyle, ...props.selectProps, options: options, value: value, isLoading: props.isLoading, onChange: props.onChange }));
30
33
  return (React.createElement("div", { className: join(baseClassName, props.isLoading && `${baseClassName}--loading`, !value.length && `${baseClassName}--empty`), onKeyDownCapture: (e) => {
31
34
  const event = e.nativeEvent || e;
32
35
  event.stopPropagation = () => {
@@ -9,6 +9,7 @@ import { NewColumnSelector } from './ColumnSelector';
9
9
  import { AdaptableFormControlTextClear } from './Forms/AdaptableFormControlTextClear';
10
10
  import { useAdaptable } from '../AdaptableContext';
11
11
  import { ValueOptionsTags } from './ValueSelector';
12
+ import { getColumnTypeFriendlyName } from '../../AdaptableState/Common/AdaptableColumn';
12
13
  export const isScopeValid = ({ Scope }) => {
13
14
  const result = [];
14
15
  if (!Scope) {
@@ -175,5 +176,5 @@ export const NewScopeComponent = (props) => {
175
176
  ColumnTypes: columnTypes,
176
177
  };
177
178
  props.updateScope(newScope);
178
- } }, columnType)))))))));
179
+ } }, getColumnTypeFriendlyName(columnType))))))))));
179
180
  };
@@ -18,7 +18,7 @@ import { areSummaryRowsValid, RowSummarySection, RowSummarySectionSummary, } fro
18
18
  import { WEIGHTED_AVERAGE_AGGREGATED_FUNCTION } from '../../../AdaptableState/Common/RowSummary';
19
19
  import { isPivotLayout } from '../../../Utilities/isPivotLayout';
20
20
  import { PivotRowGroupingSection, PivotRowGroupingSectionSummary, } from './sections/PivotRowGroupingSection';
21
- import { PivotAggregationsSection, PivotAggregationsSectionSummary, } from './sections/PivotAggregationsSection';
21
+ import { isPivotAggregationsSectionValid, PivotAggregationsSection, PivotAggregationsSectionSummary, } from './sections/PivotAggregationsSection';
22
22
  export const LayoutWizard = (props) => {
23
23
  const dispatch = useDispatch();
24
24
  const adaptable = useAdaptable();
@@ -113,7 +113,7 @@ export const LayoutWizard = (props) => {
113
113
  isVisible: () => layoutSupportedFeatures.PivotAggregationColumns && layoutSupportedFeatures.PivotColumns,
114
114
  details: 'Select Pivot Column Aggregations',
115
115
  renderSummary: () => React.createElement(PivotAggregationsSectionSummary, null),
116
- isValid: (data) => isAggregationsSectionValid(data),
116
+ isValid: (data) => isPivotAggregationsSectionValid(data),
117
117
  render: () => (React.createElement(Box, { p: 2, style: { height: '100%' } },
118
118
  React.createElement(PivotAggregationsSection, { onChange: (layout) => {
119
119
  let newLayout = cloneObject(layout);
@@ -190,7 +190,7 @@ export const AggregationsSection = (props) => {
190
190
  React.createElement(Tabs.Content, null,
191
191
  React.createElement(Flex, null,
192
192
  React.createElement(FormLayout, null,
193
- React.createElement(CheckBox, { checked: layout.SuppressAggFuncInHeader, onChange: handleSuppressAggFuncInHeader }, "Suppress Aggregation Function Text in Column Header"))),
193
+ React.createElement(CheckBox, { checked: layout.SuppressAggFuncInHeader, onChange: handleSuppressAggFuncInHeader }, "Omit Aggregation Function from Header"))),
194
194
  React.createElement(ValueSelector, { showFilterInput: true, showSelectedOnlyPosition: "top", filter: columnFilter, toIdentifier: (option) => `${option.columnId}`, toLabel: (option) => option.friendlyName ?? option.columnId, toListLabel: (column) => (React.createElement(ColumnRow, { onChangeAggFunction: handleAggregationChange, layout: layout, column: column, aggregationColumnsMap: aggregationColumnsMap, numberColumns: numberColumns })), options: sortedAggregableColumns, value: (layout.TableAggregationColumns || []).map((agg) => agg.ColumnId), allowReorder: () => true, xSelectedLabel: () => {
195
195
  return `Active aggregations:`;
196
196
  }, onChange: handleColumnsSelectionChange }))));
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- import { Layout, PivotLayout } from '../../../../../types';
3
- export declare const isAggregationsSectionValid: (data: Layout) => true | string;
2
+ import { PivotLayout } from '../../../../../types';
3
+ export declare const isPivotAggregationsSectionValid: (data: PivotLayout) => true | string;
4
4
  export declare const PivotAggregationsSectionSummary: React.FunctionComponent;
5
5
  interface PivotAggregationsSectionProps {
6
6
  onChange: (data: PivotLayout) => void;
@@ -5,11 +5,14 @@ import DropdownButton from '../../../../components/DropdownButton';
5
5
  import FormLayout, { FormRow } from '../../../../components/FormLayout';
6
6
  import { Tabs } from '../../../../components/Tabs';
7
7
  import { Tag } from '../../../../components/Tag';
8
+ import { getAggFuncName, WEIGHTED_AVERAGE_AGG_FN_NAME, } from '../../../../AdaptableState/Common/AggregationColumns';
8
9
  import { useAdaptable } from '../../../AdaptableContext';
9
10
  import { ValueSelector } from '../../../Components/ValueSelector';
10
11
  import { useOnePageAdaptableWizardContext } from '../../../Wizard/OnePageAdaptableWizard';
11
12
  import { columnFilter } from './Utilities';
12
13
  import ArrayExtensions from '../../../../Utilities/Extensions/ArrayExtensions';
14
+ import StringExtensions from '../../../../Utilities/Extensions/StringExtensions';
15
+ import { Select } from '../../../../components/Select';
13
16
  const PivotColumnRow = (props) => {
14
17
  const adaptable = useAdaptable();
15
18
  const aggValue = (props.layout.PivotAggregationColumns || []).find((x) => x.ColumnId === props.column.columnId)?.AggFunc;
@@ -21,31 +24,31 @@ const PivotColumnRow = (props) => {
21
24
  return {
22
25
  label: fnName,
23
26
  onClick: () => {
24
- let aggCols = props.layout.PivotAggregationColumns;
27
+ let aggCols = props.layout.PivotAggregationColumns || [];
25
28
  if (!aggCols) {
26
29
  return;
27
30
  }
28
- if (fnName === WEIGHTED_AVERAGE_AGG_FN_NAME) {
29
- aggCols = aggCols.map((x) => {
30
- if (x.ColumnId === props.column.columnId) {
31
- return {
32
- ...x,
33
- type: 'weightedAverage',
34
- weightedColumnId: null,
35
- };
36
- }
37
- return x;
38
- });
39
- }
40
- else {
41
- aggCols = aggCols.map((x) => {
42
- if (x.ColumnId === props.column.columnId) {
43
- return {
44
- ...x,
45
- AggFunc: fnName,
46
- };
47
- }
48
- return x;
31
+ const AggFuncValue = fnName === WEIGHTED_AVERAGE_AGG_FN_NAME
32
+ ? {
33
+ type: 'weightedAverage',
34
+ weightedColumnId: null,
35
+ }
36
+ : fnName;
37
+ let found = false;
38
+ aggCols = aggCols.map(({ ColumnId, AggFunc }) => {
39
+ if (ColumnId === props.column.columnId) {
40
+ found = true;
41
+ return {
42
+ ColumnId,
43
+ AggFunc: AggFuncValue,
44
+ };
45
+ }
46
+ return { ColumnId, AggFunc };
47
+ });
48
+ if (!found) {
49
+ aggCols.push({
50
+ ColumnId: props.column.columnId,
51
+ AggFunc: AggFuncValue,
49
52
  });
50
53
  }
51
54
  props.onChangeAggFunction(aggCols);
@@ -62,16 +65,27 @@ const PivotColumnRow = (props) => {
62
65
  if (!aggCols) {
63
66
  return;
64
67
  }
65
- aggCols = aggCols.map((x) => {
66
- if (x.ColumnId === props.column.columnId) {
68
+ const AggFuncValue = {
69
+ type: 'weightedAverage',
70
+ weightedColumnId: col.columnId,
71
+ };
72
+ let found = false;
73
+ aggCols = aggCols.map(({ ColumnId, AggFunc }) => {
74
+ if (ColumnId === props.column.columnId) {
75
+ found = true;
67
76
  return {
68
- ...x,
69
- type: 'weightedAverage',
70
- weightedColumnId: col.columnId,
77
+ ColumnId,
78
+ AggFunc: AggFuncValue,
71
79
  };
72
80
  }
73
- return x;
81
+ return { ColumnId, AggFunc };
74
82
  });
83
+ if (!found) {
84
+ aggCols.push({
85
+ ColumnId: props.column.columnId,
86
+ AggFunc: AggFuncValue,
87
+ });
88
+ }
75
89
  props.onChangeAggFunction(aggCols);
76
90
  },
77
91
  };
@@ -83,18 +97,122 @@ const PivotColumnRow = (props) => {
83
97
  ? adaptable.api.columnApi.getFriendlyNameForColumnId(aggValue.weightedColumnId)
84
98
  : 'Select Weight';
85
99
  }
86
- return (React.createElement(Flex, { alignItems: "center" },
87
- props.column.friendlyName,
88
- aggValue && (React.createElement(DropdownButton, { columns: ['label'], items: aggOptions, ml: 2 }, currentAggFnName)),
89
- currentAggFnName === WEIGHTED_AVERAGE_AGG_FN_NAME && (React.createElement(Flex, { backgroundColor: "primary", ml: 3, alignItems: "center" },
90
- React.createElement(Text, null, "Weight"),
91
- ' ',
92
- React.createElement(DropdownButton, { columns: ['label'], items: numericColumnsOptions, ml: 2 }, weightName)))));
100
+ const totalOptions = ['Off', 'Before', 'After', 'Pivot Specific'].map((totalVariant) => {
101
+ return {
102
+ label: totalVariant,
103
+ onClick: () => {
104
+ let aggCols = props.layout.PivotAggregationColumns;
105
+ if (!aggCols) {
106
+ return;
107
+ }
108
+ aggCols = aggCols.map((aggCol) => {
109
+ if (aggCol.ColumnId === props.column.columnId) {
110
+ let updatedTotalColumn = false;
111
+ if (totalVariant === 'Before') {
112
+ updatedTotalColumn = 'before';
113
+ }
114
+ if (totalVariant === 'After') {
115
+ updatedTotalColumn = 'after';
116
+ }
117
+ if (totalVariant === 'Pivot Specific') {
118
+ updatedTotalColumn = props.layout.PivotColumns.map((pivotColId) => {
119
+ return {
120
+ PivotColumnId: pivotColId,
121
+ ShowTotal: true,
122
+ };
123
+ });
124
+ }
125
+ return {
126
+ ...aggCol,
127
+ TotalColumn: updatedTotalColumn,
128
+ };
129
+ }
130
+ return aggCol;
131
+ });
132
+ props.onChangeAggFunction(aggCols);
133
+ },
134
+ };
135
+ });
136
+ const currentAggCol = props.layout.PivotAggregationColumns?.find((aggCol) => aggCol.ColumnId === props.column.columnId);
137
+ const currentTotal = currentAggCol?.TotalColumn
138
+ ? currentAggCol.TotalColumn === true || currentAggCol.TotalColumn === 'before'
139
+ ? 'Before'
140
+ : currentAggCol.TotalColumn === 'after'
141
+ ? 'After'
142
+ : Array.isArray(currentAggCol.TotalColumn)
143
+ ? 'Pivot Specific'
144
+ : 'Off'
145
+ : 'Off';
146
+ const hasPivotSpecificTotals = Array.isArray(currentAggCol?.TotalColumn);
147
+ const pivotSpecificTotals = Array.isArray(currentAggCol?.TotalColumn)
148
+ ? currentAggCol.TotalColumn
149
+ : props.layout.PivotColumns?.map((pivotColId) => ({
150
+ PivotColumnId: pivotColId,
151
+ ShowTotal: false,
152
+ }));
153
+ const handleTotalChange = (pivotColId, value) => {
154
+ const updatedAggCols = (props.layout.PivotAggregationColumns || []).map((aggCol) => {
155
+ if (aggCol.ColumnId === props.column.columnId) {
156
+ const updatedTotals = pivotSpecificTotals.map((total) => {
157
+ if (total.PivotColumnId === pivotColId) {
158
+ return { ...total, ShowTotal: value };
159
+ }
160
+ return total;
161
+ });
162
+ return { ...aggCol, TotalColumn: updatedTotals };
163
+ }
164
+ return aggCol;
165
+ });
166
+ props.onChangeAggFunction(updatedAggCols);
167
+ };
168
+ const pivotTotalOptions = ['Off', 'Before', 'After'].map((option) => ({
169
+ label: option,
170
+ value: option === 'Off' ? false : option.toLowerCase(),
171
+ }));
172
+ return (React.createElement(Box, { "data-name": props.column.columnId, className: "ab-Layout-Wizard__ColumnRow" },
173
+ React.createElement(Flex, { alignItems: "flex-start" },
174
+ React.createElement(Flex, { flex: "0 0 auto", alignItems: "center" },
175
+ React.createElement(Flex, { minWidth: 80 }, props.column.friendlyName),
176
+ aggValue && (React.createElement(DropdownButton, { columns: ['label'], items: aggOptions, ml: 2 }, currentAggFnName)),
177
+ currentAggFnName === WEIGHTED_AVERAGE_AGG_FN_NAME && (React.createElement(Flex, { backgroundColor: "primary", ml: 3, alignItems: "center" },
178
+ React.createElement(Text, null, "Weight"),
179
+ ' ',
180
+ React.createElement(DropdownButton, { columns: ['label'], items: numericColumnsOptions, ml: 2 }, weightName))),
181
+ aggValue && (React.createElement(Flex, { backgroundColor: "primary", ml: 3, alignItems: "center" },
182
+ React.createElement(Text, null, "Total Column"),
183
+ ' ',
184
+ React.createElement(DropdownButton, { columns: ['label'], items: totalOptions, ml: 2 }, currentTotal)))),
185
+ hasPivotSpecificTotals && (React.createElement(Flex, { ml: 2, pl: 2, flexWrap: "wrap", flex: "1 1 auto", alignItems: "center", style: {
186
+ minWidth: '200px',
187
+ borderLeft: '1px solid var(--ab-color-text-on-primary)',
188
+ rowGap: '8px',
189
+ columnGap: '12px',
190
+ } }, props.layout.PivotColumns.map((pivotColId) => {
191
+ const pivotTotalSetting = pivotSpecificTotals.find((t) => t.PivotColumnId === pivotColId);
192
+ const currentValue = pivotTotalSetting == undefined
193
+ ? 'Off'
194
+ : pivotTotalSetting.ShowTotal === false
195
+ ? 'Off'
196
+ : pivotTotalSetting.ShowTotal === 'before' ||
197
+ pivotTotalSetting.ShowTotal === true ||
198
+ pivotTotalSetting.ShowTotal == undefined
199
+ ? 'Before'
200
+ : pivotTotalSetting.ShowTotal === 'after'
201
+ ? 'After'
202
+ : 'Off';
203
+ return (React.createElement(Flex, { key: pivotColId, alignItems: "center" },
204
+ React.createElement(Text, { mr: 1 },
205
+ adaptable.api.columnApi.getFriendlyNameForColumnId(pivotColId),
206
+ ":"),
207
+ React.createElement(DropdownButton, { columns: ['label'], items: pivotTotalOptions.map((opt) => ({
208
+ label: opt.label,
209
+ onClick: () => handleTotalChange(pivotColId, opt.value),
210
+ })) }, currentValue)));
211
+ }))))));
93
212
  };
94
- const WEIGHTED_AVERAGE_AGG_FN_NAME = 'weightedAvg';
95
- export const isAggregationsSectionValid = (data) => {
96
- const weightedAvg = data.TableAggregationColumns
97
- ? (data.TableAggregationColumns || [])
213
+ export const isPivotAggregationsSectionValid = (data) => {
214
+ const weightedAvg = data.PivotAggregationColumns
215
+ ? (data.PivotAggregationColumns || [])
98
216
  .map((agg) => agg.AggFunc)
99
217
  .find((agg) => typeof agg === 'object' && agg.type === 'weightedAverage')
100
218
  : null;
@@ -126,7 +244,6 @@ export const PivotAggregationsSection = (props) => {
126
244
  const sortedAggregableColumns = React.useMemo(() => {
127
245
  return ArrayExtensions.sortArrayWithOrder(allAggregableColumns.map((col) => col.columnId), (layout.PivotAggregationColumns ?? []).map((col) => col.ColumnId), { sortUnorderedItems: false }).map((colId) => adaptable.api.columnApi.getColumnWithColumnId(colId));
128
246
  }, [layout, allAggregableColumns]);
129
- globalThis.layout = layout;
130
247
  const handleColumnsSelectionChange = React.useCallback((columnIds) => {
131
248
  const currentAggColumns = layout.PivotAggregationColumns ?? [];
132
249
  const PivotAggregationColumns = columnIds.map((colId) => {
@@ -134,6 +251,7 @@ export const PivotAggregationsSection = (props) => {
134
251
  ColumnId: colId,
135
252
  AggFunc: currentAggColumns.find((x) => x.ColumnId === colId)?.AggFunc ??
136
253
  adaptable.api.columnApi.getDefaultAggFunc(colId),
254
+ TotalColumn: currentAggColumns.find((x) => x.ColumnId === colId)?.TotalColumn,
137
255
  };
138
256
  });
139
257
  props.onChange({
@@ -141,10 +259,14 @@ export const PivotAggregationsSection = (props) => {
141
259
  PivotAggregationColumns,
142
260
  });
143
261
  }, [layout]);
144
- const handleAggregationChange = React.useCallback((PivotAggregationColumns) => {
262
+ const handleAggregationChange = React.useCallback((pivotAggregationColumns) => {
263
+ if (pivotAggregationColumns.some((aggCol) => aggCol.TotalColumn !== false || aggCol.TotalColumn !== null)) {
264
+ // if any Aggregation Column has a Total Column, we need to disable the Pivot Group Total Column
265
+ delete layout['PivotGroupTotalColumn'];
266
+ }
145
267
  props.onChange({
146
268
  ...layout,
147
- PivotAggregationColumns,
269
+ PivotAggregationColumns: pivotAggregationColumns,
148
270
  });
149
271
  }, [layout]);
150
272
  const aggregationColumnsMap = React.useMemo(() => {
@@ -174,12 +296,66 @@ export const PivotAggregationsSection = (props) => {
174
296
  SuppressAggFuncInHeader: checked,
175
297
  });
176
298
  };
299
+ const checkIfPivotGroupTotalColumnEnabled = () => {
300
+ // check that all AggregationColumns have identical AggFuncs
301
+ const aggregationColumns = layout.PivotAggregationColumns;
302
+ if (!aggregationColumns || aggregationColumns.length === 0) {
303
+ return true;
304
+ }
305
+ const firstAggFuncName = getAggFuncName(aggregationColumns[0].AggFunc);
306
+ if (layout.PivotAggregationColumns?.some((aggCol) => getAggFuncName(aggCol.AggFunc) !== firstAggFuncName)) {
307
+ return 'Requires identical aggregation on all columns';
308
+ }
309
+ // check that no Aggregation Total Column is enabled
310
+ const hasAggregationTotalColumn = aggregationColumns.some((aggCol) => aggCol.TotalColumn !== false && aggCol.TotalColumn != null);
311
+ if (hasAggregationTotalColumn) {
312
+ return 'Can only be enabled when no Aggregation Total Column is present';
313
+ }
314
+ return true;
315
+ };
316
+ const isPivotGroupTotalColumnEnabled = checkIfPivotGroupTotalColumnEnabled();
177
317
  return (React.createElement(Tabs, { style: { height: '100%' } },
178
318
  React.createElement(Tabs.Tab, null, "Column Aggregations"),
179
319
  React.createElement(Tabs.Content, null,
180
320
  React.createElement(Flex, null,
181
321
  React.createElement(FormLayout, null,
182
- React.createElement(CheckBox, { checked: layout.SuppressAggFuncInHeader, onChange: handleSuppressAggFuncInHeader }, "Suppress Aggregation Function Text in Column Header"))),
322
+ React.createElement(FormRow, { label: 'Omit Aggregation from Header' },
323
+ React.createElement(CheckBox, { checked: layout.SuppressAggFuncInHeader, onChange: handleSuppressAggFuncInHeader })),
324
+ React.createElement(FormRow, { label: 'Grand Total Row' },
325
+ React.createElement(Select, { style: { width: 120 }, options: ['top', 'bottom'].map((position) => {
326
+ return {
327
+ label: StringExtensions.CapitaliseFirstLetter(position),
328
+ value: position,
329
+ };
330
+ }), placeholder: "Off", value: layout.GrandTotalRow, onChange: (value) => {
331
+ props.onChange({
332
+ ...layout,
333
+ GrandTotalRow: value,
334
+ });
335
+ }, isClearable: true })),
336
+ React.createElement(FormRow, { label: 'Grand Total Column' },
337
+ React.createElement(Select, { style: { width: 120 }, options: ['before', 'after'].map((position) => {
338
+ return {
339
+ label: StringExtensions.CapitaliseFirstLetter(position),
340
+ value: position,
341
+ };
342
+ }), placeholder: "Off", value: layout.GrandTotalColumn, onChange: (value) => {
343
+ props.onChange({
344
+ ...layout,
345
+ GrandTotalColumn: value,
346
+ });
347
+ }, isClearable: true })),
348
+ React.createElement(FormRow, { label: 'Pivot Group Total Column' }, isPivotGroupTotalColumnEnabled === true ? (React.createElement(Select, { style: { width: 120 }, options: ['before', 'after'].map((position) => {
349
+ return {
350
+ label: StringExtensions.CapitaliseFirstLetter(position),
351
+ value: position,
352
+ };
353
+ }), placeholder: "Off", value: layout.PivotGroupTotalColumn, onChange: (value) => {
354
+ props.onChange({
355
+ ...layout,
356
+ PivotGroupTotalColumn: value,
357
+ });
358
+ }, isClearable: true })) : (React.createElement(Text, { marginLeft: 1, style: { fontStyle: 'italic' } }, isPivotGroupTotalColumnEnabled))))),
183
359
  React.createElement(ValueSelector, { showFilterInput: true, showSelectedOnlyPosition: "top", filter: columnFilter, toIdentifier: (option) => `${option.columnId}`, toLabel: (option) => option.friendlyName ?? option.columnId, toListLabel: (column) => (React.createElement(PivotColumnRow, { onChangeAggFunction: handleAggregationChange, layout: layout, column: column, aggregationColumnsMap: aggregationColumnsMap, numberColumns: numberColumns })), options: sortedAggregableColumns, value: (layout.PivotAggregationColumns || []).map((col) => col.ColumnId), allowReorder: true, xSelectedLabel: () => {
184
360
  return `Active aggregations:`;
185
361
  }, onChange: handleColumnsSelectionChange }))));
@@ -28,8 +28,10 @@ const INFINITE_COLUMNS_WITH_CHECKBOX = {
28
28
  },
29
29
  resizable: false,
30
30
  defaultSortable: false,
31
- renderSelectionCheckBox: ({ renderBag }) => {
32
- return renderBag.selectionCheckBox;
31
+ renderSelectionCheckBox: true,
32
+ className: 'ab-Select-CheckboxColumn',
33
+ renderValue: ({ renderBag }) => {
34
+ return React.createElement("div", { className: "InfiniteCell_content_value" }, renderBag.value);
33
35
  },
34
36
  renderHeader: (headerParams) => {
35
37
  return (React.createElement(React.Fragment, null,
@@ -74,8 +76,15 @@ const doesOptionMatchValue = function (value) {
74
76
  };
75
77
  };
76
78
  export const Select = function (props) {
79
+ let maxLabelLength = 0;
77
80
  const ref = React.useRef(null);
78
- const valueToOptionMap = new Map((props.options || []).map((opt) => [opt.value, opt]));
81
+ const valueToOptionMap = new Map((props.options || []).map((opt) => {
82
+ let label = opt.label;
83
+ if (typeof label === 'string' || typeof label === 'number' || typeof label === 'boolean') {
84
+ maxLabelLength = Math.max(maxLabelLength, `${label}`.length);
85
+ }
86
+ return [opt.value, opt];
87
+ }));
79
88
  const findOptionByValue = (value) => {
80
89
  const option = valueToOptionMap.get(value);
81
90
  if (option) {
@@ -416,7 +425,10 @@ export const Select = function (props) {
416
425
  zIndex: 999999,
417
426
  boxShadow: 'var(--ab-cmp-select-menu__box-shadow)',
418
427
  minWidth: `var(--ab-cmp-select-menu__min-width)`,
428
+ width: `${Math.max(maxLabelLength, 10)}ch`,
419
429
  '--ab-cmp-select-menu__min-height': `min(${(props.options || []).length + (showHeaderSelectionCheckbox ? 1 : 0)} * var(--ab-grid-row-height), 20rem)`,
430
+ maxHeight: 'var(--ab-cmp-select-menu__max-height)',
431
+ maxWidth: 'var(--ab-cmp-select-menu__max-width)',
420
432
  ...commonStyles(state),
421
433
  ...props.menuStyle,
422
434
  };
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: 1745430358199 || Date.now(),
4
- VERSION: "20.0.7-canary.1" || '--current-version--',
3
+ PUBLISH_TIMESTAMP: 1745834803008 || Date.now(),
4
+ VERSION: "20.0.7-canary.2" || '--current-version--',
5
5
  };
@@ -72,8 +72,8 @@ export declare class LayoutManager<DATA_TYPE = any> extends LMEmitter {
72
72
  applyPivotTotals(layout: PivotLayoutModel): void;
73
73
  applyPivotExpandLevel(layout: PivotLayoutModel): void;
74
74
  private withSuppressColumnAnimation;
75
+ private patchColDefType;
75
76
  private setupPivotTotals;
76
- private isPivotRowTotalColDef;
77
77
  private patchPivotTotalColumn;
78
78
  private getPivotTotalColumnConfig;
79
79
  }
@@ -6,7 +6,9 @@ import { isLayoutEqual } from './isLayoutEqual';
6
6
  import { simplifyLayoutModel, simplifyPivotLayoutModel, simplifyTableLayoutModel, } from './simplifyLayoutModel';
7
7
  import { sortColumnIdsByOrder } from './sortColumnIdsByOrder';
8
8
  import { destructurePivotColumnId } from './destructurePivotColumnId';
9
- import { isPivotTotalColumn } from './isPivotTotalColumn';
9
+ import { isPivotAggTotalColumn } from './isPivotAggTotalColumn';
10
+ import { isPivotGrandTotalColumn } from './isPivotGrandTotalColumn';
11
+ import { isPivotGroupTotalColumn } from './isPivotGroupTotalColumn';
10
12
  function flattenColDefs(colDefs) {
11
13
  const res = [];
12
14
  const iteration = (c) => {
@@ -1108,8 +1110,28 @@ export class LayoutManager extends LMEmitter {
1108
1110
  }
1109
1111
  return res;
1110
1112
  }
1113
+ patchColDefType(colDef, colTypes) {
1114
+ const originalTypes = colDef.type == undefined ? [] : Array.isArray(colDef.type) ? colDef.type : [colDef.type];
1115
+ const columnTypes = new Set(originalTypes);
1116
+ colTypes.forEach((colType) => {
1117
+ columnTypes.add(colType);
1118
+ });
1119
+ colDef.type = Array.from(columnTypes);
1120
+ }
1111
1121
  setupPivotTotals() {
1112
1122
  const _original_processPivotResultColDef = this.gridApi.getGridOption('processPivotResultColDef');
1123
+ this.gridApi.setGridOption('processPivotResultColDef', (colDef) => {
1124
+ _original_processPivotResultColDef?.(colDef);
1125
+ if (!isPivotLayoutModel(this.currentLayout)) {
1126
+ return;
1127
+ }
1128
+ if (isPivotGrandTotalColumn(colDef)) {
1129
+ this.patchColDefType(colDef, ['pivotTotalColumn', 'pivotGrandTotalColumn']);
1130
+ }
1131
+ if (isPivotGroupTotalColumn(colDef.colId)) {
1132
+ this.patchColDefType(colDef, ['pivotTotalColumn', 'pivotGroupTotalColumn']);
1133
+ }
1134
+ });
1113
1135
  const _original_processPivotResultColGroupDef = this.gridApi.getGridOption('processPivotResultColGroupDef');
1114
1136
  this.gridApi.setGridOption('processPivotResultColGroupDef', (colGroupDef) => {
1115
1137
  _original_processPivotResultColGroupDef?.(colGroupDef);
@@ -1119,9 +1141,6 @@ export class LayoutManager extends LMEmitter {
1119
1141
  this.patchPivotTotalColumn(colGroupDef);
1120
1142
  });
1121
1143
  }
1122
- isPivotRowTotalColDef(colDef) {
1123
- return colDef.colId?.startsWith('PivotRowTotal_');
1124
- }
1125
1144
  patchPivotTotalColumn(colGroupDef) {
1126
1145
  const hasPivotTotalCols = (pivotLayout) => {
1127
1146
  return pivotLayout.PivotAggregationColumns?.some((aggCol) => !!aggCol.TotalColumn);
@@ -1135,7 +1154,7 @@ export class LayoutManager extends LMEmitter {
1135
1154
  const pivotTotalColDefsAfter = [];
1136
1155
  const normalColDefs = [];
1137
1156
  colGroupDef.children.forEach((colDef) => {
1138
- if (this.isPivotRowTotalColDef(colDef)) {
1157
+ if (isPivotGrandTotalColumn(colDef)) {
1139
1158
  if (this.gridApi.getGridOption('pivotRowTotals') === 'after') {
1140
1159
  pivotRowTotalColDefsAfter.push(colDef);
1141
1160
  }
@@ -1144,11 +1163,12 @@ export class LayoutManager extends LMEmitter {
1144
1163
  }
1145
1164
  return;
1146
1165
  }
1147
- if (isPivotTotalColumn(colDef)) {
1166
+ if (isPivotAggTotalColumn(colDef)) {
1148
1167
  if (!colDef.colId.startsWith('pivot_')) {
1149
1168
  this.warn(`Pivot total column ${colDef.colId} is not prefixed with 'pivot_', skipping...`);
1150
1169
  return;
1151
1170
  }
1171
+ this.patchColDefType(colDef, ['pivotTotalColumn', 'pivotAggregationTotalColumn']);
1152
1172
  // we do this for all total cols, but we will hide the ones that are not visible
1153
1173
  colDef.columnGroupShow = undefined;
1154
1174
  const totalColConfig = this.getPivotTotalColumnConfig(colDef, this.currentLayout);
@@ -0,0 +1,2 @@
1
+ import { ColDef } from 'ag-grid-enterprise';
2
+ export declare function isPivotAggTotalColumn(colDef: ColDef): colDef is ColDef;
@@ -1,3 +1,3 @@
1
- export function isPivotTotalColumn(colDef) {
1
+ export function isPivotAggTotalColumn(colDef) {
2
2
  return !!colDef.pivotTotalColumnIds?.length;
3
3
  }
@@ -0,0 +1,2 @@
1
+ import { ColDef, ColGroupDef } from 'ag-grid-enterprise';
2
+ export declare function isPivotGrandTotalColumn(colDef: ColDef | ColGroupDef): boolean;
@@ -0,0 +1,3 @@
1
+ export function isPivotGrandTotalColumn(colDef) {
2
+ return colDef?.colId?.startsWith('PivotRowTotal_pivot_');
3
+ }