@adaptabletools/adaptable 22.0.0 → 22.0.1-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 +1 -1
- package/src/AdaptableInterfaces/IAdaptable.d.ts +1 -0
- package/src/Api/GridApi.d.ts +4 -0
- package/src/Api/Implementation/GridApiImpl.d.ts +1 -0
- package/src/Api/Implementation/GridApiImpl.js +3 -0
- package/src/Api/Implementation/RowFormApiImpl.d.ts +1 -0
- package/src/Api/Implementation/RowFormApiImpl.js +13 -0
- package/src/Api/Internal/ActionColumnInternalApi.js +2 -19
- package/src/Api/Internal/ExportInternalApi.js +1 -1
- package/src/Api/RowFormApi.d.ts +5 -0
- package/src/Strategy/CellSummaryModule.d.ts +1 -0
- package/src/Strategy/CellSummaryModule.js +3 -0
- package/src/Strategy/LayoutModule.js +22 -18
- package/src/Strategy/PlusMinusModule.d.ts +1 -0
- package/src/Strategy/PlusMinusModule.js +8 -2
- package/src/Utilities/only.d.ts +6 -3
- package/src/Utilities/only.js +20 -34
- package/src/Utilities/weightedAverage.d.ts +11 -0
- package/src/Utilities/weightedAverage.js +59 -45
- package/src/agGrid/AdaptableAgGrid.d.ts +1 -0
- package/src/agGrid/AdaptableAgGrid.js +4 -1
- package/src/env.js +2 -2
- package/tsconfig.esm.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaptabletools/adaptable",
|
|
3
|
-
"version": "22.0.0",
|
|
3
|
+
"version": "22.0.1-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",
|
|
@@ -143,6 +143,7 @@ export interface IAdaptable {
|
|
|
143
143
|
refreshCells(rowNode: IRowNode, columns: (string | any)[], forceUpdate: boolean, suppressFlash?: boolean): void;
|
|
144
144
|
refreshAllCells(forceUpdate?: boolean): void;
|
|
145
145
|
refreshColumns(columns: (string | Column)[], forceUpdate: boolean, suppressFlash?: boolean): void;
|
|
146
|
+
refreshGridHeader(): void;
|
|
146
147
|
refreshSelectedCellsState(): SelectedCellInfo | undefined;
|
|
147
148
|
refreshSelectedRowsState(): SelectedRowInfo | undefined;
|
|
148
149
|
selectColumn(columnId: string, config?: {
|
package/src/Api/GridApi.d.ts
CHANGED
|
@@ -537,6 +537,10 @@ export interface GridApi {
|
|
|
537
537
|
* @param rowNodes AG Grid rows
|
|
538
538
|
*/
|
|
539
539
|
refreshRowNodes(rowNodes?: IRowNode[]): void;
|
|
540
|
+
/**
|
|
541
|
+
* Forces a re-render of the Grid Header
|
|
542
|
+
*/
|
|
543
|
+
refreshGridHeader(): void;
|
|
540
544
|
/**
|
|
541
545
|
* Forces a re-render of all Group Rows (including aggregations)
|
|
542
546
|
*/
|
|
@@ -138,6 +138,7 @@ export declare class GridApiImpl extends ApiBase implements GridApi {
|
|
|
138
138
|
refreshRowNode(rowNode: IRowNode): void;
|
|
139
139
|
refreshRowNodes(rowNodes?: IRowNode[]): void;
|
|
140
140
|
refreshGroupRowNodes(): void;
|
|
141
|
+
refreshGridHeader(): void;
|
|
141
142
|
isCellEditable(gridCell: GridCell): boolean;
|
|
142
143
|
isCellEdited(gridCell: GridCell): boolean;
|
|
143
144
|
isEveryCellEditable(gridCells: GridCell[]): boolean;
|
|
@@ -547,6 +547,9 @@ export class GridApiImpl extends ApiBase {
|
|
|
547
547
|
this.getAgGridApi().refreshClientSideRowModel('group');
|
|
548
548
|
this._adaptable.updateRowGroupsAndColumnGroupsExpandedState();
|
|
549
549
|
}
|
|
550
|
+
refreshGridHeader() {
|
|
551
|
+
this._adaptable.refreshGridHeader();
|
|
552
|
+
}
|
|
550
553
|
isCellEditable(gridCell) {
|
|
551
554
|
// If not Grid Cell or Column then return false - GridCell.column may be undefined for cells from synthetic columns created by AG Grid (ex. autoGroup columns)
|
|
552
555
|
if (!gridCell || !gridCell.column || !gridCell.rowNode) {
|
|
@@ -44,4 +44,17 @@ export class RowFormApiImpl extends ApiBase {
|
|
|
44
44
|
},
|
|
45
45
|
}));
|
|
46
46
|
}
|
|
47
|
+
displayDeleteRowForm(primaryKey) {
|
|
48
|
+
const rowNode = this.getGridApi().getRowNodeForPrimaryKey(primaryKey);
|
|
49
|
+
if (!rowNode) {
|
|
50
|
+
this.logWarn(`Can NOT delete row: rowNode not found for primaryKey ${primaryKey}`);
|
|
51
|
+
}
|
|
52
|
+
const eventInfo = {
|
|
53
|
+
type: 'rowDeleted',
|
|
54
|
+
rowNode: rowNode,
|
|
55
|
+
...this.getAdaptableInternalApi().buildBaseContext(),
|
|
56
|
+
};
|
|
57
|
+
this.getEventApi().internalApi.fireRowFormSubmittedEvent(eventInfo);
|
|
58
|
+
this.getRowFormOptions().onRowFormSubmit?.(eventInfo);
|
|
59
|
+
}
|
|
47
60
|
}
|
|
@@ -109,27 +109,10 @@ export class ActionColumnInternalApi extends ApiBase {
|
|
|
109
109
|
break;
|
|
110
110
|
case 'delete':
|
|
111
111
|
button.onClick = (button, context) => {
|
|
112
|
-
|
|
113
|
-
type: 'rowDeleted',
|
|
114
|
-
rowNode: context.rowNode,
|
|
115
|
-
...this.getAdaptableInternalApi().buildBaseContext(),
|
|
116
|
-
};
|
|
117
|
-
this.getEventApi().internalApi.fireRowFormSubmittedEvent(eventInfo);
|
|
118
|
-
this.getRowFormOptions().onRowFormSubmit?.(eventInfo);
|
|
112
|
+
this.getRowFormApi().displayDeleteRowForm(context.primaryKeyValue);
|
|
119
113
|
};
|
|
120
114
|
button.tooltip = button.tooltip ? button.tooltip : 'Delete Row';
|
|
121
|
-
button.icon = button.icon ?? {
|
|
122
|
-
name: 'delete',
|
|
123
|
-
};
|
|
124
|
-
break;
|
|
125
|
-
case 'edit':
|
|
126
|
-
button.onClick = (button, context) => {
|
|
127
|
-
this.getRowFormApi().displayEditRowForm(context.primaryKeyValue);
|
|
128
|
-
};
|
|
129
|
-
button.tooltip = button.tooltip ? button.tooltip : 'Edit Row';
|
|
130
|
-
button.icon = button.icon ?? {
|
|
131
|
-
name: 'edit',
|
|
132
|
-
};
|
|
115
|
+
button.icon = button.icon ?? { name: 'delete' };
|
|
133
116
|
break;
|
|
134
117
|
}
|
|
135
118
|
}
|
|
@@ -41,7 +41,7 @@ export class ExportInternalApi extends ApiBase {
|
|
|
41
41
|
}
|
|
42
42
|
break;
|
|
43
43
|
case 'VisibleColumns':
|
|
44
|
-
// hope that
|
|
44
|
+
// hope that visible column property is updated whenever the layout changes... (need to check!)
|
|
45
45
|
if (!cellDataChangedInfo.column.visible) {
|
|
46
46
|
return false;
|
|
47
47
|
}
|
package/src/Api/RowFormApi.d.ts
CHANGED
|
@@ -16,4 +16,9 @@ export interface RowFormApi {
|
|
|
16
16
|
* @param primaryKey - Primary Key of the duplicated row
|
|
17
17
|
*/
|
|
18
18
|
displayCloneRowForm(primaryKey?: any): void;
|
|
19
|
+
/**
|
|
20
|
+
* Deletes row from grid (with event fired) - note: no visible Row Form is displayed
|
|
21
|
+
* @param primaryKey - Primary Key of the deleted row
|
|
22
|
+
*/
|
|
23
|
+
displayDeleteRowForm(primaryKey?: any): void;
|
|
19
24
|
}
|
|
@@ -18,6 +18,7 @@ export type WeightedAverageConfig = {
|
|
|
18
18
|
export declare class CellSummaryModule extends AdaptableModuleBase implements ICellSummaryModule {
|
|
19
19
|
cachedCellSummary: WeakMap<SelectedCellInfo<any>, CellSummmaryInfo>;
|
|
20
20
|
constructor(api: AdaptableApi);
|
|
21
|
+
isModuleAvailable(): boolean;
|
|
21
22
|
getViewAccessLevel(): AccessLevel;
|
|
22
23
|
createColumnMenuItems(column: AdaptableColumn): import("../Utilities/MenuItem").MenuItemShowPopup<"separator" | "calculated-column-edit" | "cell-summary-show" | "chart-show" | "column-group" | "column-filter-group" | "column-filter-bar-hide" | "column-filter-bar-show" | "column-filter-clear" | "column-filter-suspend" | "column-filter-unsuspend" | "column-info-show" | "custom-sort-add" | "custom-sort-edit" | "dashboard-group" | "dashboard-collapse" | "dashboard-configure" | "dashboard-dock" | "dashboard-expand" | "dashboard-float" | "dashboard-hide" | "dashboard-show" | "data-import" | "flashing-cell-add" | "flashing-cell-delete" | "format-column-add" | "format-column-edit" | "free-text-column-edit" | "grid-group" | "grid-info-show" | "layout-column-caption-change" | "layout-column-hide" | "layout-edit" | "layout-column-select" | "layout-column-select-preserve" | "layout-column-select-reset" | "layout-grid-select" | "plus-minus-add" | "settings-panel-open" | "styling-group" | "styled-column-badge-add" | "styled-column-badge-edit" | "styled-column-gradient-add" | "styled-column-gradient-edit" | "styled-column-percent-bar-add" | "styled-column-percent-bar-edit" | "styled-column-sparkline-add" | "styled-column-sparkline-edit" | "system-status-show" | "_navbar">[];
|
|
23
24
|
createContextMenuItems(menuContext: ContextMenuContext): import("../Utilities/MenuItem").MenuItemShowPopup<"calculated-column-edit" | "cell-summary-show" | "column-group" | "column-filter-group" | "column-filter-clear" | "column-filter-suspend" | "column-filter-unsuspend" | "column-info-show" | "dashboard-group" | "dashboard-collapse" | "dashboard-configure" | "dashboard-dock" | "dashboard-expand" | "dashboard-float" | "dashboard-hide" | "dashboard-show" | "data-import" | "grid-group" | "grid-info-show" | "layout-edit" | "settings-panel-open" | "system-status-show" | "menu-group" | "alert-clear" | "bulk-update-apply" | "column-filter-on-cell-value" | "comment-add" | "comment-remove" | "edit-group" | "export-group" | "export-all-data" | "export-all-data-excel-download" | "export-all-data-visualexcel-download" | "export-all-data-csv" | "export-all-data-csv-download" | "export-all-data-csv-clipboard" | "export-all-data-json" | "export-all-data-json-download" | "export-all-data-json-clipboard" | "export-current-layout" | "export-current-layout-excel-download" | "export-current-layout-visualexcel-download" | "export-current-layout-csv" | "export-current-layout-csv-download" | "export-current-layout-csv-clipboard" | "export-current-layout-json" | "export-current-layout-json-download" | "export-current-layout-json-clipboard" | "export-selected-data" | "export-selected-data-excel-download" | "export-selected-data-visualexcel-download" | "export-selected-data-csv" | "export-selected-data-csv-download" | "export-selected-data-csv-clipboard" | "export-selected-data-json" | "export-selected-data-json-download" | "export-selected-data-json-clipboard" | "fdc3-broadcast" | "fdc3-raise-intent" | "flashing-cell-clear" | "flashing-row-clear" | "layout-aggregated-view" | "layout-auto-size" | "layout-clear-selection" | "layout-select-all" | "note-add" | "note-remove" | "smart-edit-apply">[];
|
|
@@ -12,6 +12,9 @@ export class CellSummaryModule extends AdaptableModuleBase {
|
|
|
12
12
|
constructor(api) {
|
|
13
13
|
super(ModuleConstants.CellSummaryModuleId, ModuleConstants.CellSummaryFriendlyName, 'cells', 'CellSummaryPopup', 'See summary information on a group of numeric cells using multiple summary operations', api);
|
|
14
14
|
}
|
|
15
|
+
isModuleAvailable() {
|
|
16
|
+
return super.isModuleAvailable() && this.api.gridApi.isGridRangeSelectable();
|
|
17
|
+
}
|
|
15
18
|
getViewAccessLevel() {
|
|
16
19
|
return 'Full';
|
|
17
20
|
}
|
|
@@ -143,24 +143,26 @@ export class LayoutModule extends AdaptableModuleBase {
|
|
|
143
143
|
this.api.columnApi.hideColumn(column.columnId);
|
|
144
144
|
}));
|
|
145
145
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
this.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
this.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this.
|
|
146
|
+
if (this.api.gridApi.isGridRangeSelectable()) {
|
|
147
|
+
const hasExistingSelection = this.api.gridApi.getSelectedCellInfo()?.gridCells?.length;
|
|
148
|
+
if (hasExistingSelection) {
|
|
149
|
+
returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-column-select-preserve', 'Select Column (Preserve Selection)', 'select-fwd', () => {
|
|
150
|
+
this.api.columnApi.addColumnToSelection(column.columnId);
|
|
151
|
+
}));
|
|
152
|
+
returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-column-select-reset', 'Select Column (Reset Selection)', 'tab-unselected', () => {
|
|
153
|
+
this.api.columnApi.selectColumn(column.columnId);
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-column-select', 'Select Column', 'tab-unselected', () => {
|
|
158
|
+
this.api.columnApi.selectColumn(column.columnId);
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-grid-select', 'Select Grid', 'select-all', () => {
|
|
162
|
+
this.api.gridApi.selectAll();
|
|
158
163
|
}));
|
|
159
164
|
}
|
|
160
165
|
}
|
|
161
|
-
returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-grid-select', 'Select Grid', 'select-all', () => {
|
|
162
|
-
this.api.gridApi.selectAll();
|
|
163
|
-
}));
|
|
164
166
|
return returnColumnMenuItems;
|
|
165
167
|
}
|
|
166
168
|
createContextMenuItems(menuContext) {
|
|
@@ -179,9 +181,11 @@ export class LayoutModule extends AdaptableModuleBase {
|
|
|
179
181
|
this.api.gridApi.deselectAll();
|
|
180
182
|
}));
|
|
181
183
|
}
|
|
182
|
-
|
|
183
|
-
this.
|
|
184
|
-
|
|
184
|
+
if (this.api.gridApi.isGridRangeSelectable()) {
|
|
185
|
+
returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-select-all', 'Select Grid', 'select-all', () => {
|
|
186
|
+
this.api.gridApi.selectAll();
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
185
189
|
returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-auto-size', 'Auto Size', 'arrow-expand', () => {
|
|
186
190
|
this.api.columnApi.autosizeAllColumns();
|
|
187
191
|
}));
|
|
@@ -12,6 +12,7 @@ export declare class PlusMinusModule extends AdaptableModuleBase implements IPlu
|
|
|
12
12
|
private shouldHandleKeyDown;
|
|
13
13
|
private adaptable;
|
|
14
14
|
constructor(api: AdaptableApi);
|
|
15
|
+
isModuleAvailable(): boolean;
|
|
15
16
|
getModuleAdaptableObjects(config?: LayoutExtendedConfig): AdaptableObject[];
|
|
16
17
|
getExplicitlyReferencedColumnIds(plusMinusNudge: PlusMinusNudge): string[];
|
|
17
18
|
getReferencedNamedQueryNames(plusMinusNudge: PlusMinusNudge): string[];
|
|
@@ -18,6 +18,9 @@ export class PlusMinusModule extends AdaptableModuleBase {
|
|
|
18
18
|
this.shouldHandleKeyDown = false;
|
|
19
19
|
this.adaptable = api.internalApi.getAdaptableInstance();
|
|
20
20
|
}
|
|
21
|
+
isModuleAvailable() {
|
|
22
|
+
return super.isModuleAvailable() && this.api.gridApi.isGridRangeSelectable();
|
|
23
|
+
}
|
|
21
24
|
getModuleAdaptableObjects(config) {
|
|
22
25
|
return this.api.plusMinusApi.getAllPlusMinus(config);
|
|
23
26
|
}
|
|
@@ -36,11 +39,14 @@ export class PlusMinusModule extends AdaptableModuleBase {
|
|
|
36
39
|
return this.api.namedQueryApi.internalApi.getReferencedNamedQueryNames(plusMinusNudge.Rule?.BooleanExpression);
|
|
37
40
|
}
|
|
38
41
|
onAdaptableReady() {
|
|
39
|
-
|
|
40
|
-
this.shouldHandleKeyDown =
|
|
42
|
+
const hasPlusMinusNudges = ArrayExtensions.IsNotNullOrEmpty(this.api.plusMinusApi.getAllPlusMinus());
|
|
43
|
+
this.shouldHandleKeyDown = this.isModuleAvailable() && hasPlusMinusNudges;
|
|
41
44
|
if (this.shouldHandleKeyDown) {
|
|
42
45
|
this.setupKeyDownListener();
|
|
43
46
|
}
|
|
47
|
+
else if (hasPlusMinusNudges && !this.api.gridApi.isGridRangeSelectable()) {
|
|
48
|
+
this.api.consoleWarn('Plus/Minus module is not available because AG Grid is not selectable');
|
|
49
|
+
}
|
|
44
50
|
}
|
|
45
51
|
setupKeyDownListener() {
|
|
46
52
|
this.adaptable._on('KeyDown', (keyDownEvent) => {
|
package/src/Utilities/only.d.ts
CHANGED
|
@@ -8,8 +8,11 @@ interface OnlyAggResult {
|
|
|
8
8
|
* AG Grid aggFunc that returns the column value only when all rows in the group
|
|
9
9
|
* share the same value. Returns null when values differ (or when there are no values).
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* params.values already respects suppressAggFilteredOnly, containing either:
|
|
12
|
+
* - Raw cell values (string | number) for leaf children
|
|
13
|
+
* - OnlyAggResult objects for sub-group children (with pre-computed distinct values)
|
|
14
|
+
*
|
|
15
|
+
* Bails out early as soon as two distinct values are found.
|
|
13
16
|
*/
|
|
14
|
-
export declare const only: (params: IAggFuncParams
|
|
17
|
+
export declare const only: (params: IAggFuncParams) => OnlyAggResult;
|
|
15
18
|
export {};
|
package/src/Utilities/only.js
CHANGED
|
@@ -12,43 +12,29 @@ function createOnlyResult(distinctValues) {
|
|
|
12
12
|
* AG Grid aggFunc that returns the column value only when all rows in the group
|
|
13
13
|
* share the same value. Returns null when values differ (or when there are no values).
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* params.values already respects suppressAggFilteredOnly, containing either:
|
|
16
|
+
* - Raw cell values (string | number) for leaf children
|
|
17
|
+
* - OnlyAggResult objects for sub-group children (with pre-computed distinct values)
|
|
18
|
+
*
|
|
19
|
+
* Bails out early as soon as two distinct values are found.
|
|
17
20
|
*/
|
|
18
|
-
export const only = (params
|
|
19
|
-
const {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const childNodes = (filteredOnly ? groupRowNode.childrenAfterFilter : groupRowNode.childrenAfterGroup) ?? [];
|
|
26
|
-
const distinctValues = new Set();
|
|
27
|
-
for (const rowNode of childNodes) {
|
|
28
|
-
const rawValue = gridApi.getCellValue({ colKey: columnId, rowNode });
|
|
29
|
-
if (typeof rawValue === 'number' || typeof rawValue === 'string') {
|
|
30
|
-
distinctValues.add(rawValue);
|
|
31
|
-
if (distinctValues.size > 1) {
|
|
32
|
-
return createOnlyResult(distinctValues);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
21
|
+
export const only = (params) => {
|
|
22
|
+
const { values } = params;
|
|
23
|
+
const distinctValues = new Set();
|
|
24
|
+
for (let i = 0; i < values.length; i++) {
|
|
25
|
+
const value = values[i];
|
|
26
|
+
if (typeof value === 'number' || typeof value === 'string') {
|
|
27
|
+
distinctValues.add(value);
|
|
35
28
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// `params.values` contains the OnlyAggResult objects they returned.
|
|
41
|
-
// We merge their distinctValues sets instead of re-traversing leaf rows.
|
|
42
|
-
const mergedDistinctValues = new Set();
|
|
43
|
-
for (const childResult of values) {
|
|
44
|
-
if (childResult && typeof childResult === 'object' && 'distinctValues' in childResult) {
|
|
45
|
-
for (const val of childResult.distinctValues) {
|
|
46
|
-
mergedDistinctValues.add(val);
|
|
47
|
-
if (mergedDistinctValues.size > 1) {
|
|
48
|
-
return createOnlyResult(mergedDistinctValues);
|
|
49
|
-
}
|
|
29
|
+
else if (value != null && typeof value === 'object' && 'distinctValues' in value) {
|
|
30
|
+
// sub-group: merge pre-computed distinct values (set has at most 2 elements)
|
|
31
|
+
for (const v of value.distinctValues) {
|
|
32
|
+
distinctValues.add(v);
|
|
50
33
|
}
|
|
51
34
|
}
|
|
35
|
+
if (distinctValues.size > 1) {
|
|
36
|
+
return createOnlyResult(distinctValues);
|
|
37
|
+
}
|
|
52
38
|
}
|
|
53
|
-
return createOnlyResult(
|
|
39
|
+
return createOnlyResult(distinctValues);
|
|
54
40
|
};
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { IAggFuncParams } from 'ag-grid-enterprise';
|
|
2
2
|
export declare const getNumericValue: (input: unknown) => number | null;
|
|
3
|
+
/**
|
|
4
|
+
* Computes a weighted average aggregation: Σ(value × weight) / Σ(weight)
|
|
5
|
+
*
|
|
6
|
+
* AG Grid calls agg functions bottom-up through the group hierarchy. For each group:
|
|
7
|
+
* - Leaf children contribute their raw value × weight
|
|
8
|
+
* - Sub-group children already have partial sums from a previous pass,
|
|
9
|
+
* so we combine those directly instead of re-traversing to leaves
|
|
10
|
+
*
|
|
11
|
+
* The returned object stores partial sums ([columnId] and [weightColumnId])
|
|
12
|
+
* so parent groups can combine sub-group results correctly.
|
|
13
|
+
*/
|
|
3
14
|
export declare const weightedAverage: (params: IAggFuncParams, columnId: string, weightColumnId: string) => {
|
|
4
15
|
[x: string]: number | (() => string) | (() => number);
|
|
5
16
|
toString: () => string;
|
|
@@ -6,55 +6,69 @@ export const getNumericValue = (input) => {
|
|
|
6
6
|
const numericValue = toNumber(input);
|
|
7
7
|
return isNaN(numericValue) ? null : numericValue;
|
|
8
8
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
});
|
|
21
|
-
return leafNodes;
|
|
22
|
-
}
|
|
9
|
+
/**
|
|
10
|
+
* Computes a weighted average aggregation: Σ(value × weight) / Σ(weight)
|
|
11
|
+
*
|
|
12
|
+
* AG Grid calls agg functions bottom-up through the group hierarchy. For each group:
|
|
13
|
+
* - Leaf children contribute their raw value × weight
|
|
14
|
+
* - Sub-group children already have partial sums from a previous pass,
|
|
15
|
+
* so we combine those directly instead of re-traversing to leaves
|
|
16
|
+
*
|
|
17
|
+
* The returned object stores partial sums ([columnId] and [weightColumnId])
|
|
18
|
+
* so parent groups can combine sub-group results correctly.
|
|
19
|
+
*/
|
|
23
20
|
export const weightedAverage = (params, columnId, weightColumnId) => {
|
|
24
|
-
const { api: gridApi, rowNode: groupRowNode } = params;
|
|
25
|
-
|
|
26
|
-
let
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
21
|
+
const { api: gridApi, rowNode: groupRowNode, values } = params;
|
|
22
|
+
// numerator: Σ(value × weight)
|
|
23
|
+
let weightedValueSum = 0;
|
|
24
|
+
// denominator: Σ(weight)
|
|
25
|
+
let totalWeight = 0;
|
|
26
|
+
// params.values already respects suppressAggFilteredOnly.
|
|
27
|
+
// We need the matching child nodes only for leaf rows (to look up weight column values).
|
|
28
|
+
const childNodes = getMatchingChildNodes(groupRowNode, values.length);
|
|
29
|
+
for (let i = 0; i < values.length; i++) {
|
|
30
|
+
const value = values[i];
|
|
31
|
+
if (value != null && typeof value === 'object') {
|
|
32
|
+
// sub-group: partial sums already computed by a previous aggregation pass
|
|
33
|
+
weightedValueSum += value[columnId] ?? 0;
|
|
34
|
+
totalWeight += value[weightColumnId] ?? 0;
|
|
37
35
|
}
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
else {
|
|
37
|
+
// leaf row: compute value × weight from cell data
|
|
38
|
+
const childNode = childNodes[i];
|
|
39
|
+
if (!childNode) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// values might be strings during editing
|
|
43
|
+
const columnValue = getNumericValue(value);
|
|
44
|
+
const weightValue = getNumericValue(gridApi.getCellValue({ colKey: weightColumnId, rowNode: childNode }));
|
|
45
|
+
if (weightValue !== null) {
|
|
46
|
+
totalWeight += weightValue;
|
|
47
|
+
}
|
|
48
|
+
if (columnValue !== null && weightValue !== null) {
|
|
49
|
+
weightedValueSum += columnValue * weightValue;
|
|
50
|
+
}
|
|
40
51
|
}
|
|
41
|
-
});
|
|
42
|
-
let result = columnValueSum / weightedColumnValueSum;
|
|
43
|
-
// 0 / 0 = NaN
|
|
44
|
-
if (isNaN(result)) {
|
|
45
|
-
result = 0;
|
|
46
52
|
}
|
|
53
|
+
const result = totalWeight !== 0 ? weightedValueSum / totalWeight : 0;
|
|
47
54
|
return {
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
toNumber: function () {
|
|
55
|
-
return result;
|
|
56
|
-
},
|
|
57
|
-
[columnId]: columnValueSum,
|
|
58
|
-
[weightColumnId]: weightedColumnValueSum,
|
|
55
|
+
// toString/toNumber let AG Grid's default cell renderer display and sort the value
|
|
56
|
+
toString: () => String(result),
|
|
57
|
+
toNumber: () => result,
|
|
58
|
+
// partial sums stored so parent groups can combine sub-group results
|
|
59
|
+
[columnId]: weightedValueSum,
|
|
60
|
+
[weightColumnId]: totalWeight,
|
|
59
61
|
};
|
|
60
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* Returns the child node list that corresponds to params.values.
|
|
65
|
+
* When suppressAggFilteredOnly is false, params.values comes from childrenAfterFilter.
|
|
66
|
+
* When true, it comes from childrenAfterGroup (all children).
|
|
67
|
+
* We match by length to pick the right list without checking the grid option directly.
|
|
68
|
+
*/
|
|
69
|
+
function getMatchingChildNodes(groupRowNode, valueCount) {
|
|
70
|
+
if (groupRowNode.childrenAfterFilter?.length === valueCount) {
|
|
71
|
+
return groupRowNode.childrenAfterFilter;
|
|
72
|
+
}
|
|
73
|
+
return groupRowNode.childrenAfterGroup ?? [];
|
|
74
|
+
}
|
|
@@ -223,6 +223,7 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
223
223
|
redrawBody(): void;
|
|
224
224
|
refreshHeader(): void;
|
|
225
225
|
redrawRows(rowNodes?: IRowNode[]): void;
|
|
226
|
+
refreshGridHeader(): void;
|
|
226
227
|
redrawRow(rowNode: IRowNode): void;
|
|
227
228
|
refreshCell(rowNode: IRowNode, column: string | any, forceUpdate: boolean, suppressFlash?: boolean): void;
|
|
228
229
|
refreshCells(rowNode: IRowNode, columns: (string | Column)[], forceUpdate: boolean, suppressFlash?: boolean): void;
|
|
@@ -1082,7 +1082,7 @@ export class AdaptableAgGrid {
|
|
|
1082
1082
|
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'aggFuncs', (original_aggFuncs) => {
|
|
1083
1083
|
const aggregationFunctions = original_aggFuncs || {};
|
|
1084
1084
|
aggregationFunctions[ONLY_AGG_FN_NAME] = (params) => {
|
|
1085
|
-
return only(params
|
|
1085
|
+
return only(params);
|
|
1086
1086
|
};
|
|
1087
1087
|
aggregationFunctions[WEIGHTED_AVERAGE_AGG_FN_NAME] = (params) => {
|
|
1088
1088
|
const columnId = params.column.getColId();
|
|
@@ -2260,6 +2260,9 @@ export class AdaptableAgGrid {
|
|
|
2260
2260
|
this.logger.consoleError('AG Grid redrawRows failed to locate some row nodes.', rowNodes, ex);
|
|
2261
2261
|
}
|
|
2262
2262
|
}
|
|
2263
|
+
refreshGridHeader() {
|
|
2264
|
+
this.agGridAdapter.getAgGridApi().refreshHeader();
|
|
2265
|
+
}
|
|
2263
2266
|
redrawRow(rowNode) {
|
|
2264
2267
|
this.redrawRows([rowNode]);
|
|
2265
2268
|
}
|
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:
|
|
4
|
-
VERSION: "22.0.0" || '--current-version--',
|
|
3
|
+
PUBLISH_TIMESTAMP: 1772037233183 || Date.now(),
|
|
4
|
+
VERSION: "22.0.1-canary.0" || '--current-version--',
|
|
5
5
|
};
|