@adaptabletools/adaptable 23.0.22 → 23.1.0-canary.1
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 +3 -2
- package/src/AdaptableInterfaces/IAdaptable.d.ts +37 -1
- package/src/AdaptableOptions/ColumnMenuOptions.d.ts +1 -1
- package/src/AdaptableOptions/ContextMenuOptions.d.ts +1 -1
- package/src/AdaptableOptions/FilterOptions.d.ts +22 -6
- package/src/Api/Internal/FormatColumnInternalApi.d.ts +12 -2
- package/src/Api/Internal/FormatColumnInternalApi.js +4 -0
- package/src/Redux/Store/AdaptableStore.js +20 -6
- package/src/Strategy/LayoutModule.js +4 -1
- package/src/Utilities/Helpers/StyledColumns/SparklineStyleHelper.d.ts +2 -0
- package/src/Utilities/Helpers/StyledColumns/SparklineStyleHelper.js +13 -10
- package/src/Utilities/Hooks/useAdaptableOptions.d.ts +1 -1
- package/src/Utilities/Services/AnnotationsService.js +8 -8
- package/src/View/Components/ColumnFilter/components/FloatingFilterValues.d.ts +3 -9
- package/src/View/Components/ColumnFilter/components/FloatingFilterValues.js +10 -6
- package/src/View/Components/PredicateEditor/PredicateEditor.js +8 -4
- package/src/View/StyledColumn/Wizard/StyledColumnSparklineSettingsSection.js +18 -8
- package/src/View/Wizard/OnePageAdaptableWizard.d.ts +2 -2
- package/src/View/Wizard/OnePageWizards.d.ts +1 -1
- package/src/agGrid/AdaptableAgGrid.d.ts +71 -10
- package/src/agGrid/AdaptableAgGrid.js +125 -88
- package/src/agGrid/AgGridAdapter.d.ts +33 -1
- package/src/agGrid/AgGridAdapter.js +91 -0
- package/src/agGrid/AgGridColumnAdapter.d.ts +68 -1
- package/src/agGrid/AgGridColumnAdapter.js +191 -73
- package/src/agGrid/AgGridMenuAdapter.d.ts +8 -2
- package/src/agGrid/AgGridMenuAdapter.js +17 -4
- package/src/agGrid/AgGridModulesAdapter.js +6 -1
- package/src/agGrid/AgGridThemeAdapter.d.ts +17 -0
- package/src/agGrid/AgGridThemeAdapter.js +37 -6
- package/src/agGrid/gridRefreshScope.d.ts +20 -0
- package/src/agGrid/gridRefreshScope.js +39 -0
- package/src/components/Radio/index.d.ts +2 -2
- package/src/devTools/DevToolsTracks.d.ts +6 -0
- package/src/devTools/DevToolsTracks.js +6 -0
- package/src/devTools/index.d.ts +25 -1
- package/src/env.js +2 -2
- package/src/layout-manager/src/index.d.ts +9 -0
- package/src/layout-manager/src/index.js +38 -17
- package/src/parser/src/types.d.ts +3 -1
- package/src/types.d.ts +1 -1
- package/tsconfig.esm.tsbuildinfo +1 -1
|
@@ -2,10 +2,10 @@ import { AdaptableOptions } from '../AdaptableOptions/AdaptableOptions';
|
|
|
2
2
|
import { ChartRef, Column, GridApi, GridOptions, IRowNode, Module, RowModelType, StatusPanelDef } from 'ag-grid-enterprise';
|
|
3
3
|
import { AdaptableLogger } from './AdaptableLogger';
|
|
4
4
|
import { AdaptableApi, DestroyConfig } from '../Api/AdaptableApi';
|
|
5
|
-
import { AdaptableVariant, IAdaptable, NormalizeAdaptableStateOptions } from '../AdaptableInterfaces/IAdaptable';
|
|
5
|
+
import { AdaptableVariant, GridRefreshScope, IAdaptable, NormalizeAdaptableStateOptions } from '../AdaptableInterfaces/IAdaptable';
|
|
6
6
|
import { EmitterCallback } from '../Utilities/Emitter';
|
|
7
7
|
import { AdaptablePlugin } from '../AdaptableOptions/AdaptablePlugin';
|
|
8
|
-
import { AgGridAdapter } from './AgGridAdapter';
|
|
8
|
+
import { AgGridAdapter, RowNodeEvent } from './AgGridAdapter';
|
|
9
9
|
import { IDataService } from '../Utilities/Services/Interface/IDataService';
|
|
10
10
|
import { AdaptableState } from '../AdaptableState/AdaptableState';
|
|
11
11
|
import { IAdaptableStore } from '../Redux/Store/Interface/IAdaptableStore';
|
|
@@ -54,7 +54,6 @@ interface AdaptableInitInternalConfig<TData = any> {
|
|
|
54
54
|
}
|
|
55
55
|
export declare class AdaptableAgGrid implements IAdaptable {
|
|
56
56
|
logger: AdaptableLogger;
|
|
57
|
-
private _id;
|
|
58
57
|
lifecycleState: AdaptableLifecycleState;
|
|
59
58
|
variant: AdaptableVariant;
|
|
60
59
|
private emitter;
|
|
@@ -94,7 +93,7 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
94
93
|
ThemeService: IThemeService;
|
|
95
94
|
private LicenseService;
|
|
96
95
|
private ChartingService;
|
|
97
|
-
private
|
|
96
|
+
private isListeningToAgGridRowNodeEvents;
|
|
98
97
|
private debouncedSetSelectedRows;
|
|
99
98
|
private debouncedSetSelectedCells;
|
|
100
99
|
private agGridListenerKeydown;
|
|
@@ -131,9 +130,6 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
131
130
|
constructor(config?: {
|
|
132
131
|
getAgGridColumnApiModuleReference?: () => Module;
|
|
133
132
|
});
|
|
134
|
-
static forEachAdaptable(fn: (adaptable: AdaptableAgGrid) => void): void;
|
|
135
|
-
private static collectInstance;
|
|
136
|
-
private static dismissInstance;
|
|
137
133
|
get isAgGridInitialising(): boolean;
|
|
138
134
|
get isReady(): boolean;
|
|
139
135
|
get isAvailable(): boolean;
|
|
@@ -187,6 +183,22 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
187
183
|
* Either initializes the AG Grid instance or delegates it to the framework wrappers (React/Anglar)
|
|
188
184
|
*/
|
|
189
185
|
private initializeAgGrid;
|
|
186
|
+
/**
|
|
187
|
+
* Derives the host element of the grid (the element the framework wrapper / `createGrid()` renders
|
|
188
|
+
* the grid into) when `ContainerOptions.agGridContainer` is not provided.
|
|
189
|
+
*
|
|
190
|
+
* AG Grid 36+ wraps the grid in three grid-owned `div.ag-styled-root` elements which mirror the
|
|
191
|
+
* theme classes (`ag-theme-params-N ...`, or the host's `ag-theme-<name>` in legacy mode);
|
|
192
|
+
* `AgGridAdapter.getAgGridRootElement()` is the innermost one. These wrappers must be skipped:
|
|
193
|
+
* they are re-classed by AG Grid on every theme change, so anything AdapTable adds/removes on them
|
|
194
|
+
* (legacy theme switching) would be lost.
|
|
195
|
+
*
|
|
196
|
+
* Resolution order:
|
|
197
|
+
* 1. the closest non-`.ag-styled-root` ancestor of the grid root (the host element)
|
|
198
|
+
* 2. legacy theme mode only: if the host element has no `ag-theme-*` class, the closest ancestor
|
|
199
|
+
* which has one (AG Grid itself accepts the theme class anywhere up the tree)
|
|
200
|
+
*/
|
|
201
|
+
private deriveAgGridContainerElement;
|
|
190
202
|
useRowNodeLookUp(): boolean;
|
|
191
203
|
private buildInitContainerContext;
|
|
192
204
|
getAgGridContainerElement(): HTMLElement | null;
|
|
@@ -198,6 +210,13 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
198
210
|
private initAdaptableStore;
|
|
199
211
|
private mapAdaptableStateToAgGridState;
|
|
200
212
|
private addGridEventListeners;
|
|
213
|
+
/**
|
|
214
|
+
* see #local_event_service_monkey_patch (AgGridAdapter.ts)
|
|
215
|
+
*
|
|
216
|
+
* Entry point for the AG Grid RowNode `dataChanged` / `cellChanged` events, which AG Grid does not expose publicly.
|
|
217
|
+
* These drive Adaptable's data change detection (CellChanged events, Alerts, Flashing Cells, etc.)
|
|
218
|
+
*/
|
|
219
|
+
onAgGridRowNodeEvent(event: RowNodeEvent): void;
|
|
201
220
|
private shouldAutoSizeLayout;
|
|
202
221
|
private autoSizeLayoutIfNeeded;
|
|
203
222
|
forPlugins(callback: (plugin: AdaptablePlugin) => any): void;
|
|
@@ -228,10 +247,52 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
228
247
|
getDisplayValueFromRawValue(rowNode: IRowNode, columnId: string, rawValue: any): string | undefined;
|
|
229
248
|
private getCleanValue;
|
|
230
249
|
getNormalisedValueFromRawValue(rawValue: any, column: AdaptableColumn): string | number | boolean | Date | unknown;
|
|
231
|
-
|
|
250
|
+
/**
|
|
251
|
+
* The refresh scope already applied by a column-model pass in the current microtask window
|
|
252
|
+
* (`null` when no pass ran yet), see `updateColumnModelAndRefreshGrid`.
|
|
253
|
+
*/
|
|
254
|
+
private __columnModelRefreshDoneInThisTick;
|
|
232
255
|
private __forceUpdateColumnModel;
|
|
233
|
-
|
|
234
|
-
|
|
256
|
+
/**
|
|
257
|
+
* #narrow_column_model_refresh
|
|
258
|
+
*
|
|
259
|
+
* Runs the column-model pass at most once per microtask window: the first call runs it synchronously
|
|
260
|
+
* with the requested refresh scope; a later call in the same window does NOT set up the columns again
|
|
261
|
+
* (the #stable_col_def_callbacks read live state anyway) but still gets any refresh it asks for that
|
|
262
|
+
* the first call did not perform - eg a cells-only pass followed by a request for a row redraw.
|
|
263
|
+
*/
|
|
264
|
+
updateColumnModelAndRefreshGrid(refreshScope?: GridRefreshScope): void;
|
|
265
|
+
/**
|
|
266
|
+
* #column_model_refresh_perf
|
|
267
|
+
*
|
|
268
|
+
* The whole pass and each of its phases are published as DevTools performance tracks
|
|
269
|
+
* (`Runtime` track, see `DevToolsTracks`) when profiling is enabled (`localStorage.adaptableProfileTracks = 'true'`).
|
|
270
|
+
* The `Update column model & refresh grid` entry carries the number of columns set up, the number of
|
|
271
|
+
* colDefs AG Grid actually saw as changed (see `AgGridAdapter.DANGER_getColDefsVersion`) and the refresh
|
|
272
|
+
* scope applied, so a `performance.getEntriesByName()` consumer (eg the `perf/column-model-refresh`
|
|
273
|
+
* Playwright spec) can tell a callback-only pass from one that committed real colDef changes.
|
|
274
|
+
*
|
|
275
|
+
* @param refreshScope see #narrow_column_model_refresh; defaults to a full refresh (rows + header)
|
|
276
|
+
*/
|
|
277
|
+
_updateColumnModelAndRefreshGridNow(refreshScope?: GridRefreshScope): void;
|
|
278
|
+
/**
|
|
279
|
+
* see #narrow_column_model_refresh
|
|
280
|
+
* Applies the given refresh scope; each operation is a DevTools `Runtime` track entry (see #column_model_refresh_perf).
|
|
281
|
+
*/
|
|
282
|
+
private refreshGridAfterColumnModelUpdate;
|
|
283
|
+
/**
|
|
284
|
+
* see #narrow_column_model_refresh
|
|
285
|
+
* The cell-level counterpart of `redrawBody()`: re-runs the colDef callbacks on every rendered cell
|
|
286
|
+
* without destroying the rows, so cell focus, selection and an in-progress edit survive.
|
|
287
|
+
* `cellStyle` results are normalised (see `normalizeStyleForAgGrid`), so a style that no longer applies
|
|
288
|
+
* is cleared even though AG Grid only ever ADDS inline styles on refresh.
|
|
289
|
+
*/
|
|
290
|
+
refreshRenderedCells(): void;
|
|
291
|
+
/**
|
|
292
|
+
* Re-applies the current sort, eg. after a Custom Sort was added/edited/removed at runtime.
|
|
293
|
+
* The column comparators are already up to date (see #stable_col_def_callbacks), AG Grid just has to sort again.
|
|
294
|
+
*/
|
|
295
|
+
refreshSortIfColumnsSorted(): void;
|
|
235
296
|
redrawBody(): void;
|
|
236
297
|
refreshHeader(): void;
|
|
237
298
|
redrawRows(rowNodes?: IRowNode[]): void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { debounce } from '../Utilities/Helpers/TimingHelper';
|
|
2
|
-
import { createGrid,
|
|
2
|
+
import { createGrid, } from 'ag-grid-enterprise';
|
|
3
3
|
import { AdaptableLogger } from './AdaptableLogger';
|
|
4
4
|
import { PrimaryKeyDocsLink } from '../Utilities/Constants/DocumentationLinkConstants';
|
|
5
|
+
import { describeGridRefreshScope, FULL_GRID_REFRESH_SCOPE, getMissingGridRefreshScope, mergeGridRefreshScopes, } from './gridRefreshScope';
|
|
5
6
|
import StringExtensions from '../Utilities/Extensions/StringExtensions';
|
|
6
7
|
import { applyQuickSearchFindCssVars } from '../Utilities/Helpers/QuickSearchHelper';
|
|
7
8
|
import Emitter from '../Utilities/Emitter';
|
|
@@ -110,48 +111,9 @@ import { AgGridFilterAdapterFactory } from './AgGridFilterAdapter';
|
|
|
110
111
|
import { AdaptableFilterHandler } from './AdaptableFilterHandler';
|
|
111
112
|
import { AgGridFloatingFilterAdapterFactory } from './AgGridFloatingFilterAdapter';
|
|
112
113
|
import { listenForDevTools } from '../setupDevTools';
|
|
113
|
-
const LocalEventService_Prototype = LocalEventService.prototype;
|
|
114
|
-
const LocalEventService_dispatchEvent = LocalEventService_Prototype.dispatchEvent;
|
|
115
|
-
LocalEventService_Prototype.dispatchEvent = function (event) {
|
|
116
|
-
const agGridApi = event.api;
|
|
117
|
-
if (agGridApi?.isDestroyed()) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
LocalEventService_dispatchEvent.apply(this, arguments);
|
|
121
|
-
if (event.type === 'cellChanged' || event.type === 'dataChanged') {
|
|
122
|
-
const eventRowNode = event.node;
|
|
123
|
-
if (!eventRowNode) {
|
|
124
|
-
AdaptableLogger.consoleErrorBase(`No RowNode found in passed event, this should never happen!`, event);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
const extractGridApiFromRowNode = (rowNode) => {
|
|
128
|
-
const rowNodeApi = rowNode?.beans?.gridApi;
|
|
129
|
-
if (!rowNodeApi) {
|
|
130
|
-
AdaptableLogger.consoleErrorBase(`No GridAPI found in passed RowNode, this should never happen!`, rowNode);
|
|
131
|
-
}
|
|
132
|
-
return rowNodeApi;
|
|
133
|
-
};
|
|
134
|
-
if (eventRowNode) {
|
|
135
|
-
AdaptableAgGrid.forEachAdaptable((adaptable) => {
|
|
136
|
-
if (extractGridApiFromRowNode(eventRowNode) !== adaptable.agGridAdapter?.getAgGridApi(true)) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (adaptable.isDestroyed) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
const fn = adaptable.rowListeners ? adaptable.rowListeners[event.type] : null;
|
|
143
|
-
if (fn) {
|
|
144
|
-
fn(event);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
const adaptableInstances = {};
|
|
151
114
|
const publishTimestamp = Number(ADAPTABLE_PUBLISH_TIMESTAMP);
|
|
152
115
|
export class AdaptableAgGrid {
|
|
153
116
|
logger;
|
|
154
|
-
_id;
|
|
155
117
|
lifecycleState;
|
|
156
118
|
variant;
|
|
157
119
|
emitter;
|
|
@@ -188,7 +150,7 @@ export class AdaptableAgGrid {
|
|
|
188
150
|
ThemeService;
|
|
189
151
|
LicenseService;
|
|
190
152
|
ChartingService;
|
|
191
|
-
|
|
153
|
+
isListeningToAgGridRowNodeEvents = false;
|
|
192
154
|
debouncedSetSelectedRows;
|
|
193
155
|
debouncedSetSelectedCells;
|
|
194
156
|
agGridListenerKeydown;
|
|
@@ -226,18 +188,6 @@ export class AdaptableAgGrid {
|
|
|
226
188
|
this.agGridModulesAdapter = new AgGridModulesAdapter(this);
|
|
227
189
|
this.DataService = new DataService(this);
|
|
228
190
|
}
|
|
229
|
-
static forEachAdaptable(fn) {
|
|
230
|
-
Object.keys(adaptableInstances).forEach((key) => {
|
|
231
|
-
fn(adaptableInstances[key]);
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
static collectInstance(adaptable, adaptableId) {
|
|
235
|
-
adaptable._id = adaptableId;
|
|
236
|
-
adaptableInstances[adaptable._id] = adaptable;
|
|
237
|
-
}
|
|
238
|
-
static dismissInstance(adaptable) {
|
|
239
|
-
delete adaptableInstances[adaptable._id];
|
|
240
|
-
}
|
|
241
191
|
get isAgGridInitialising() {
|
|
242
192
|
return this.lifecycleState === 'initAgGrid';
|
|
243
193
|
}
|
|
@@ -330,7 +280,6 @@ export class AdaptableAgGrid {
|
|
|
330
280
|
const adaptableId = this._rawAdaptableOptions.adaptableId;
|
|
331
281
|
const initMarker = getMarker(adaptableId).track.Init.label.Init.start();
|
|
332
282
|
const perfInitAdaptableAgGrid = this.logger.beginPerf(`Adaptable._initAdaptableAgGrid()`);
|
|
333
|
-
AdaptableAgGrid.collectInstance(this, this._rawAdaptableOptions.adaptableId);
|
|
334
283
|
this.variant = config.variant;
|
|
335
284
|
this.initWithLazyData =
|
|
336
285
|
config.gridOptions.rowData == undefined || config.gridOptions.rowData.length === 0;
|
|
@@ -669,6 +618,7 @@ export class AdaptableAgGrid {
|
|
|
669
618
|
agGridApi.onFilterChanged();
|
|
670
619
|
filteringApplied = true;
|
|
671
620
|
}
|
|
621
|
+
agGridApi.refreshCells();
|
|
672
622
|
this._emit('AdapTableFiltersApplied');
|
|
673
623
|
return filteringApplied;
|
|
674
624
|
}
|
|
@@ -1055,6 +1005,14 @@ export class AdaptableAgGrid {
|
|
|
1055
1005
|
return result;
|
|
1056
1006
|
};
|
|
1057
1007
|
});
|
|
1008
|
+
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'getColumnMenuItems', (original_getColumnMenuItems) => {
|
|
1009
|
+
return (params) => {
|
|
1010
|
+
if (params.source === 'columnMenu') {
|
|
1011
|
+
return this.agGridMenuAdapter.buildColumnMenu(params, original_getColumnMenuItems);
|
|
1012
|
+
}
|
|
1013
|
+
return this.agGridMenuAdapter.buildColumnsToolPanelMenu(params);
|
|
1014
|
+
};
|
|
1015
|
+
});
|
|
1058
1016
|
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'getMainMenuItems', (original_getMainMenuItems) => {
|
|
1059
1017
|
return (params) => {
|
|
1060
1018
|
return this.agGridMenuAdapter.buildColumnMenu(params, original_getMainMenuItems);
|
|
@@ -1300,8 +1258,7 @@ export class AdaptableAgGrid {
|
|
|
1300
1258
|
this.logger.info('Initializing with lazy data (no initial rowData).');
|
|
1301
1259
|
}
|
|
1302
1260
|
if (!this.getAgGridContainerElement()) {
|
|
1303
|
-
const
|
|
1304
|
-
const gridContainer = gridRoot?.closest('[class*="ag-theme"]');
|
|
1261
|
+
const gridContainer = this.deriveAgGridContainerElement(agGridApi.getGridOption('theme') === 'legacy');
|
|
1305
1262
|
if (!gridContainer) {
|
|
1306
1263
|
this.logger.consoleError('Failed to derive AG Grid container from the framework wrapper. Please provide a valid container element via ContainerOptions.agGridContainer.');
|
|
1307
1264
|
}
|
|
@@ -1321,6 +1278,27 @@ export class AdaptableAgGrid {
|
|
|
1321
1278
|
const agGridApi = createGrid(agGridContainer, gridOptions, gridParams);
|
|
1322
1279
|
return agGridApi;
|
|
1323
1280
|
}
|
|
1281
|
+
deriveAgGridContainerElement(isLegacyTheme) {
|
|
1282
|
+
const gridRoot = this.agGridAdapter.getAgGridRootElement();
|
|
1283
|
+
if (!gridRoot) {
|
|
1284
|
+
return undefined;
|
|
1285
|
+
}
|
|
1286
|
+
let hostElement = gridRoot;
|
|
1287
|
+
while (hostElement && hostElement.classList?.contains('ag-styled-root')) {
|
|
1288
|
+
hostElement = hostElement.parentElement;
|
|
1289
|
+
}
|
|
1290
|
+
if (!hostElement) {
|
|
1291
|
+
return undefined;
|
|
1292
|
+
}
|
|
1293
|
+
const hasAgThemeClass = (element) => Array.from(element.classList ?? []).some((cls) => cls.indexOf('ag-theme-') === 0);
|
|
1294
|
+
if (isLegacyTheme && !hasAgThemeClass(hostElement)) {
|
|
1295
|
+
const themedAncestor = hostElement.parentElement?.closest('[class*="ag-theme-"]');
|
|
1296
|
+
if (themedAncestor && hasAgThemeClass(themedAncestor)) {
|
|
1297
|
+
return themedAncestor;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
return hostElement;
|
|
1301
|
+
}
|
|
1324
1302
|
useRowNodeLookUp() {
|
|
1325
1303
|
return this.agGridAdapter.getAgGridApi().getGridOption('getRowId') != undefined;
|
|
1326
1304
|
}
|
|
@@ -1452,7 +1430,10 @@ export class AdaptableAgGrid {
|
|
|
1452
1430
|
if (this.api.formatColumnApi.getActiveFormatColumns().some((fc) => {
|
|
1453
1431
|
return fc.ColumnGroupScope != null;
|
|
1454
1432
|
})) {
|
|
1455
|
-
this.updateColumnModelAndRefreshGrid(
|
|
1433
|
+
this.updateColumnModelAndRefreshGrid({
|
|
1434
|
+
cells: true,
|
|
1435
|
+
header: this.api.formatColumnApi.internalApi.hasFormatColumnsTargetingHeader(),
|
|
1436
|
+
});
|
|
1456
1437
|
}
|
|
1457
1438
|
}));
|
|
1458
1439
|
this.agGridAdapter.getAgGridApi().addEventListener('columnPivotChanged', (this.listenerPivotChanged = (params) => {
|
|
@@ -1519,25 +1500,23 @@ export class AdaptableAgGrid {
|
|
|
1519
1500
|
};
|
|
1520
1501
|
this.agGridAdapter.getAgGridApi().addGlobalListener(this.listenerGlobalChartingChanges);
|
|
1521
1502
|
}
|
|
1522
|
-
this.
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
}
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
},
|
|
1540
|
-
};
|
|
1503
|
+
this.isListeningToAgGridRowNodeEvents = true;
|
|
1504
|
+
}
|
|
1505
|
+
onAgGridRowNodeEvent(event) {
|
|
1506
|
+
if (!this.isListeningToAgGridRowNodeEvents) {
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
if (event.type === 'dataChanged') {
|
|
1510
|
+
const { node, oldData, newData } = event;
|
|
1511
|
+
this.onRowDataChanged({ rowNode: node, oldData, newData });
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
if (event.type === 'cellChanged') {
|
|
1515
|
+
const { node, column, oldValue, newValue } = event;
|
|
1516
|
+
if (column) {
|
|
1517
|
+
this.onCellDataChanged({ rowNode: node, oldValue, newValue, colId: column.getColId() });
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1541
1520
|
}
|
|
1542
1521
|
shouldAutoSizeLayout() {
|
|
1543
1522
|
const { layoutApi } = this.api;
|
|
@@ -1908,29 +1887,87 @@ export class AdaptableAgGrid {
|
|
|
1908
1887
|
}
|
|
1909
1888
|
return rawValue;
|
|
1910
1889
|
}
|
|
1911
|
-
|
|
1890
|
+
__columnModelRefreshDoneInThisTick = null;
|
|
1912
1891
|
__forceUpdateColumnModel = false;
|
|
1913
|
-
updateColumnModelAndRefreshGrid() {
|
|
1914
|
-
|
|
1892
|
+
updateColumnModelAndRefreshGrid(refreshScope = FULL_GRID_REFRESH_SCOPE) {
|
|
1893
|
+
const alreadyDone = this.__columnModelRefreshDoneInThisTick;
|
|
1894
|
+
if (alreadyDone && !this.__forceUpdateColumnModel) {
|
|
1895
|
+
const missingScope = getMissingGridRefreshScope(alreadyDone, refreshScope);
|
|
1896
|
+
if (missingScope) {
|
|
1897
|
+
this.refreshGridAfterColumnModelUpdate(missingScope);
|
|
1898
|
+
this.__columnModelRefreshDoneInThisTick = mergeGridRefreshScopes(alreadyDone, missingScope);
|
|
1899
|
+
}
|
|
1915
1900
|
return;
|
|
1916
1901
|
}
|
|
1917
1902
|
this.__forceUpdateColumnModel = false;
|
|
1918
1903
|
try {
|
|
1919
|
-
this._updateColumnModelAndRefreshGridNow();
|
|
1920
|
-
this.
|
|
1904
|
+
this._updateColumnModelAndRefreshGridNow(refreshScope);
|
|
1905
|
+
this.__columnModelRefreshDoneInThisTick = alreadyDone
|
|
1906
|
+
? mergeGridRefreshScopes(alreadyDone, refreshScope)
|
|
1907
|
+
: { ...refreshScope };
|
|
1921
1908
|
}
|
|
1922
1909
|
finally {
|
|
1923
1910
|
queueMicrotask(() => {
|
|
1924
|
-
this.
|
|
1911
|
+
this.__columnModelRefreshDoneInThisTick = null;
|
|
1925
1912
|
});
|
|
1926
1913
|
}
|
|
1927
1914
|
}
|
|
1928
|
-
_updateColumnModelAndRefreshGridNow() {
|
|
1929
|
-
|
|
1915
|
+
_updateColumnModelAndRefreshGridNow(refreshScope = FULL_GRID_REFRESH_SCOPE) {
|
|
1916
|
+
const startTime = performance.now();
|
|
1917
|
+
const adaptableId = this.adaptableOptions.adaptableId;
|
|
1918
|
+
const runtimeTrack = () => getMarker(adaptableId).track.Runtime.label;
|
|
1919
|
+
const colDefsVersionBefore = this.agGridAdapter.DANGER_getColDefsVersion();
|
|
1920
|
+
const passMarker = runtimeTrack().UpdateColumnModel.start();
|
|
1921
|
+
const deriveMarker = runtimeTrack().DeriveColumnState.start();
|
|
1930
1922
|
this.deriveAdaptableColumnStateFromAgGrid();
|
|
1923
|
+
deriveMarker.end();
|
|
1924
|
+
const setupColumnsMarker = runtimeTrack().SetupColumns.start();
|
|
1931
1925
|
this.agGridColumnAdapter.setupColumns();
|
|
1932
|
-
|
|
1933
|
-
this.
|
|
1926
|
+
setupColumnsMarker.end();
|
|
1927
|
+
this.refreshGridAfterColumnModelUpdate(refreshScope);
|
|
1928
|
+
const colDefsVersionAfter = this.agGridAdapter.DANGER_getColDefsVersion();
|
|
1929
|
+
const colDefsChanged = colDefsVersionBefore != null && colDefsVersionAfter != null
|
|
1930
|
+
? colDefsVersionAfter - colDefsVersionBefore
|
|
1931
|
+
: -1;
|
|
1932
|
+
const columnCount = this.api.columnApi.getColumns().length;
|
|
1933
|
+
const refreshScopeLabel = describeGridRefreshScope(refreshScope);
|
|
1934
|
+
passMarker.end({
|
|
1935
|
+
details: [
|
|
1936
|
+
{ name: 'columns', value: columnCount },
|
|
1937
|
+
{ name: 'colDefsChanged', value: colDefsChanged },
|
|
1938
|
+
{ name: 'refresh', value: refreshScopeLabel },
|
|
1939
|
+
],
|
|
1940
|
+
});
|
|
1941
|
+
this.logger.info(`Updated column model and refreshed grid in ${Math.round(performance.now() - startTime)}ms (${columnCount} columns, ${colDefsChanged} colDefs changed, refresh: ${refreshScopeLabel}).`);
|
|
1942
|
+
}
|
|
1943
|
+
refreshGridAfterColumnModelUpdate(refreshScope) {
|
|
1944
|
+
const runtimeTrack = getMarker(this.adaptableOptions.adaptableId).track.Runtime.label;
|
|
1945
|
+
if (refreshScope.rows) {
|
|
1946
|
+
const redrawBodyMarker = runtimeTrack.RedrawBody.start();
|
|
1947
|
+
this.redrawBody();
|
|
1948
|
+
redrawBodyMarker.end();
|
|
1949
|
+
}
|
|
1950
|
+
else if (refreshScope.cells) {
|
|
1951
|
+
const refreshCellsMarker = runtimeTrack.RefreshCells.start();
|
|
1952
|
+
this.refreshRenderedCells();
|
|
1953
|
+
refreshCellsMarker.end();
|
|
1954
|
+
}
|
|
1955
|
+
if (refreshScope.header) {
|
|
1956
|
+
const refreshHeaderMarker = runtimeTrack.RefreshHeader.start();
|
|
1957
|
+
this.refreshHeader();
|
|
1958
|
+
refreshHeaderMarker.end();
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
refreshRenderedCells() {
|
|
1962
|
+
this.agGridAdapter.getAgGridApi().refreshCells({ force: true, suppressFlash: true });
|
|
1963
|
+
this.refreshAgGridFindIfNeeded();
|
|
1964
|
+
this._emit('GridRefreshed');
|
|
1965
|
+
}
|
|
1966
|
+
refreshSortIfColumnsSorted() {
|
|
1967
|
+
const columnSorts = this.api.layoutApi.getCurrentLayout()?.ColumnSorts;
|
|
1968
|
+
if (columnSorts?.length) {
|
|
1969
|
+
this.layoutManager.refreshSort();
|
|
1970
|
+
}
|
|
1934
1971
|
}
|
|
1935
1972
|
redrawBody() {
|
|
1936
1973
|
this.redrawRows();
|
|
@@ -3415,6 +3452,7 @@ export class AdaptableAgGrid {
|
|
|
3415
3452
|
'doesExternalFilterPass',
|
|
3416
3453
|
'excelStyles',
|
|
3417
3454
|
'getContextMenuItems',
|
|
3455
|
+
'getColumnMenuItems',
|
|
3418
3456
|
'getMainMenuItems',
|
|
3419
3457
|
'getRowClass',
|
|
3420
3458
|
'getRowId',
|
|
@@ -3458,13 +3496,12 @@ export class AdaptableAgGrid {
|
|
|
3458
3496
|
this.agGridThemeAdapter = null;
|
|
3459
3497
|
this.agGridModulesAdapter?.destroy();
|
|
3460
3498
|
this.agGridModulesAdapter = null;
|
|
3461
|
-
this.
|
|
3499
|
+
this.isListeningToAgGridRowNodeEvents = false;
|
|
3462
3500
|
this.emitter.destroy();
|
|
3463
3501
|
this.emitter = null;
|
|
3464
3502
|
this.adaptableOptions = null;
|
|
3465
3503
|
this.columnMinMaxValuesCache = null;
|
|
3466
3504
|
this.lifecycleState = 'preDestroyed';
|
|
3467
|
-
AdaptableAgGrid.dismissInstance(this);
|
|
3468
3505
|
if (config?.unmount) {
|
|
3469
3506
|
const abContainerElement = this.getAdaptableContainerElement();
|
|
3470
3507
|
if (abContainerElement != null) {
|
|
@@ -1,9 +1,34 @@
|
|
|
1
|
-
import { ColDef, ColGroupDef, Column, GridApi, GridOptions, IRowNode, ManagedGridOptionKey, ManagedGridOptions, Module } from 'ag-grid-enterprise';
|
|
1
|
+
import { AgEvent, ColDef, ColGroupDef, Column, GridApi, GridOptions, IRowNode, ManagedGridOptionKey, ManagedGridOptions, Module } from 'ag-grid-enterprise';
|
|
2
2
|
import type { AgChartInstance, AgSparklineOptions } from 'ag-charts-types';
|
|
3
3
|
import { AdaptableAgGrid } from './AdaptableAgGrid';
|
|
4
4
|
import { AdaptableColumn, AdaptableColumnGroup } from '../AdaptableState/Common/AdaptableColumn';
|
|
5
5
|
import { SelectedCellInfo } from '../AdaptableState/Selection/SelectedCellInfo';
|
|
6
6
|
import { SelectedRowInfo } from '../AdaptableState/Selection/SelectedRowInfo';
|
|
7
|
+
/**
|
|
8
|
+
* #local_event_service_monkey_patch
|
|
9
|
+
*
|
|
10
|
+
* AG Grid does not expose the RowNode `cellChanged` and `dataChanged` events (they are dispatched only on the
|
|
11
|
+
* RowNode's own, lazily created, `LocalEventService`), so we override `LocalEventService.prototype.dispatchEvent`
|
|
12
|
+
* and hook our own data change detection into it.
|
|
13
|
+
*
|
|
14
|
+
* Since AG Grid v36, `LocalEventService` lives in the `ag-stack` package (not in `ag-grid-community`).
|
|
15
|
+
* Unlike a duplicated `ag-grid-community`, a duplicated `ag-stack` copy in a consumer bundle
|
|
16
|
+
* (different install location, CJS vs ESM, version skew) is SILENT - AG Grid keeps working,
|
|
17
|
+
* but a prototype patched via `import { LocalEventService } from 'ag-stack'` would never be hit
|
|
18
|
+
* by the grid, because the grid instantiates the class from ITS copy of the module.
|
|
19
|
+
*
|
|
20
|
+
* Because of this we don't patch the statically imported class; instead we patch the prototype
|
|
21
|
+
* of the `LocalEventService` instance actually used by the running grid (`beans.eventSvc.globalSvc`)
|
|
22
|
+
* - one patch per distinct prototype, regardless of how many copies of `ag-stack` are loaded.
|
|
23
|
+
*
|
|
24
|
+
* The patched prototype is shared by ALL grids (and all their RowNodes), so the patch identifies the
|
|
25
|
+
* originating grid via `rowNode.beans` and routes the event to that grid's AgGridAdapter
|
|
26
|
+
* (see DANGER_AG_GRID_ADAPTERS_MAP & AgGridAdapter.handleRowNodeEvent).
|
|
27
|
+
*/
|
|
28
|
+
export type RowNodeEventType = 'dataChanged' | 'cellChanged';
|
|
29
|
+
export interface RowNodeEvent extends AgEvent<RowNodeEventType> {
|
|
30
|
+
node: IRowNode;
|
|
31
|
+
}
|
|
7
32
|
export type AgGridThemeMode = 'legacy' | 'themingApi';
|
|
8
33
|
export declare class AgGridAdapter {
|
|
9
34
|
private _adaptableInstance;
|
|
@@ -26,6 +51,11 @@ export declare class AgGridAdapter {
|
|
|
26
51
|
private getActivePivotColumnFilters;
|
|
27
52
|
private get agGridOptionsService();
|
|
28
53
|
setAgGridId(agGridId: string): void;
|
|
54
|
+
/**
|
|
55
|
+
* see #local_event_service_monkey_patch
|
|
56
|
+
* Called (for the grid managed by this adapter) whenever AG Grid dispatches a RowNode `cellChanged` / `dataChanged` event
|
|
57
|
+
*/
|
|
58
|
+
handleRowNodeEvent(event: RowNodeEvent): void;
|
|
29
59
|
setAgGridApi(gridApi: GridApi): void;
|
|
30
60
|
getAgGridApi(skipLogging?: boolean): GridApi | undefined;
|
|
31
61
|
monkeyPatchingGridOptionsUpdates(): void;
|
|
@@ -34,6 +64,8 @@ export declare class AgGridAdapter {
|
|
|
34
64
|
private DANGER_getPrivateAgGridBeans;
|
|
35
65
|
DANGER_getCreateSparkline(): ((options: AgSparklineOptions) => AgChartInstance<AgSparklineOptions>) | undefined;
|
|
36
66
|
DANGER_getLiveGridOptions(): GridOptions<any>;
|
|
67
|
+
DANGER_getColDefsVersion(): number | undefined;
|
|
68
|
+
DANGER_invalidateSortCache(): void;
|
|
37
69
|
getAgGridRootElement(): HTMLElement;
|
|
38
70
|
/**
|
|
39
71
|
* When AG Grid is rendered the first time, the AG GridApi is not yet set in the Adaptable context (as it's set only AFTER the grid is fully initialised)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ColumnApiModule, } from 'ag-grid-enterprise';
|
|
2
|
+
import { AdaptableLogger } from './AdaptableLogger';
|
|
2
3
|
import { ACTION_COLUMN_TYPE, CALCULATED_COLUMN_TYPE, FDC3_COLUMN_TYPE, FREE_TEXT_COLUMN_TYPE, } from '../AdaptableState/Common/AdaptableColumn';
|
|
3
4
|
import { ACCESS_LEVEL_HIDDEN, ADAPTABLE_FDC3_ACTION_COLUMN_FRIENDLY_NAME, } from '../Utilities/Constants/GeneralConstants';
|
|
4
5
|
import { createUuid } from '../AdaptableState/Uuid';
|
|
@@ -10,7 +11,84 @@ import { isPivotColumnTotal } from '../layout-manager/src/isPivotColumnTotal';
|
|
|
10
11
|
import { isPivotAggTotalColumn } from '../layout-manager/src/isPivotAggTotalColumn';
|
|
11
12
|
import { ONLY_AGG_FN_NAME, WEIGHTED_AVERAGE_AGG_FN_NAME, } from '../AdaptableState/Common/AggregationColumns';
|
|
12
13
|
const DANGER_AG_GRID_BEANS_MAP = {};
|
|
14
|
+
const DANGER_AG_GRID_ADAPTERS_MAP = {};
|
|
13
15
|
const getColumnApiModule = () => ColumnApiModule;
|
|
16
|
+
const PATCHED_LOCAL_EVENT_SERVICE_PROTOTYPES = new WeakSet();
|
|
17
|
+
const patchLocalEventServiceDispatchEvent = (beans) => {
|
|
18
|
+
const localEventServiceInstance = beans?.eventSvc?.globalSvc;
|
|
19
|
+
const LocalEventService_Prototype = localEventServiceInstance
|
|
20
|
+
? Object.getPrototypeOf(localEventServiceInstance)
|
|
21
|
+
: null;
|
|
22
|
+
if (!LocalEventService_Prototype ||
|
|
23
|
+
typeof LocalEventService_Prototype.dispatchEvent !== 'function') {
|
|
24
|
+
AdaptableLogger.consoleErrorBase(`CRITICAL: could not get hold of AG Grid LocalEventService, data change detection will NOT work!`, beans);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (PATCHED_LOCAL_EVENT_SERVICE_PROTOTYPES.has(LocalEventService_Prototype)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
PATCHED_LOCAL_EVENT_SERVICE_PROTOTYPES.add(LocalEventService_Prototype);
|
|
31
|
+
const LocalEventService_dispatchEvent = LocalEventService_Prototype.dispatchEvent;
|
|
32
|
+
LocalEventService_Prototype.dispatchEvent = function (event) {
|
|
33
|
+
LocalEventService_dispatchEvent.apply(this, arguments);
|
|
34
|
+
if (event.type !== 'cellChanged' && event.type !== 'dataChanged') {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const rowNodeEvent = event;
|
|
38
|
+
const rowNode = rowNodeEvent.node;
|
|
39
|
+
if (!rowNode) {
|
|
40
|
+
AdaptableLogger.consoleErrorBase(`No RowNode found in passed event, this should never happen!`, event);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const gridId = rowNode.beans?.context?.getId();
|
|
44
|
+
if (!gridId) {
|
|
45
|
+
AdaptableLogger.consoleErrorBase(`No gridId found in passed RowNode, this should never happen!`, rowNode);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
DANGER_AG_GRID_ADAPTERS_MAP[gridId]?.handleRowNodeEvent(rowNodeEvent);
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const patchVisibleColsPartition = (beans) => {
|
|
52
|
+
const visibleCols = beans?.visibleCols;
|
|
53
|
+
if (!visibleCols || typeof visibleCols.partitionVisibleCols !== 'function') {
|
|
54
|
+
console.error(`CRITICAL: could not get hold of AG Grid VisibleColsService.partitionVisibleCols, the selection column may NOT be displayed when it is the last column!`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const original_partitionVisibleCols = visibleCols.partitionVisibleCols;
|
|
58
|
+
visibleCols.partitionVisibleCols = function () {
|
|
59
|
+
const result = original_partitionVisibleCols.apply(this, arguments);
|
|
60
|
+
const leftCols = result?.leftCols ?? [];
|
|
61
|
+
const rightCols = result?.rightCols ?? [];
|
|
62
|
+
const centerCols = result?.centerCols ?? [];
|
|
63
|
+
if (leftCols.length + rightCols.length + centerCols.length === 0) {
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
const colModel = beans.colModel;
|
|
67
|
+
const selectionCol = colModel?.colsList?.find((col) => col?.colKind === 'selection');
|
|
68
|
+
if (!selectionCol || !selectionCol.visible) {
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
if (leftCols.includes(selectionCol) ||
|
|
72
|
+
rightCols.includes(selectionCol) ||
|
|
73
|
+
centerCols.includes(selectionCol)) {
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
const showAutoGroupAndValuesOnly = colModel.pivotMode && !colModel.showingPivotResult;
|
|
77
|
+
if (showAutoGroupAndValuesOnly && !(beans.selectionColSvc?.isEnabled?.() ?? false)) {
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
if (selectionCol.pinned === 'right') {
|
|
81
|
+
rightCols.push(selectionCol);
|
|
82
|
+
}
|
|
83
|
+
else if (selectionCol.pinned) {
|
|
84
|
+
leftCols.push(selectionCol);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
centerCols.push(selectionCol);
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
14
92
|
export class AgGridAdapter {
|
|
15
93
|
_adaptableInstance;
|
|
16
94
|
DANGER_USE_GETTER_gridApi;
|
|
@@ -38,11 +116,14 @@ export class AgGridAdapter {
|
|
|
38
116
|
console.error('CRITICAL: No gridId found in beans, this should never happen!');
|
|
39
117
|
}
|
|
40
118
|
DANGER_AG_GRID_BEANS_MAP[gridId] = beans;
|
|
119
|
+
patchLocalEventServiceDispatchEvent(beans);
|
|
120
|
+
patchVisibleColsPartition(beans);
|
|
41
121
|
};
|
|
42
122
|
}
|
|
43
123
|
}
|
|
44
124
|
destroy() {
|
|
45
125
|
delete DANGER_AG_GRID_BEANS_MAP[this._agGridId];
|
|
126
|
+
delete DANGER_AG_GRID_ADAPTERS_MAP[this._agGridId];
|
|
46
127
|
this.initialGridOptions = null;
|
|
47
128
|
this.DANGER_gridApi_from_args = null;
|
|
48
129
|
this.DANGER_USE_GETTER_gridApi = null;
|
|
@@ -86,6 +167,10 @@ export class AgGridAdapter {
|
|
|
86
167
|
}
|
|
87
168
|
setAgGridId(agGridId) {
|
|
88
169
|
this._agGridId = agGridId;
|
|
170
|
+
DANGER_AG_GRID_ADAPTERS_MAP[agGridId] = this;
|
|
171
|
+
}
|
|
172
|
+
handleRowNodeEvent(event) {
|
|
173
|
+
this._adaptableInstance?.onAgGridRowNodeEvent(event);
|
|
89
174
|
}
|
|
90
175
|
setAgGridApi(gridApi) {
|
|
91
176
|
this.DANGER_USE_GETTER_gridApi = gridApi;
|
|
@@ -223,6 +308,12 @@ export class AgGridAdapter {
|
|
|
223
308
|
DANGER_getLiveGridOptions() {
|
|
224
309
|
return this.DANGER_getPrivateAgGridBeans()?.gridOptions;
|
|
225
310
|
}
|
|
311
|
+
DANGER_getColDefsVersion() {
|
|
312
|
+
return this.DANGER_getPrivateAgGridBeans()?.colModel?.colDefsVersion;
|
|
313
|
+
}
|
|
314
|
+
DANGER_invalidateSortCache() {
|
|
315
|
+
this.DANGER_getPrivateAgGridBeans()?.sortSvc?.invalidate();
|
|
316
|
+
}
|
|
226
317
|
getAgGridRootElement() {
|
|
227
318
|
return this.DANGER_getPrivateAgGridBeans()?.eGridDiv;
|
|
228
319
|
}
|