@gooddata/sdk-ui-pivot 11.52.0-alpha.4 → 11.52.0-alpha.6
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/esm/CorePivotTable.d.ts +8 -146
- package/esm/CorePivotTable.d.ts.map +1 -1
- package/esm/CorePivotTable.js +658 -494
- package/esm/index.d.ts +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/next/context/PivotTablePropsContext.d.ts +2 -3
- package/esm/next/context/PivotTablePropsContext.d.ts.map +1 -1
- package/esm/next/index.d.ts +1 -1
- package/esm/next/index.d.ts.map +1 -1
- package/esm/next/types/conditionalFormatting.d.ts +14 -0
- package/esm/next/types/conditionalFormatting.d.ts.map +1 -1
- package/esm/next/types/public.d.ts +4 -4
- package/esm/sdk-ui-pivot.d.ts +18 -4
- package/package.json +13 -13
package/esm/CorePivotTable.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2007-2026 GoodData Corporation
|
|
3
|
-
import {
|
|
3
|
+
import { useCallback, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
4
4
|
import { AllCommunityModule, ModuleRegistry, provideGlobalGridOptions, } from "ag-grid-community";
|
|
5
5
|
import { AgGridReact } from "ag-grid-react";
|
|
6
6
|
import cx from "classnames";
|
|
@@ -36,7 +36,38 @@ ModuleRegistry.registerModules([AllCommunityModule]);
|
|
|
36
36
|
// Mark all grids as using legacy themes
|
|
37
37
|
provideGlobalGridOptions({ theme: "legacy" });
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Applies the table default props. This is the functional component equivalent of the `defaultProps` static
|
|
40
|
+
* that this component used to have while it was implemented as a class component.
|
|
41
|
+
*/
|
|
42
|
+
function resolveDefaultProps(props) {
|
|
43
|
+
return {
|
|
44
|
+
...props,
|
|
45
|
+
locale: props.locale ?? PIVOT_TABLE_DEFAULT_PROPS.locale,
|
|
46
|
+
drillableItems: props.drillableItems ?? PIVOT_TABLE_DEFAULT_PROPS.drillableItems,
|
|
47
|
+
afterRender: props.afterRender ?? PIVOT_TABLE_DEFAULT_PROPS.afterRender,
|
|
48
|
+
pushData: props.pushData ?? PIVOT_TABLE_DEFAULT_PROPS.pushData,
|
|
49
|
+
onExportReady: props.onExportReady ?? PIVOT_TABLE_DEFAULT_PROPS.onExportReady,
|
|
50
|
+
onLoadingChanged: props.onLoadingChanged ?? PIVOT_TABLE_DEFAULT_PROPS.onLoadingChanged,
|
|
51
|
+
onError: props.onError ?? PIVOT_TABLE_DEFAULT_PROPS.onError,
|
|
52
|
+
onDataView: props.onDataView ?? PIVOT_TABLE_DEFAULT_PROPS.onDataView,
|
|
53
|
+
onDrill: props.onDrill ?? PIVOT_TABLE_DEFAULT_PROPS.onDrill,
|
|
54
|
+
ErrorComponent: props.ErrorComponent ?? PIVOT_TABLE_DEFAULT_PROPS.ErrorComponent,
|
|
55
|
+
LoadingComponent: props.LoadingComponent ?? PIVOT_TABLE_DEFAULT_PROPS.LoadingComponent,
|
|
56
|
+
pageSize: props.pageSize ?? PIVOT_TABLE_DEFAULT_PROPS.pageSize,
|
|
57
|
+
config: props.config ?? PIVOT_TABLE_DEFAULT_PROPS.config,
|
|
58
|
+
onColumnResized: props.onColumnResized ?? PIVOT_TABLE_DEFAULT_PROPS.onColumnResized,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function stopEventWhenResizeHeader(e) {
|
|
62
|
+
// Do not propagate event when it originates from the table resizer.
|
|
63
|
+
// This means for example that we can resize columns without triggering drag in the application.
|
|
64
|
+
if (e.target?.className?.includes?.("ag-header-cell-resize")) {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
e.stopPropagation();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* This component implements pivot table using the community version of ag-grid.
|
|
40
71
|
*
|
|
41
72
|
* Bear in mind that this is not a typical, standard React component implementation; the main reason
|
|
42
73
|
* behind that is that while ag-grid comes with a React component the ag-grid itself is not a React component
|
|
@@ -46,10 +77,14 @@ provideGlobalGridOptions({ theme: "legacy" });
|
|
|
46
77
|
* Instead of looking at this implementation as a typical React component, look at it like a adapter between
|
|
47
78
|
* React and ag-grid which is used to render data obtained using GD executions.
|
|
48
79
|
*
|
|
49
|
-
* The code in this
|
|
80
|
+
* The code in this component is built to reflect the adapter nature of the integration. The responsibility of this
|
|
50
81
|
* component is to correctly handle the component lifecycle and orchestrate integration of React and ag-grid, React
|
|
51
82
|
* and GoodData, React and GoodData and ag-grid.
|
|
52
83
|
*
|
|
84
|
+
* Note on the implementation: because the table is driven imperatively, all the non-react state lives in refs and
|
|
85
|
+
* all the functions that the table hands over to its sub-components are stable for the entire lifetime of the
|
|
86
|
+
* component; they read the current props, state and internal state through refs.
|
|
87
|
+
*
|
|
53
88
|
* Lifecycle
|
|
54
89
|
* ---------
|
|
55
90
|
*
|
|
@@ -76,7 +111,7 @@ provideGlobalGridOptions({ theme: "legacy" });
|
|
|
76
111
|
* prepared execution, add the extra settings and re-drive the execution. Once done, it will update the internal
|
|
77
112
|
* state and ping ag-grid API to re-render the table.
|
|
78
113
|
*
|
|
79
|
-
* In case the client changes props (say modifying the prepared execution) the
|
|
114
|
+
* In case the client changes props (say modifying the prepared execution) the update effect will determine
|
|
80
115
|
* whether the full reinitialization is in order. If so the entire existing ag-grid and all our internal state
|
|
81
116
|
* is thrown out and table is initialized from scratch.
|
|
82
117
|
*
|
|
@@ -142,36 +177,18 @@ provideGlobalGridOptions({ theme: "legacy" });
|
|
|
142
177
|
*
|
|
143
178
|
* @internal
|
|
144
179
|
*/
|
|
145
|
-
export
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
sortingEventHandlers;
|
|
158
|
-
aggregationEventHandlers;
|
|
159
|
-
dataLoadingEventHandlers;
|
|
160
|
-
// Config accessor instance
|
|
161
|
-
configAccessors;
|
|
162
|
-
configDelegates;
|
|
163
|
-
// Sticky row manager instance
|
|
164
|
-
stickyRowManager;
|
|
165
|
-
// Height calculation manager instance
|
|
166
|
-
heightCalculationManager;
|
|
167
|
-
// Execution abort manager instance
|
|
168
|
-
executionAbortManager;
|
|
169
|
-
// Component update analyzer instance
|
|
170
|
-
componentUpdateAnalyzer;
|
|
171
|
-
constructor(props) {
|
|
172
|
-
super(props);
|
|
173
|
-
const { execution, config } = props;
|
|
174
|
-
this.state = {
|
|
180
|
+
export function CorePivotTableAgImpl(props) {
|
|
181
|
+
const resolvedProps = resolveDefaultProps(props);
|
|
182
|
+
/*
|
|
183
|
+
* Vast majority of the code below runs outside of the React rendering (ag-grid callbacks, timeouts, promise
|
|
184
|
+
* continuations). Props and state are therefore mirrored into refs so that this code always sees the current
|
|
185
|
+
* values - exactly like `this.props` and `this.state` used to do.
|
|
186
|
+
*/
|
|
187
|
+
const propsRef = useRef(resolvedProps);
|
|
188
|
+
propsRef.current = resolvedProps;
|
|
189
|
+
const [state, setStateInternal] = useState(() => {
|
|
190
|
+
const { execution, config } = resolvedProps;
|
|
191
|
+
return {
|
|
175
192
|
readyToRender: false,
|
|
176
193
|
columnTotals: cloneDeep(sanitizeDefTotals(execution.definition)),
|
|
177
194
|
rowTotals: getTotalsForColumnsBucket(execution.definition),
|
|
@@ -180,18 +197,480 @@ export class CorePivotTableAgImpl extends Component {
|
|
|
180
197
|
tempExecution: execution,
|
|
181
198
|
isLoading: false,
|
|
182
199
|
};
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
200
|
+
});
|
|
201
|
+
const stateRef = useRef(state);
|
|
202
|
+
stateRef.current = state;
|
|
203
|
+
/*
|
|
204
|
+
* Callbacks passed to the `setState(update, callback)` calls; they must run after the commit of the state
|
|
205
|
+
* update that registered them - the same way React does it for class components.
|
|
206
|
+
*
|
|
207
|
+
* Callbacks of the state updates that are already reflected in the state being rendered are moved to the
|
|
208
|
+
* 'committed' queue below, which is then drained by an effect after the commit.
|
|
209
|
+
*/
|
|
210
|
+
const enqueuedStateUpdateCallbacks = useRef([]);
|
|
211
|
+
const committedStateUpdateCallbacks = useRef([]);
|
|
212
|
+
if (enqueuedStateUpdateCallbacks.current.length > 0) {
|
|
213
|
+
committedStateUpdateCallbacks.current.push(...enqueuedStateUpdateCallbacks.current);
|
|
214
|
+
enqueuedStateUpdateCallbacks.current = [];
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Drop-in replacement of `React.Component.setState`: merges the partial state (or the result of the state
|
|
218
|
+
* updater function) into the current state and optionally calls a callback once the new state is committed.
|
|
219
|
+
*/
|
|
220
|
+
const setState = useCallback((update, callback) => {
|
|
221
|
+
if (callback) {
|
|
222
|
+
enqueuedStateUpdateCallbacks.current.push(callback);
|
|
223
|
+
}
|
|
224
|
+
setStateInternal((prevState) => ({
|
|
225
|
+
...prevState,
|
|
226
|
+
...(typeof update === "function" ? update(prevState) : update),
|
|
227
|
+
}));
|
|
228
|
+
}, []);
|
|
229
|
+
const errorMap = useMemo(() => newErrorMapping(resolvedProps.intl), [resolvedProps.intl]);
|
|
230
|
+
const pivotTableId = useMemo(() => uuidv4().replace(/-/g, ""), []);
|
|
231
|
+
/*
|
|
232
|
+
* The internal table state is intentionally kept out of the React state; it is replaced whenever the table
|
|
233
|
+
* gets re-initialized. Always access it through the ref so that the current instance is used.
|
|
234
|
+
*/
|
|
235
|
+
const internalRef = useRef(new InternalTableState());
|
|
236
|
+
const containerRef = useRef(undefined);
|
|
237
|
+
// Execution abort manager instance; created once for the whole lifetime of the component
|
|
238
|
+
const [executionAbortManager] = useState(() => new ExecutionAbortManager({
|
|
239
|
+
enableExecutionCancelling: resolvedProps.config?.enableExecutionCancelling,
|
|
240
|
+
}));
|
|
241
|
+
/*
|
|
242
|
+
* The imperative helpers below are created during the first render (this is what the constructor used to do)
|
|
243
|
+
* and are replaced whenever the table gets re-initialized.
|
|
244
|
+
*/
|
|
245
|
+
const eventHandlersRef = useRef(null);
|
|
246
|
+
const configAccessorsRef = useRef(null);
|
|
247
|
+
const componentUpdateAnalyzerRef = useRef(null);
|
|
248
|
+
const boundAgGridCallbacksRef = useRef(null);
|
|
249
|
+
/*
|
|
250
|
+
* The table methods handed over to the sub-components need to be able to trigger the table
|
|
251
|
+
* re-initialization; the re-initialization in turn needs the table methods. This ref breaks that cycle.
|
|
252
|
+
*/
|
|
253
|
+
const reinitializeRef = useRef(() => { });
|
|
254
|
+
/**
|
|
255
|
+
* Getter of the current internal table state. It is essential to always obtain the internal state through
|
|
256
|
+
* this getter because the internal state gets replaced on table re-initialization.
|
|
257
|
+
*/
|
|
258
|
+
const getInternal = useCallback(() => internalRef.current, []);
|
|
259
|
+
const getContainerRef = useCallback(() => containerRef.current, []);
|
|
260
|
+
const getEventHandlers = useCallback(() => {
|
|
261
|
+
const eventHandlers = eventHandlersRef.current;
|
|
262
|
+
invariant(eventHandlers);
|
|
263
|
+
return eventHandlers;
|
|
264
|
+
}, []);
|
|
265
|
+
const getConfigAccessors = useCallback(() => {
|
|
266
|
+
const configAccessors = configAccessorsRef.current;
|
|
267
|
+
invariant(configAccessors);
|
|
268
|
+
return configAccessors;
|
|
269
|
+
}, []);
|
|
270
|
+
//
|
|
271
|
+
// Table configuration accessors
|
|
272
|
+
//
|
|
273
|
+
const getLastSortedColId = useCallback(() => internalRef.current.lastSortedColId, []);
|
|
274
|
+
const setLastSortedColId = useCallback((colId) => {
|
|
275
|
+
internalRef.current.lastSortedColId = colId;
|
|
276
|
+
}, []);
|
|
277
|
+
// Delegate to config accessors
|
|
278
|
+
const getColumnTotals = useCallback(() => getConfigAccessors().configDelegates.getColumnTotals(), [getConfigAccessors]);
|
|
279
|
+
const getRowTotals = useCallback(() => getConfigAccessors().configDelegates.getRowTotals(), [getConfigAccessors]);
|
|
280
|
+
const getExecutionDefinition = useCallback(() => getConfigAccessors().configDelegates.getExecutionDefinition(), [getConfigAccessors]);
|
|
281
|
+
const getGroupRows = useCallback(() => getConfigAccessors().configDelegates.getGroupRows(), [getConfigAccessors]);
|
|
282
|
+
const getMeasureGroupDimension = useCallback(() => getConfigAccessors().configDelegates.getMeasureGroupDimension(), [getConfigAccessors]);
|
|
283
|
+
const getColumnHeadersPosition = useCallback(() => getConfigAccessors().configDelegates.getColumnHeadersPosition(), [getConfigAccessors]);
|
|
284
|
+
const getMenuConfig = useCallback(() => getConfigAccessors().configDelegates.getMenuConfig(), [getConfigAccessors]);
|
|
285
|
+
const getDefaultWidth = useCallback(() => getConfigAccessors().configDelegates.getDefaultWidth(), [getConfigAccessors]);
|
|
286
|
+
const isColumnAutoresizeEnabled = useCallback(() => getConfigAccessors().configDelegates.isColumnAutoresizeEnabled(), [getConfigAccessors]);
|
|
287
|
+
const isGrowToFitEnabled = useCallback((props = propsRef.current) => getConfigAccessors().configDelegates.isGrowToFitEnabled(props), [getConfigAccessors]);
|
|
288
|
+
const getColumnWidths = useCallback((props) => getConfigAccessors().configDelegates.getColumnWidths(props), [getConfigAccessors]);
|
|
289
|
+
const hasColumnWidths = useCallback(() => getConfigAccessors().configDelegates.hasColumnWidths(), [getConfigAccessors]);
|
|
290
|
+
const getDefaultWidthFromProps = useCallback((props) => getConfigAccessors().configDelegates.getDefaultWidthFromProps(props), [getConfigAccessors]);
|
|
291
|
+
const shouldAutoResizeColumns = useCallback(() => getConfigAccessors().configDelegates.shouldAutoResizeColumns(), [getConfigAccessors]);
|
|
292
|
+
const getResizingConfig = useCallback(() => {
|
|
293
|
+
const currentProps = propsRef.current;
|
|
294
|
+
const internal = internalRef.current;
|
|
295
|
+
return {
|
|
296
|
+
defaultWidth: getDefaultWidth(),
|
|
297
|
+
growToFit: isGrowToFitEnabled(),
|
|
298
|
+
columnAutoresizeOption: getDefaultWidthFromProps(currentProps),
|
|
299
|
+
widths: getColumnWidths(currentProps),
|
|
300
|
+
isAltKeyPressed: internal.isAltKeyPressed,
|
|
301
|
+
isMetaOrCtrlKeyPressed: internal.isMetaOrCtrlKeyPressed,
|
|
302
|
+
// use clientWidth of the viewport container to accommodate for vertical scrollbars if needed
|
|
303
|
+
clientWidth: containerRef.current?.getElementsByClassName("ag-body-viewport")[0]?.clientWidth ?? 0,
|
|
304
|
+
containerRef: containerRef.current,
|
|
305
|
+
separators: currentProps?.config?.separators,
|
|
306
|
+
onColumnResized: currentProps.onColumnResized,
|
|
307
|
+
};
|
|
308
|
+
}, [getColumnWidths, getDefaultWidth, getDefaultWidthFromProps, isGrowToFitEnabled]);
|
|
309
|
+
/**
|
|
310
|
+
* All pushData calls done by the table must go through this guard.
|
|
311
|
+
*
|
|
312
|
+
* TODO: The guard should ensure a 'disconnect' between push data handling and the calling function processing.
|
|
313
|
+
* When the pushData is handled by the application, it MAY (and in our case it DOES) trigger processing that
|
|
314
|
+
* lands back in the table. This opens additional set of invariants to check / be prepared for in order to
|
|
315
|
+
* optimize the renders and re-renders.
|
|
316
|
+
*/
|
|
317
|
+
const pushDataGuard = useCallback((data) => {
|
|
318
|
+
propsRef.current.pushData?.(data);
|
|
319
|
+
/*
|
|
320
|
+
* TODO: Switch to this on in FET-715.
|
|
321
|
+
setTimeout(() => {
|
|
322
|
+
propsRef.current.pushData?.(data);
|
|
323
|
+
}, 0);
|
|
324
|
+
*/
|
|
325
|
+
}, []);
|
|
326
|
+
//
|
|
327
|
+
// Sticky row handling - delegated to StickyRowManager
|
|
328
|
+
//
|
|
329
|
+
const updateStickyRow = useCallback(() => {
|
|
330
|
+
getConfigAccessors().stickyRowManager.updateStickyRow();
|
|
331
|
+
}, [getConfigAccessors]);
|
|
332
|
+
const updateStickyRowContent = useCallback((scrollPosition) => {
|
|
333
|
+
getConfigAccessors().stickyRowManager.updateStickyRowContent(scrollPosition);
|
|
334
|
+
}, [getConfigAccessors]);
|
|
335
|
+
//
|
|
336
|
+
// Desired height updating - delegated to HeightCalculationManager
|
|
337
|
+
//
|
|
338
|
+
const updateDesiredHeight = useCallback(() => {
|
|
339
|
+
getConfigAccessors().heightCalculationManager.updateDesiredHeight();
|
|
340
|
+
}, [getConfigAccessors]);
|
|
341
|
+
//
|
|
342
|
+
// Table resizing
|
|
343
|
+
//
|
|
344
|
+
const growToFit = useCallback(() => {
|
|
345
|
+
const internal = internalRef.current;
|
|
346
|
+
invariant(internal.table);
|
|
347
|
+
if (!isGrowToFitEnabled()) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
internal.table.growToFit(getResizingConfig());
|
|
351
|
+
if (!stateRef.current.resized && !internal.table.isResizing()) {
|
|
352
|
+
setState({
|
|
353
|
+
resized: true,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}, [getResizingConfig, isGrowToFitEnabled, setState]);
|
|
357
|
+
const autoresizeColumns = useCallback(async (force = false) => {
|
|
358
|
+
if (stateRef.current.resized && !force) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const didResize = await internalRef.current.table?.autoresizeColumns(getResizingConfig(), force);
|
|
362
|
+
if (didResize) {
|
|
363
|
+
// after column resizing, horizontal scroolbar may change and table height may need resizing
|
|
364
|
+
updateDesiredHeight();
|
|
365
|
+
}
|
|
366
|
+
if (didResize && !stateRef.current.resized) {
|
|
367
|
+
setState({
|
|
368
|
+
resized: true,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}, [getResizingConfig, setState, updateDesiredHeight]);
|
|
372
|
+
const stopWatchingTableRendered = useCallback(() => {
|
|
373
|
+
internalRef.current.stopWatching();
|
|
374
|
+
propsRef.current.afterRender();
|
|
375
|
+
}, []);
|
|
376
|
+
const startWatchingTableRendered = useCallback(() => {
|
|
377
|
+
const internal = internalRef.current;
|
|
378
|
+
if (!internal.table) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const missingContainerRef = !containerRef.current; // table having no data will be unmounted, it causes ref null
|
|
382
|
+
const isTableRendered = shouldAutoResizeColumns()
|
|
383
|
+
? stateRef.current.resized
|
|
384
|
+
: internal.table.isPivotTableReady();
|
|
385
|
+
const shouldCallAutoresizeColumns = internal.table.isPivotTableReady() && !stateRef.current.resized && !internal.table.isResizing();
|
|
386
|
+
if (shouldAutoResizeColumns() && shouldCallAutoresizeColumns) {
|
|
387
|
+
void autoresizeColumns();
|
|
388
|
+
}
|
|
389
|
+
if (missingContainerRef || isTableRendered) {
|
|
390
|
+
stopWatchingTableRendered();
|
|
391
|
+
}
|
|
392
|
+
}, [autoresizeColumns, shouldAutoResizeColumns, stopWatchingTableRendered]);
|
|
393
|
+
//
|
|
394
|
+
// event handlers
|
|
395
|
+
//
|
|
396
|
+
const onGridReady = useCallback((event) => {
|
|
397
|
+
getEventHandlers().gridEventHandlers.onGridReady(event);
|
|
398
|
+
}, [getEventHandlers]);
|
|
399
|
+
const onFirstDataRendered = useCallback(async (_event) => {
|
|
400
|
+
await getEventHandlers().dataRenderHandlers.onFirstDataRendered(_event);
|
|
401
|
+
}, [getEventHandlers]);
|
|
402
|
+
const onModelUpdated = useCallback((event) => {
|
|
403
|
+
getEventHandlers().gridEventHandlers.onModelUpdated(event);
|
|
404
|
+
}, [getEventHandlers]);
|
|
405
|
+
const onGridColumnsChanged = useCallback(() => {
|
|
406
|
+
getEventHandlers().gridEventHandlers.onGridColumnsChanged();
|
|
407
|
+
}, [getEventHandlers]);
|
|
408
|
+
const onGridSizeChanged = useCallback((gridSizeChangedEvent) => {
|
|
409
|
+
getEventHandlers().resizeEventHandlers.onGridSizeChanged(gridSizeChangedEvent);
|
|
410
|
+
}, [getEventHandlers]);
|
|
411
|
+
const onGridColumnResized = useCallback((columnEvent) => {
|
|
412
|
+
getEventHandlers().resizeEventHandlers.onGridColumnResized(columnEvent);
|
|
413
|
+
}, [getEventHandlers]);
|
|
414
|
+
const onSortChanged = useCallback((event) => {
|
|
415
|
+
getEventHandlers().sortingEventHandlers.onSortChanged(event);
|
|
416
|
+
}, [getEventHandlers]);
|
|
417
|
+
const onPinnedRowDataChanged = useCallback(async (event) => {
|
|
418
|
+
await getEventHandlers().resizeEventHandlers.onPinnedRowDataChanged(event);
|
|
419
|
+
}, [getEventHandlers]);
|
|
420
|
+
const onBodyScroll = useCallback((event) => {
|
|
421
|
+
getEventHandlers().scrollEventHandlers.onBodyScroll(event);
|
|
422
|
+
}, [getEventHandlers]);
|
|
423
|
+
const onContainerMouseDown = useCallback((event) => {
|
|
424
|
+
getEventHandlers().scrollEventHandlers.onContainerMouseDown(event);
|
|
425
|
+
}, [getEventHandlers]);
|
|
426
|
+
const onPageLoaded = useCallback((dv, newResult) => {
|
|
427
|
+
getEventHandlers().dataLoadingEventHandlers.onPageLoaded(dv, newResult);
|
|
428
|
+
}, [getEventHandlers]);
|
|
429
|
+
const onMenuAggregationClick = useCallback((menuAggregationClickConfig) => {
|
|
430
|
+
getEventHandlers().aggregationEventHandlers.onMenuAggregationClick(menuAggregationClickConfig);
|
|
431
|
+
}, [getEventHandlers]);
|
|
432
|
+
const onLoadingChanged = useCallback((loadingState) => {
|
|
433
|
+
getEventHandlers().dataLoadingEventHandlers.onLoadingChanged(loadingState);
|
|
434
|
+
}, [getEventHandlers]);
|
|
435
|
+
const onError = useCallback((error, execution = propsRef.current.execution) => {
|
|
436
|
+
getEventHandlers().dataLoadingEventHandlers.onError(error, execution);
|
|
437
|
+
}, [getEventHandlers]);
|
|
438
|
+
/**
|
|
439
|
+
* This will be called when user changes sorts or adds totals. This means complete re-execution with
|
|
440
|
+
* new sorts or totals. Loading indicators will be shown instead of all rendered rows thanks to the
|
|
441
|
+
* LoadingRenderer used in all cells of the left-most column.
|
|
442
|
+
*
|
|
443
|
+
* The table must take care to remove the sticky (top-pinned) row - it is treated differently by
|
|
444
|
+
* ag-grid and will be literally sticking there on its own with the loading indicators.
|
|
445
|
+
*
|
|
446
|
+
* Once transformation finishes - indicated by call to onPageLoaded, table can re-instance the sticky row.
|
|
447
|
+
*
|
|
448
|
+
* @param newExecution - the new execution which is being run and will be used to populate the table
|
|
449
|
+
*/
|
|
450
|
+
const onExecutionTransformed = useCallback((newExecution) => {
|
|
451
|
+
// Handle the reinitialize call directly here since we can't pass it to the handler
|
|
452
|
+
const internal = internalRef.current;
|
|
453
|
+
if (!internal.table) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
internal.table.clearStickyRow();
|
|
457
|
+
// Force double execution only when totals/subtotals for columns change, so table is render properly.
|
|
458
|
+
if (!isEqual(stateRef.current.tempExecution.definition.buckets[2], newExecution.definition.buckets[2])) {
|
|
459
|
+
setState({
|
|
460
|
+
tempExecution: newExecution,
|
|
461
|
+
});
|
|
462
|
+
reinitializeRef.current(newExecution);
|
|
463
|
+
}
|
|
464
|
+
}, [setState]);
|
|
465
|
+
/**
|
|
466
|
+
* All callback functions that the table passes to ag-grid must be bound to the current internal state of the table. The
|
|
467
|
+
* callback functions MUST be noop if the internal state at the time of call is different from the internal state
|
|
468
|
+
* at the time of creation.
|
|
469
|
+
*
|
|
470
|
+
* This is essential to prevent errors stemming for racy behavior triggered by ag-grid. ag-grid often triggers
|
|
471
|
+
* event callbacks using setTimeout(). It can happen, that once the event is actually processed the ag-grid table
|
|
472
|
+
* which caused it is unmounted. Doing anything with the unmounted table's gridApi leads to errors.
|
|
473
|
+
*
|
|
474
|
+
* Without this, table may trigger ag-grid errors such as this:
|
|
475
|
+
*
|
|
476
|
+
* https://github.com/ag-grid/ag-grid/issues/3457
|
|
477
|
+
*
|
|
478
|
+
* or this:
|
|
479
|
+
*
|
|
480
|
+
* https://github.com/ag-grid/ag-grid/issues/3334
|
|
481
|
+
*/
|
|
482
|
+
const createBoundAgGridCallbacks = useCallback(() => {
|
|
483
|
+
const internal = internalRef.current;
|
|
484
|
+
const debouncedGridSizeChanged = createDebouncedCallback(createStateBoundCallback(onGridSizeChanged, internal, getInternal), AGGRID_ON_RESIZE_TIMEOUT);
|
|
485
|
+
return {
|
|
486
|
+
onGridReady: createStateBoundCallback(onGridReady, internal, getInternal),
|
|
487
|
+
onFirstDataRendered: createStateBoundCallback(onFirstDataRendered, internal, getInternal),
|
|
488
|
+
onBodyScroll: createStateBoundCallback(onBodyScroll, internal, getInternal),
|
|
489
|
+
onModelUpdated: createStateBoundCallback(onModelUpdated, internal, getInternal),
|
|
490
|
+
onGridColumnsChanged: createStateBoundCallback(onGridColumnsChanged, internal, getInternal),
|
|
491
|
+
onGridColumnResized: createStateBoundCallback(onGridColumnResized, internal, getInternal),
|
|
492
|
+
onSortChanged: createStateBoundCallback(onSortChanged, internal, getInternal),
|
|
493
|
+
onGridSizeChanged: debouncedGridSizeChanged,
|
|
494
|
+
onPinnedRowDataChanged: createStateBoundCallback(onPinnedRowDataChanged, internal, getInternal),
|
|
495
|
+
};
|
|
496
|
+
}, [
|
|
497
|
+
getInternal,
|
|
498
|
+
onBodyScroll,
|
|
499
|
+
onFirstDataRendered,
|
|
500
|
+
onGridColumnResized,
|
|
501
|
+
onGridColumnsChanged,
|
|
502
|
+
onGridReady,
|
|
503
|
+
onGridSizeChanged,
|
|
504
|
+
onModelUpdated,
|
|
505
|
+
onPinnedRowDataChanged,
|
|
506
|
+
onSortChanged,
|
|
507
|
+
]);
|
|
508
|
+
const getTableMethods = useCallback(() => {
|
|
509
|
+
const boundAgGridCallbacks = boundAgGridCallbacksRef.current;
|
|
510
|
+
invariant(boundAgGridCallbacks);
|
|
511
|
+
return {
|
|
512
|
+
hasColumnWidths: hasColumnWidths(),
|
|
513
|
+
getExecutionDefinition,
|
|
514
|
+
getMenuConfig,
|
|
515
|
+
getGroupRows,
|
|
516
|
+
getColumnTotals,
|
|
517
|
+
getRowTotals,
|
|
518
|
+
getColumnHeadersPosition,
|
|
519
|
+
getMeasureGroupDimension,
|
|
520
|
+
getResizingConfig,
|
|
521
|
+
onLoadingChanged,
|
|
522
|
+
onError,
|
|
523
|
+
onExportReady: propsRef.current.onExportReady ?? (() => { }),
|
|
524
|
+
pushData: pushDataGuard,
|
|
525
|
+
onPageLoaded,
|
|
526
|
+
onExecutionTransformed,
|
|
527
|
+
onMenuAggregationClick,
|
|
528
|
+
setLastSortedColId,
|
|
529
|
+
...boundAgGridCallbacks,
|
|
530
|
+
};
|
|
531
|
+
}, [
|
|
532
|
+
getColumnHeadersPosition,
|
|
533
|
+
getColumnTotals,
|
|
534
|
+
getExecutionDefinition,
|
|
535
|
+
getGroupRows,
|
|
536
|
+
getMeasureGroupDimension,
|
|
537
|
+
getMenuConfig,
|
|
538
|
+
getResizingConfig,
|
|
539
|
+
getRowTotals,
|
|
540
|
+
hasColumnWidths,
|
|
541
|
+
onError,
|
|
542
|
+
onExecutionTransformed,
|
|
543
|
+
onLoadingChanged,
|
|
544
|
+
onMenuAggregationClick,
|
|
545
|
+
onPageLoaded,
|
|
546
|
+
pushDataGuard,
|
|
547
|
+
setLastSortedColId,
|
|
548
|
+
]);
|
|
549
|
+
//
|
|
550
|
+
// Initialization of the imperative parts of the table
|
|
551
|
+
//
|
|
552
|
+
const initializeEventHandlers = useCallback(() => {
|
|
553
|
+
const internal = internalRef.current;
|
|
554
|
+
const currentProps = propsRef.current;
|
|
555
|
+
// Create event handler instances with proper context
|
|
556
|
+
eventHandlersRef.current = {
|
|
557
|
+
gridEventHandlers: new GridEventHandlers({
|
|
558
|
+
internal,
|
|
559
|
+
props: currentProps,
|
|
560
|
+
updateDesiredHeight,
|
|
561
|
+
onFirstDataRendered,
|
|
562
|
+
updateStickyRow,
|
|
563
|
+
getGroupRows,
|
|
564
|
+
getLastSortedColId,
|
|
565
|
+
setLastSortedColId,
|
|
566
|
+
}),
|
|
567
|
+
dataRenderHandlers: new DataRenderHandlers({
|
|
568
|
+
internal,
|
|
569
|
+
isColumnAutoresizeEnabled,
|
|
570
|
+
isGrowToFitEnabled,
|
|
571
|
+
autoresizeColumns,
|
|
572
|
+
growToFit,
|
|
573
|
+
updateStickyRow,
|
|
574
|
+
startWatchingTableRendered,
|
|
575
|
+
}),
|
|
576
|
+
scrollEventHandlers: new ScrollEventHandlers({
|
|
577
|
+
internal,
|
|
578
|
+
updateStickyRowContent,
|
|
579
|
+
}),
|
|
580
|
+
resizeEventHandlers: new ResizeEventHandlers({
|
|
581
|
+
internal,
|
|
582
|
+
updateDesiredHeight,
|
|
583
|
+
autoresizeColumns,
|
|
584
|
+
getResizingConfig,
|
|
585
|
+
}),
|
|
586
|
+
sortingEventHandlers: new SortingEventHandlers({
|
|
587
|
+
internal,
|
|
588
|
+
getExecutionDefinition,
|
|
589
|
+
pushDataGuard,
|
|
590
|
+
setState,
|
|
591
|
+
}),
|
|
592
|
+
aggregationEventHandlers: new AggregationEventHandlers({
|
|
593
|
+
internal,
|
|
594
|
+
getExecutionDefinition,
|
|
595
|
+
getColumnTotals,
|
|
596
|
+
getRowTotals,
|
|
597
|
+
pushDataGuard,
|
|
598
|
+
setState,
|
|
599
|
+
}),
|
|
600
|
+
dataLoadingEventHandlers: new DataLoadingEventHandlers({
|
|
601
|
+
internal,
|
|
602
|
+
props: currentProps,
|
|
603
|
+
updateStickyRow,
|
|
604
|
+
updateDesiredHeight,
|
|
605
|
+
setState,
|
|
606
|
+
}),
|
|
607
|
+
};
|
|
608
|
+
}, [
|
|
609
|
+
autoresizeColumns,
|
|
610
|
+
getColumnTotals,
|
|
611
|
+
getExecutionDefinition,
|
|
612
|
+
getGroupRows,
|
|
613
|
+
getLastSortedColId,
|
|
614
|
+
getResizingConfig,
|
|
615
|
+
getRowTotals,
|
|
616
|
+
growToFit,
|
|
617
|
+
isColumnAutoresizeEnabled,
|
|
618
|
+
isGrowToFitEnabled,
|
|
619
|
+
onFirstDataRendered,
|
|
620
|
+
pushDataGuard,
|
|
621
|
+
setLastSortedColId,
|
|
622
|
+
setState,
|
|
623
|
+
startWatchingTableRendered,
|
|
624
|
+
updateDesiredHeight,
|
|
625
|
+
updateStickyRow,
|
|
626
|
+
updateStickyRowContent,
|
|
627
|
+
]);
|
|
628
|
+
const createComponentUpdateAnalyzer = useCallback(() => new ComponentUpdateAnalyzer({
|
|
629
|
+
props: propsRef.current,
|
|
630
|
+
state: stateRef.current,
|
|
631
|
+
internal: internalRef.current,
|
|
632
|
+
executionAbortManager,
|
|
633
|
+
}), [executionAbortManager]);
|
|
634
|
+
const initializeConfigAccessors = useCallback(() => {
|
|
635
|
+
const internal = internalRef.current;
|
|
636
|
+
const currentProps = propsRef.current;
|
|
637
|
+
const currentState = stateRef.current;
|
|
638
|
+
const configAccessors = new TableConfigAccessors({
|
|
639
|
+
props: currentProps,
|
|
640
|
+
state: currentState,
|
|
191
641
|
});
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
642
|
+
configAccessorsRef.current = {
|
|
643
|
+
configAccessors,
|
|
644
|
+
configDelegates: createConfigDelegates(configAccessors),
|
|
645
|
+
// Initialize sticky row manager
|
|
646
|
+
stickyRowManager: new StickyRowManager({
|
|
647
|
+
internal,
|
|
648
|
+
props: currentProps,
|
|
649
|
+
state: currentState,
|
|
650
|
+
getGroupRows,
|
|
651
|
+
}),
|
|
652
|
+
// Initialize height calculation manager
|
|
653
|
+
heightCalculationManager: new HeightCalculationManager({
|
|
654
|
+
internal,
|
|
655
|
+
props: currentProps,
|
|
656
|
+
state: currentState,
|
|
657
|
+
setState,
|
|
658
|
+
getContainerRef,
|
|
659
|
+
}),
|
|
660
|
+
};
|
|
661
|
+
// Initialize component update analyzer
|
|
662
|
+
componentUpdateAnalyzerRef.current = createComponentUpdateAnalyzer();
|
|
663
|
+
}, [createComponentUpdateAnalyzer, getContainerRef, getGroupRows, setState]);
|
|
664
|
+
/*
|
|
665
|
+
* Mirrors what the class constructor used to do: create the event handlers, config accessors and the
|
|
666
|
+
* ag-grid callbacks before anything gets rendered.
|
|
667
|
+
*/
|
|
668
|
+
const isInitializedRef = useRef(false);
|
|
669
|
+
if (!isInitializedRef.current) {
|
|
670
|
+
isInitializedRef.current = true;
|
|
671
|
+
initializeEventHandlers();
|
|
672
|
+
initializeConfigAccessors();
|
|
673
|
+
boundAgGridCallbacksRef.current = createBoundAgGridCallbacks();
|
|
195
674
|
}
|
|
196
675
|
//
|
|
197
676
|
// Lifecycle
|
|
@@ -210,26 +689,26 @@ export class CorePivotTableAgImpl extends Component {
|
|
|
210
689
|
*
|
|
211
690
|
* @param execution - prepared execution to drive
|
|
212
691
|
*/
|
|
213
|
-
initialize = (execution) => {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
isLoading:
|
|
217
|
-
readyToRender:
|
|
692
|
+
const initialize = useCallback((execution) => {
|
|
693
|
+
internalRef.current.abandonInitialization();
|
|
694
|
+
executionAbortManager.refresh({
|
|
695
|
+
isLoading: stateRef.current.isLoading,
|
|
696
|
+
readyToRender: stateRef.current.readyToRender,
|
|
218
697
|
});
|
|
219
|
-
const initializer = new TableFacadeInitializer(execution,
|
|
698
|
+
const initializer = new TableFacadeInitializer(execution, getTableMethods(), propsRef.current, () => executionAbortManager.getCurrentController());
|
|
220
699
|
void initializer.initialize().then((result) => {
|
|
221
|
-
if (!result ||
|
|
700
|
+
if (!result || internalRef.current.initializer !== result.initializer) {
|
|
222
701
|
/*
|
|
223
702
|
* This particular initialization was abandoned.
|
|
224
703
|
*/
|
|
225
704
|
return;
|
|
226
705
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
706
|
+
internalRef.current.initializer = undefined;
|
|
707
|
+
internalRef.current.table = result.table;
|
|
708
|
+
setState({ readyToRender: true });
|
|
230
709
|
});
|
|
231
710
|
return initializer;
|
|
232
|
-
};
|
|
711
|
+
}, [executionAbortManager, getTableMethods, setState]);
|
|
233
712
|
/**
|
|
234
713
|
* Completely re-initializes the table in order to show data for the provided prepared execution. At this point
|
|
235
714
|
* code has determined that the table layout for the other prepared execution differs from what is currently
|
|
@@ -237,53 +716,52 @@ export class CorePivotTableAgImpl extends Component {
|
|
|
237
716
|
*
|
|
238
717
|
* This will reset all React state and non-react state and start table initialization process.
|
|
239
718
|
*/
|
|
240
|
-
reinitialize = (execution) => {
|
|
241
|
-
|
|
719
|
+
const reinitialize = useCallback((execution) => {
|
|
720
|
+
setState({
|
|
242
721
|
readyToRender: false,
|
|
243
722
|
columnTotals: cloneDeep(sanitizeDefTotals(execution.definition)),
|
|
244
723
|
rowTotals: getTotalsForColumnsBucket(execution.definition),
|
|
245
724
|
error: undefined,
|
|
246
|
-
desiredHeight:
|
|
725
|
+
desiredHeight: propsRef.current.config.maxHeight,
|
|
247
726
|
resized: false,
|
|
248
727
|
}, () => {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
728
|
+
internalRef.current.destroy();
|
|
729
|
+
internalRef.current = new InternalTableState();
|
|
730
|
+
initializeEventHandlers();
|
|
731
|
+
initializeConfigAccessors();
|
|
732
|
+
boundAgGridCallbacksRef.current = createBoundAgGridCallbacks();
|
|
733
|
+
internalRef.current.initializer = initialize(execution);
|
|
255
734
|
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
735
|
+
}, [
|
|
736
|
+
createBoundAgGridCallbacks,
|
|
737
|
+
initialize,
|
|
738
|
+
initializeConfigAccessors,
|
|
739
|
+
initializeEventHandlers,
|
|
740
|
+
setState,
|
|
741
|
+
]);
|
|
742
|
+
reinitializeRef.current = reinitialize;
|
|
743
|
+
/**
|
|
744
|
+
* Handles the component update; this is the functional equivalent of what used to live in
|
|
745
|
+
* `componentDidUpdate`.
|
|
746
|
+
*/
|
|
747
|
+
const handleUpdate = useCallback((prevProps) => {
|
|
748
|
+
const currentProps = propsRef.current;
|
|
749
|
+
const previousAnalyzer = componentUpdateAnalyzerRef.current;
|
|
750
|
+
invariant(previousAnalyzer);
|
|
269
751
|
// Update execution abort manager config if it changed
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
enableExecutionCancelling:
|
|
752
|
+
if (previousAnalyzer.hasExecutionCancellingChanged(prevProps)) {
|
|
753
|
+
executionAbortManager.updateConfig({
|
|
754
|
+
enableExecutionCancelling: currentProps.config?.enableExecutionCancelling,
|
|
273
755
|
});
|
|
274
756
|
}
|
|
275
757
|
// Update component update analyzer context
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
state: this.state,
|
|
279
|
-
internal: this.internal,
|
|
280
|
-
executionAbortManager: this.executionAbortManager,
|
|
281
|
-
});
|
|
758
|
+
const componentUpdateAnalyzer = createComponentUpdateAnalyzer();
|
|
759
|
+
componentUpdateAnalyzerRef.current = componentUpdateAnalyzer;
|
|
282
760
|
// reinit in progress
|
|
283
|
-
if (
|
|
761
|
+
if (componentUpdateAnalyzer.shouldSkipUpdate()) {
|
|
284
762
|
return;
|
|
285
763
|
}
|
|
286
|
-
if (
|
|
764
|
+
if (componentUpdateAnalyzer.isReinitNeeded(prevProps)) {
|
|
287
765
|
/*
|
|
288
766
|
* This triggers when execution changes (new measures / attributes). In that case,
|
|
289
767
|
* a complete re-init of the table is in order.
|
|
@@ -294,8 +772,8 @@ export class CorePivotTableAgImpl extends Component {
|
|
|
294
772
|
* Note: compared to v7 version of the table, this only happens if someone actually changes the
|
|
295
773
|
* execution-related props of the table. This branch will not hit any other time.
|
|
296
774
|
*/
|
|
297
|
-
|
|
298
|
-
|
|
775
|
+
componentUpdateAnalyzer.logReinitDebug(prevProps.execution);
|
|
776
|
+
reinitialize(currentProps.execution);
|
|
299
777
|
}
|
|
300
778
|
else {
|
|
301
779
|
/*
|
|
@@ -305,424 +783,110 @@ export class CorePivotTableAgImpl extends Component {
|
|
|
305
783
|
* The currentResult and visibleData _will_ be available at this point because the component is definitely
|
|
306
784
|
* after a successful execution and initialization.
|
|
307
785
|
*/
|
|
308
|
-
if (
|
|
309
|
-
|
|
786
|
+
if (componentUpdateAnalyzer.shouldRefreshHeader(prevProps)) {
|
|
787
|
+
internalRef.current.table?.refreshHeader();
|
|
310
788
|
}
|
|
311
|
-
if (
|
|
312
|
-
|
|
789
|
+
if (componentUpdateAnalyzer.hasGrowToFitEnabledChanged(prevProps, isGrowToFitEnabled)) {
|
|
790
|
+
growToFit();
|
|
313
791
|
}
|
|
314
|
-
if (
|
|
315
|
-
|
|
792
|
+
if (componentUpdateAnalyzer.hasColumnWidthsChanged(prevProps, getColumnWidths)) {
|
|
793
|
+
internalRef.current.table?.applyColumnSizes(getResizingConfig());
|
|
316
794
|
}
|
|
317
|
-
if (
|
|
318
|
-
|
|
795
|
+
if (componentUpdateAnalyzer.hasMaxHeightChanged(prevProps)) {
|
|
796
|
+
updateDesiredHeight();
|
|
319
797
|
}
|
|
320
798
|
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
return _jsx(PivotTableLoading, { LoadingComponent: LoadingComponent, theme: theme });
|
|
342
|
-
}
|
|
343
|
-
render() {
|
|
344
|
-
const { ErrorComponent } = this.props;
|
|
345
|
-
const { desiredHeight, error } = this.state;
|
|
346
|
-
if (error) {
|
|
347
|
-
return _jsx(PivotTableError, { error: error, errorMap: this.errorMap, ErrorComponent: ErrorComponent });
|
|
348
|
-
}
|
|
349
|
-
const style = {
|
|
350
|
-
height: desiredHeight || "100%",
|
|
351
|
-
position: "relative",
|
|
352
|
-
overflow: "hidden",
|
|
799
|
+
}, [
|
|
800
|
+
createComponentUpdateAnalyzer,
|
|
801
|
+
executionAbortManager,
|
|
802
|
+
getColumnWidths,
|
|
803
|
+
getResizingConfig,
|
|
804
|
+
growToFit,
|
|
805
|
+
isGrowToFitEnabled,
|
|
806
|
+
reinitialize,
|
|
807
|
+
updateDesiredHeight,
|
|
808
|
+
]);
|
|
809
|
+
// componentDidMount & componentWillUnmount
|
|
810
|
+
useLayoutEffect(() => {
|
|
811
|
+
internalRef.current.initializer = initialize(propsRef.current.execution);
|
|
812
|
+
return () => {
|
|
813
|
+
executionAbortManager.destroy();
|
|
814
|
+
if (containerRef.current) {
|
|
815
|
+
containerRef.current.removeEventListener("mousedown", onContainerMouseDown);
|
|
816
|
+
}
|
|
817
|
+
// this ensures any events emitted during the async initialization will be sunk. they are no longer needed.
|
|
818
|
+
internalRef.current.destroy();
|
|
353
819
|
};
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
* can start reliably interfacing with the autosizing features.
|
|
367
|
-
*/
|
|
368
|
-
const shouldRenderLoadingOverlay = (this.isColumnAutoresizeEnabled() || this.isGrowToFitEnabled()) && !this.state.resized;
|
|
369
|
-
const classNames = cx("gd-table-component", {
|
|
370
|
-
"gd-table-header-hide": this.props.config?.columnHeadersPosition === "left" &&
|
|
371
|
-
this.internal.table.tableDescriptor.isTransposed(),
|
|
372
|
-
});
|
|
373
|
-
return (_jsx("div", { className: classNames, style: style, id: this.pivotTableId, onMouseDown: this.stopEventWhenResizeHeader, onDragStart: this.stopEventWhenResizeHeader, children: _jsxs("div", { className: "gd-table ag-theme-balham s-pivot-table", style: style, ref: this.setContainerRef, children: [
|
|
374
|
-
_jsx(AgGridReact, { ...this.internal.gridOptions, modules: [AllCommunityModule] }), shouldRenderLoadingOverlay ? this.renderLoading() : null] }) }));
|
|
375
|
-
}
|
|
376
|
-
//
|
|
377
|
-
// Initialize event handlers
|
|
378
|
-
//
|
|
379
|
-
initializeEventHandlers = () => {
|
|
380
|
-
// Create event handler instances with proper context
|
|
381
|
-
this.gridEventHandlers = new GridEventHandlers({
|
|
382
|
-
internal: this.internal,
|
|
383
|
-
props: this.props,
|
|
384
|
-
updateDesiredHeight: this.updateDesiredHeight,
|
|
385
|
-
onFirstDataRendered: this.onFirstDataRendered,
|
|
386
|
-
updateStickyRow: this.updateStickyRow,
|
|
387
|
-
getGroupRows: this.getGroupRows,
|
|
388
|
-
getLastSortedColId: this.getLastSortedColId,
|
|
389
|
-
setLastSortedColId: this.setLastSortedColId,
|
|
390
|
-
});
|
|
391
|
-
this.dataRenderHandlers = new DataRenderHandlers({
|
|
392
|
-
internal: this.internal,
|
|
393
|
-
isColumnAutoresizeEnabled: this.isColumnAutoresizeEnabled,
|
|
394
|
-
isGrowToFitEnabled: this.isGrowToFitEnabled,
|
|
395
|
-
autoresizeColumns: this.autoresizeColumns,
|
|
396
|
-
growToFit: this.growToFit,
|
|
397
|
-
updateStickyRow: this.updateStickyRow,
|
|
398
|
-
startWatchingTableRendered: this.startWatchingTableRendered,
|
|
399
|
-
});
|
|
400
|
-
this.scrollEventHandlers = new ScrollEventHandlers({
|
|
401
|
-
internal: this.internal,
|
|
402
|
-
updateStickyRowContent: this.updateStickyRowContent,
|
|
403
|
-
});
|
|
404
|
-
this.resizeEventHandlers = new ResizeEventHandlers({
|
|
405
|
-
internal: this.internal,
|
|
406
|
-
updateDesiredHeight: this.updateDesiredHeight,
|
|
407
|
-
autoresizeColumns: this.autoresizeColumns,
|
|
408
|
-
getResizingConfig: this.getResizingConfig,
|
|
409
|
-
});
|
|
410
|
-
this.sortingEventHandlers = new SortingEventHandlers({
|
|
411
|
-
internal: this.internal,
|
|
412
|
-
getExecutionDefinition: this.getExecutionDefinition,
|
|
413
|
-
pushDataGuard: this.pushDataGuard,
|
|
414
|
-
setState: this.setState.bind(this),
|
|
415
|
-
});
|
|
416
|
-
this.aggregationEventHandlers = new AggregationEventHandlers({
|
|
417
|
-
internal: this.internal,
|
|
418
|
-
getExecutionDefinition: this.getExecutionDefinition,
|
|
419
|
-
getColumnTotals: this.getColumnTotals,
|
|
420
|
-
getRowTotals: this.getRowTotals,
|
|
421
|
-
pushDataGuard: this.pushDataGuard,
|
|
422
|
-
setState: this.setState.bind(this),
|
|
423
|
-
});
|
|
424
|
-
this.dataLoadingEventHandlers = new DataLoadingEventHandlers({
|
|
425
|
-
internal: this.internal,
|
|
426
|
-
props: this.props,
|
|
427
|
-
updateStickyRow: this.updateStickyRow,
|
|
428
|
-
updateDesiredHeight: this.updateDesiredHeight,
|
|
429
|
-
setState: this.setState.bind(this),
|
|
430
|
-
});
|
|
431
|
-
};
|
|
432
|
-
//
|
|
433
|
-
// event handlers
|
|
434
|
-
//
|
|
435
|
-
onGridReady = (event) => {
|
|
436
|
-
this.gridEventHandlers.onGridReady(event);
|
|
437
|
-
};
|
|
438
|
-
onFirstDataRendered = async (_event) => {
|
|
439
|
-
await this.dataRenderHandlers.onFirstDataRendered(_event);
|
|
440
|
-
};
|
|
441
|
-
onModelUpdated = (event) => {
|
|
442
|
-
this.gridEventHandlers.onModelUpdated(event);
|
|
443
|
-
};
|
|
444
|
-
onGridColumnsChanged = () => {
|
|
445
|
-
this.gridEventHandlers.onGridColumnsChanged();
|
|
446
|
-
};
|
|
447
|
-
onGridSizeChanged = (gridSizeChangedEvent) => {
|
|
448
|
-
this.resizeEventHandlers.onGridSizeChanged(gridSizeChangedEvent);
|
|
449
|
-
};
|
|
450
|
-
onGridColumnResized = (columnEvent) => {
|
|
451
|
-
this.resizeEventHandlers.onGridColumnResized(columnEvent);
|
|
452
|
-
};
|
|
453
|
-
onSortChanged = (event) => {
|
|
454
|
-
this.sortingEventHandlers.onSortChanged(event);
|
|
455
|
-
};
|
|
456
|
-
onPinnedRowDataChanged = async (event) => {
|
|
457
|
-
await this.resizeEventHandlers.onPinnedRowDataChanged(event);
|
|
458
|
-
};
|
|
459
|
-
onBodyScroll = (event) => {
|
|
460
|
-
this.scrollEventHandlers.onBodyScroll(event);
|
|
461
|
-
};
|
|
462
|
-
onContainerMouseDown = (event) => {
|
|
463
|
-
this.scrollEventHandlers.onContainerMouseDown(event);
|
|
464
|
-
};
|
|
465
|
-
onPageLoaded = (dv, newResult) => {
|
|
466
|
-
this.dataLoadingEventHandlers.onPageLoaded(dv, newResult);
|
|
467
|
-
};
|
|
468
|
-
/**
|
|
469
|
-
* This will be called when user changes sorts or adds totals. This means complete re-execution with
|
|
470
|
-
* new sorts or totals. Loading indicators will be shown instead of all rendered rows thanks to the
|
|
471
|
-
* LoadingRenderer used in all cells of the left-most column.
|
|
472
|
-
*
|
|
473
|
-
* The table must take care to remove the sticky (top-pinned) row - it is treated differently by
|
|
474
|
-
* ag-grid and will be literally sticking there on its own with the loading indicators.
|
|
475
|
-
*
|
|
476
|
-
* Once transformation finishes - indicated by call to onPageLoaded, table can re-instance the sticky row.
|
|
477
|
-
*
|
|
478
|
-
* @param newExecution - the new execution which is being run and will be used to populate the table
|
|
479
|
-
*/
|
|
480
|
-
onExecutionTransformed = (newExecution) => {
|
|
481
|
-
// Handle the reinitialize call directly here since we can't pass it to the handler
|
|
482
|
-
if (!this.internal.table) {
|
|
820
|
+
// the table must be initialized on mount only; all the functions used here are stable
|
|
821
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
822
|
+
}, []);
|
|
823
|
+
// componentDidUpdate
|
|
824
|
+
const prevPropsRef = useRef(resolvedProps);
|
|
825
|
+
const isMountedRef = useRef(false);
|
|
826
|
+
useLayoutEffect(() => {
|
|
827
|
+
const prevProps = prevPropsRef.current;
|
|
828
|
+
prevPropsRef.current = resolvedProps;
|
|
829
|
+
if (!isMountedRef.current) {
|
|
830
|
+
// the update handling must not run for the initial render
|
|
831
|
+
isMountedRef.current = true;
|
|
483
832
|
return;
|
|
484
833
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
});
|
|
491
|
-
this.reinitialize(newExecution);
|
|
492
|
-
}
|
|
493
|
-
};
|
|
494
|
-
onMenuAggregationClick = (menuAggregationClickConfig) => {
|
|
495
|
-
this.aggregationEventHandlers.onMenuAggregationClick(menuAggregationClickConfig);
|
|
496
|
-
};
|
|
497
|
-
onLoadingChanged = (loadingState) => {
|
|
498
|
-
this.dataLoadingEventHandlers.onLoadingChanged(loadingState);
|
|
499
|
-
};
|
|
500
|
-
onError = (error, execution = this.props.execution) => {
|
|
501
|
-
this.dataLoadingEventHandlers.onError(error, execution);
|
|
502
|
-
};
|
|
503
|
-
//
|
|
504
|
-
// Table resizing
|
|
505
|
-
//
|
|
506
|
-
growToFit = () => {
|
|
507
|
-
invariant(this.internal.table);
|
|
508
|
-
if (!this.isGrowToFitEnabled()) {
|
|
834
|
+
handleUpdate(prevProps);
|
|
835
|
+
});
|
|
836
|
+
// drain the setState callbacks; they run right after the commit of the state update that registered them
|
|
837
|
+
useLayoutEffect(() => {
|
|
838
|
+
if (committedStateUpdateCallbacks.current.length === 0) {
|
|
509
839
|
return;
|
|
510
840
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
};
|
|
518
|
-
autoresizeColumns = async (force = false) => {
|
|
519
|
-
if (this.state.resized && !force) {
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
const didResize = await this.internal.table?.autoresizeColumns(this.getResizingConfig(), force);
|
|
523
|
-
if (didResize) {
|
|
524
|
-
// after column resizing, horizontal scroolbar may change and table height may need resizing
|
|
525
|
-
this.updateDesiredHeight();
|
|
526
|
-
}
|
|
527
|
-
if (didResize && !this.state.resized) {
|
|
528
|
-
this.setState({
|
|
529
|
-
resized: true,
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
};
|
|
533
|
-
shouldAutoResizeColumns = () => {
|
|
534
|
-
return this.configDelegates.shouldAutoResizeColumns();
|
|
535
|
-
};
|
|
536
|
-
startWatchingTableRendered = () => {
|
|
537
|
-
if (!this.internal.table) {
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
const missingContainerRef = !this.containerRef; // table having no data will be unmounted, it causes ref null
|
|
541
|
-
const isTableRendered = this.shouldAutoResizeColumns()
|
|
542
|
-
? this.state.resized
|
|
543
|
-
: this.internal.table.isPivotTableReady();
|
|
544
|
-
const shouldCallAutoresizeColumns = this.internal.table.isPivotTableReady() &&
|
|
545
|
-
!this.state.resized &&
|
|
546
|
-
!this.internal.table.isResizing();
|
|
547
|
-
if (this.shouldAutoResizeColumns() && shouldCallAutoresizeColumns) {
|
|
548
|
-
void this.autoresizeColumns();
|
|
549
|
-
}
|
|
550
|
-
if (missingContainerRef || isTableRendered) {
|
|
551
|
-
this.stopWatchingTableRendered();
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
stopWatchingTableRendered = () => {
|
|
555
|
-
this.internal.stopWatching();
|
|
556
|
-
this.props.afterRender();
|
|
557
|
-
};
|
|
558
|
-
//
|
|
559
|
-
// Sticky row handling - delegated to StickyRowManager
|
|
560
|
-
//
|
|
561
|
-
updateStickyRow = () => {
|
|
562
|
-
this.stickyRowManager.updateStickyRow();
|
|
563
|
-
};
|
|
564
|
-
updateStickyRowContent = (scrollPosition) => {
|
|
565
|
-
this.stickyRowManager.updateStickyRowContent(scrollPosition);
|
|
566
|
-
};
|
|
567
|
-
//
|
|
568
|
-
// Desired height updating - delegated to HeightCalculationManager
|
|
569
|
-
//
|
|
570
|
-
updateDesiredHeight = () => {
|
|
571
|
-
this.heightCalculationManager.updateDesiredHeight();
|
|
572
|
-
};
|
|
573
|
-
//
|
|
574
|
-
// Initialize config accessors
|
|
575
|
-
//
|
|
576
|
-
initializeConfigAccessors = () => {
|
|
577
|
-
this.configAccessors = new TableConfigAccessors({
|
|
578
|
-
props: this.props,
|
|
579
|
-
state: this.state,
|
|
580
|
-
});
|
|
581
|
-
this.configDelegates = createConfigDelegates(this.configAccessors);
|
|
582
|
-
// Initialize sticky row manager
|
|
583
|
-
this.stickyRowManager = new StickyRowManager({
|
|
584
|
-
internal: this.internal,
|
|
585
|
-
props: this.props,
|
|
586
|
-
state: this.state,
|
|
587
|
-
getGroupRows: this.getGroupRows,
|
|
588
|
-
});
|
|
589
|
-
// Initialize height calculation manager
|
|
590
|
-
this.heightCalculationManager = new HeightCalculationManager({
|
|
591
|
-
internal: this.internal,
|
|
592
|
-
props: this.props,
|
|
593
|
-
state: this.state,
|
|
594
|
-
setState: (state, callback) => {
|
|
595
|
-
this.setState(state, callback);
|
|
596
|
-
},
|
|
597
|
-
getContainerRef: () => this.containerRef,
|
|
598
|
-
});
|
|
599
|
-
// Initialize component update analyzer
|
|
600
|
-
this.componentUpdateAnalyzer = new ComponentUpdateAnalyzer({
|
|
601
|
-
props: this.props,
|
|
602
|
-
state: this.state,
|
|
603
|
-
internal: this.internal,
|
|
604
|
-
executionAbortManager: this.executionAbortManager,
|
|
605
|
-
});
|
|
606
|
-
};
|
|
841
|
+
const callbacks = committedStateUpdateCallbacks.current;
|
|
842
|
+
committedStateUpdateCallbacks.current = [];
|
|
843
|
+
callbacks.forEach((callback) => callback());
|
|
844
|
+
});
|
|
607
845
|
//
|
|
608
|
-
//
|
|
846
|
+
// Render
|
|
609
847
|
//
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
};
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
getExecutionDefinition = () => this.configDelegates.getExecutionDefinition();
|
|
620
|
-
getGroupRows = () => this.configDelegates.getGroupRows();
|
|
621
|
-
getMeasureGroupDimension = () => this.configDelegates.getMeasureGroupDimension();
|
|
622
|
-
getColumnHeadersPosition = () => this.configDelegates.getColumnHeadersPosition();
|
|
623
|
-
getMenuConfig = () => this.configDelegates.getMenuConfig();
|
|
624
|
-
getDefaultWidth = () => this.configDelegates.getDefaultWidth();
|
|
625
|
-
isColumnAutoresizeEnabled = () => this.configDelegates.isColumnAutoresizeEnabled();
|
|
626
|
-
isGrowToFitEnabled = (props = this.props) => this.configDelegates.isGrowToFitEnabled(props);
|
|
627
|
-
getColumnWidths = (props) => this.configDelegates.getColumnWidths(props);
|
|
628
|
-
hasColumnWidths = () => this.configDelegates.hasColumnWidths();
|
|
629
|
-
getDefaultWidthFromProps = (props) => this.configDelegates.getDefaultWidthFromProps(props);
|
|
630
|
-
/**
|
|
631
|
-
* All pushData calls done by the table must go through this guard.
|
|
632
|
-
*
|
|
633
|
-
* TODO: The guard should ensure a 'disconnect' between push data handling and the calling function processing.
|
|
634
|
-
* When the pushData is handled by the application, it MAY (and in our case it DOES) trigger processing that
|
|
635
|
-
* lands back in the table. This opens additional set of invariants to check / be prepared for in order to
|
|
636
|
-
* optimize the renders and re-renders.
|
|
637
|
-
*/
|
|
638
|
-
pushDataGuard = (data) => {
|
|
639
|
-
this.props.pushData?.(data);
|
|
640
|
-
/*
|
|
641
|
-
* TODO: Switch to this on in FET-715.
|
|
642
|
-
setTimeout(() => {
|
|
643
|
-
this.props.pushData?.(data);
|
|
644
|
-
}, 0);
|
|
645
|
-
*/
|
|
848
|
+
const setContainerRef = useCallback((container) => {
|
|
849
|
+
containerRef.current = container ?? undefined;
|
|
850
|
+
if (containerRef.current) {
|
|
851
|
+
containerRef.current.addEventListener("mousedown", onContainerMouseDown);
|
|
852
|
+
}
|
|
853
|
+
}, [onContainerMouseDown]);
|
|
854
|
+
const renderLoading = () => {
|
|
855
|
+
const { LoadingComponent, theme } = resolvedProps;
|
|
856
|
+
return _jsx(PivotTableLoading, { LoadingComponent: LoadingComponent, theme: theme });
|
|
646
857
|
};
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
return createStateBoundCallback(callback, this.internal, () => this.internal);
|
|
858
|
+
const { ErrorComponent } = resolvedProps;
|
|
859
|
+
const { desiredHeight, error } = state;
|
|
860
|
+
if (error) {
|
|
861
|
+
return _jsx(PivotTableError, { error: error, errorMap: errorMap, ErrorComponent: ErrorComponent });
|
|
862
|
+
}
|
|
863
|
+
const style = {
|
|
864
|
+
height: desiredHeight || "100%",
|
|
865
|
+
position: "relative",
|
|
866
|
+
overflow: "hidden",
|
|
657
867
|
};
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
* https://github.com/ag-grid/ag-grid/issues/3334
|
|
868
|
+
if (!state.readyToRender) {
|
|
869
|
+
return (_jsx("div", { className: "gd-table-component", style: style, id: pivotTableId, children: renderLoading() }));
|
|
870
|
+
}
|
|
871
|
+
const internal = internalRef.current;
|
|
872
|
+
// when table is ready, then the table facade must be set. if this bombs then there is a bug
|
|
873
|
+
// in the initialization logic
|
|
874
|
+
invariant(internal.table);
|
|
875
|
+
if (!internal.gridOptions) {
|
|
876
|
+
internal.gridOptions = createGridOptions(internal.table, getTableMethods(), resolvedProps);
|
|
877
|
+
}
|
|
878
|
+
/*
|
|
879
|
+
* Show loading overlay until all the resizing is done. This is because the various resizing operations
|
|
880
|
+
* have to happen asynchronously - they must wait until ag-grid fires onFirstDataRendered, before our code
|
|
881
|
+
* can start reliably interfacing with the autosizing features.
|
|
674
882
|
*/
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
onGridColumnsChanged: this.stateBoundCallback(this.onGridColumnsChanged),
|
|
683
|
-
onGridColumnResized: this.stateBoundCallback(this.onGridColumnResized),
|
|
684
|
-
onSortChanged: this.stateBoundCallback(this.onSortChanged),
|
|
685
|
-
onGridSizeChanged: debouncedGridSizeChanged,
|
|
686
|
-
onPinnedRowDataChanged: this.stateBoundCallback(this.onPinnedRowDataChanged),
|
|
687
|
-
};
|
|
688
|
-
};
|
|
689
|
-
getTableMethods = () => {
|
|
690
|
-
return {
|
|
691
|
-
hasColumnWidths: this.hasColumnWidths(),
|
|
692
|
-
getExecutionDefinition: this.getExecutionDefinition,
|
|
693
|
-
getMenuConfig: this.getMenuConfig,
|
|
694
|
-
getGroupRows: this.getGroupRows,
|
|
695
|
-
getColumnTotals: this.getColumnTotals,
|
|
696
|
-
getRowTotals: this.getRowTotals,
|
|
697
|
-
getColumnHeadersPosition: this.getColumnHeadersPosition,
|
|
698
|
-
getMeasureGroupDimension: this.getMeasureGroupDimension,
|
|
699
|
-
getResizingConfig: this.getResizingConfig,
|
|
700
|
-
onLoadingChanged: this.onLoadingChanged,
|
|
701
|
-
onError: this.onError,
|
|
702
|
-
onExportReady: this.props.onExportReady ?? (() => { }),
|
|
703
|
-
pushData: this.pushDataGuard,
|
|
704
|
-
onPageLoaded: this.onPageLoaded,
|
|
705
|
-
onExecutionTransformed: this.onExecutionTransformed,
|
|
706
|
-
onMenuAggregationClick: this.onMenuAggregationClick,
|
|
707
|
-
setLastSortedColId: this.setLastSortedColId,
|
|
708
|
-
...this.boundAgGridCallbacks,
|
|
709
|
-
};
|
|
710
|
-
};
|
|
711
|
-
getResizingConfig = () => {
|
|
712
|
-
return {
|
|
713
|
-
defaultWidth: this.getDefaultWidth(),
|
|
714
|
-
growToFit: this.isGrowToFitEnabled(),
|
|
715
|
-
columnAutoresizeOption: this.getDefaultWidthFromProps(this.props),
|
|
716
|
-
widths: this.getColumnWidths(this.props),
|
|
717
|
-
isAltKeyPressed: this.internal.isAltKeyPressed,
|
|
718
|
-
isMetaOrCtrlKeyPressed: this.internal.isMetaOrCtrlKeyPressed,
|
|
719
|
-
// use clientWidth of the viewport container to accommodate for vertical scrollbars if needed
|
|
720
|
-
clientWidth: this.containerRef?.getElementsByClassName("ag-body-viewport")[0]?.clientWidth ?? 0,
|
|
721
|
-
containerRef: this.containerRef,
|
|
722
|
-
separators: this.props?.config?.separators,
|
|
723
|
-
onColumnResized: this.props.onColumnResized,
|
|
724
|
-
};
|
|
725
|
-
};
|
|
883
|
+
const shouldRenderLoadingOverlay = (isColumnAutoresizeEnabled() || isGrowToFitEnabled()) && !state.resized;
|
|
884
|
+
const classNames = cx("gd-table-component", {
|
|
885
|
+
"gd-table-header-hide": resolvedProps.config?.columnHeadersPosition === "left" &&
|
|
886
|
+
internal.table.tableDescriptor.isTransposed(),
|
|
887
|
+
});
|
|
888
|
+
return (_jsx("div", { className: classNames, style: style, id: pivotTableId, onMouseDown: stopEventWhenResizeHeader, onDragStart: stopEventWhenResizeHeader, children: _jsxs("div", { className: "gd-table ag-theme-balham s-pivot-table", style: style, ref: setContainerRef, children: [
|
|
889
|
+
_jsx(AgGridReact, { ...internal.gridOptions, modules: [AllCommunityModule] }), shouldRenderLoadingOverlay ? renderLoading() : null] }) }));
|
|
726
890
|
}
|
|
727
891
|
const CorePivotTableWithIntl = injectIntl(withTheme(CorePivotTableAgImpl));
|
|
728
892
|
/**
|