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