@ackplus/react-tanstack-data-table 1.1.12 → 1.1.13
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/README.md +143 -11
- package/dist/lib/components/droupdown/menu-dropdown.d.ts.map +1 -1
- package/dist/lib/components/droupdown/menu-dropdown.js +8 -1
- package/dist/lib/components/filters/filter-value-input.js +2 -2
- package/dist/lib/components/pagination/data-table-pagination.d.ts.map +1 -1
- package/dist/lib/components/pagination/data-table-pagination.js +10 -1
- package/dist/lib/components/toolbar/table-export-control.d.ts.map +1 -1
- package/dist/lib/components/toolbar/table-export-control.js +46 -12
- package/dist/lib/contexts/data-table-context.d.ts +7 -10
- package/dist/lib/contexts/data-table-context.d.ts.map +1 -1
- package/dist/lib/contexts/data-table-context.js +5 -1
- package/dist/lib/data-table.d.ts.map +1 -1
- package/dist/lib/data-table.js +561 -230
- package/dist/lib/features/column-filter.feature.js +38 -21
- package/dist/lib/features/selection.feature.d.ts.map +1 -1
- package/dist/lib/features/selection.feature.js +11 -3
- package/dist/lib/types/column.types.d.ts +19 -0
- package/dist/lib/types/column.types.d.ts.map +1 -1
- package/dist/lib/types/data-table-api.d.ts +24 -18
- package/dist/lib/types/data-table-api.d.ts.map +1 -1
- package/dist/lib/types/data-table.types.d.ts +36 -10
- package/dist/lib/types/data-table.types.d.ts.map +1 -1
- package/dist/lib/types/export.types.d.ts +57 -13
- package/dist/lib/types/export.types.d.ts.map +1 -1
- package/dist/lib/types/slots.types.d.ts +3 -1
- package/dist/lib/types/slots.types.d.ts.map +1 -1
- package/dist/lib/types/table.types.d.ts +1 -3
- package/dist/lib/types/table.types.d.ts.map +1 -1
- package/dist/lib/utils/debounced-fetch.utils.d.ts +8 -4
- package/dist/lib/utils/debounced-fetch.utils.d.ts.map +1 -1
- package/dist/lib/utils/debounced-fetch.utils.js +63 -14
- package/dist/lib/utils/export-utils.d.ts +14 -4
- package/dist/lib/utils/export-utils.d.ts.map +1 -1
- package/dist/lib/utils/export-utils.js +362 -66
- package/package.json +4 -2
- package/src/lib/components/droupdown/menu-dropdown.tsx +9 -3
- package/src/lib/components/filters/filter-value-input.tsx +2 -2
- package/src/lib/components/pagination/data-table-pagination.tsx +14 -2
- package/src/lib/components/toolbar/table-export-control.tsx +65 -9
- package/src/lib/contexts/data-table-context.tsx +16 -2
- package/src/lib/data-table.tsx +703 -222
- package/src/lib/features/column-filter.feature.ts +40 -19
- package/src/lib/features/selection.feature.ts +11 -5
- package/src/lib/types/column.types.ts +20 -1
- package/src/lib/types/data-table-api.ts +33 -15
- package/src/lib/types/data-table.types.ts +58 -3
- package/src/lib/types/export.types.ts +79 -10
- package/src/lib/types/slots.types.ts +3 -1
- package/src/lib/types/table.types.ts +1 -3
- package/src/lib/utils/debounced-fetch.utils.ts +90 -18
- package/src/lib/utils/export-utils.ts +496 -69
package/dist/lib/data-table.js
CHANGED
|
@@ -89,7 +89,7 @@ const DEFAULT_INITIAL_STATE = {
|
|
|
89
89
|
*/
|
|
90
90
|
exports.DataTable = (0, react_1.forwardRef)(function DataTable({ initialState, columns, data = [], totalRow = 0, idKey = 'id', extraFilter = null, footerFilter = null,
|
|
91
91
|
// Data management mode (MUI DataGrid style)
|
|
92
|
-
dataMode = 'client', initialLoadData = true, onFetchData, onDataStateChange,
|
|
92
|
+
dataMode = 'client', initialLoadData = true, onFetchData, onRefreshData, onDataChange, onDataStateChange,
|
|
93
93
|
// Selection props
|
|
94
94
|
enableRowSelection = false, enableMultiRowSelection = true, selectMode = 'page', isRowSelectable, onSelectionChange,
|
|
95
95
|
// Row click props
|
|
@@ -111,7 +111,7 @@ enablePagination = false, paginationMode = 'client',
|
|
|
111
111
|
// Filtering props
|
|
112
112
|
enableGlobalFilter = true, enableColumnFilter = false, filterMode = 'client',
|
|
113
113
|
// Sorting props
|
|
114
|
-
enableSorting = true, sortingMode = 'client', onSortingChange, exportFilename = 'export', onExportProgress, onExportComplete, onExportError, onServerExport, onExportCancel,
|
|
114
|
+
enableSorting = true, sortingMode = 'client', onSortingChange, exportFilename = 'export', exportConcurrency = 'cancelAndRestart', exportChunkSize = 1000, exportStrictTotalCheck = false, exportSanitizeCSV = true, onExportProgress, onExportComplete, onExportError, onServerExport, onExportCancel, onExportStateChange,
|
|
115
115
|
// Styling props
|
|
116
116
|
enableHover = true, enableStripes = false, tableProps = {}, fitToScreen = true, tableSize: initialTableSize = 'medium',
|
|
117
117
|
// Sticky header/footer props
|
|
@@ -184,14 +184,24 @@ logging, }, ref) {
|
|
|
184
184
|
const [serverData, setServerData] = (0, react_1.useState)(null);
|
|
185
185
|
const [serverTotal, setServerTotal] = (0, react_1.useState)(0);
|
|
186
186
|
const [exportController, setExportController] = (0, react_1.useState)(null);
|
|
187
|
+
const [exportProgress, setExportProgress] = (0, react_1.useState)({});
|
|
188
|
+
const [exportPhase, setExportPhase] = (0, react_1.useState)(null);
|
|
189
|
+
const [queuedExportCount, setQueuedExportCount] = (0, react_1.useState)(0);
|
|
187
190
|
// -------------------------------
|
|
188
191
|
// Ref hooks (grouped together)
|
|
189
192
|
// -------------------------------
|
|
190
193
|
const tableContainerRef = (0, react_1.useRef)(null);
|
|
191
194
|
const internalApiRef = (0, react_1.useRef)(null);
|
|
195
|
+
const exportControllerRef = (0, react_1.useRef)(null);
|
|
196
|
+
const exportQueueRef = (0, react_1.useRef)(Promise.resolve());
|
|
197
|
+
const isExternallyControlledData = (0, react_1.useMemo)(() => !onFetchData && (!!onDataChange || !!onRefreshData), [onFetchData, onDataChange, onRefreshData]);
|
|
192
198
|
const { debouncedFetch, isLoading: fetchLoading } = (0, debounced_fetch_utils_1.useDebouncedFetch)(onFetchData);
|
|
193
|
-
const tableData = (0, react_1.useMemo)(() =>
|
|
194
|
-
|
|
199
|
+
const tableData = (0, react_1.useMemo)(() => {
|
|
200
|
+
if (isExternallyControlledData)
|
|
201
|
+
return data;
|
|
202
|
+
return serverData !== null ? serverData : data;
|
|
203
|
+
}, [isExternallyControlledData, serverData, data]);
|
|
204
|
+
const tableTotalRow = (0, react_1.useMemo)(() => (isExternallyControlledData ? (totalRow || data.length) : (serverData !== null ? serverTotal : totalRow || data.length)), [isExternallyControlledData, serverData, serverTotal, totalRow, data]);
|
|
195
205
|
const tableLoading = (0, react_1.useMemo)(() => onFetchData ? (loading || fetchLoading) : loading, [onFetchData, loading, fetchLoading]);
|
|
196
206
|
const enhancedColumns = (0, react_1.useMemo)(() => {
|
|
197
207
|
let columnsMap = [...columns];
|
|
@@ -239,7 +249,7 @@ logging, }, ref) {
|
|
|
239
249
|
// Callback hooks (grouped together)
|
|
240
250
|
// -------------------------------
|
|
241
251
|
const fetchData = (0, react_1.useCallback)(async (overrides = {}, options) => {
|
|
242
|
-
var _a, _b, _c;
|
|
252
|
+
var _a, _b, _c, _d, _e;
|
|
243
253
|
if (!onFetchData) {
|
|
244
254
|
if (logger.isLevelEnabled('debug')) {
|
|
245
255
|
logger.debug('onFetchData not provided, skipping fetch', { overrides, columnFilter, sorting, pagination });
|
|
@@ -253,20 +263,26 @@ logging, }, ref) {
|
|
|
253
263
|
sorting,
|
|
254
264
|
...overrides,
|
|
255
265
|
};
|
|
256
|
-
console.log('Fetching data', filters);
|
|
257
266
|
if (logger.isLevelEnabled('info')) {
|
|
258
|
-
logger.info('Requesting data', {
|
|
267
|
+
logger.info('Requesting data', {
|
|
268
|
+
filters,
|
|
269
|
+
reason: (_a = options === null || options === void 0 ? void 0 : options.meta) === null || _a === void 0 ? void 0 : _a.reason,
|
|
270
|
+
force: (_b = options === null || options === void 0 ? void 0 : options.meta) === null || _b === void 0 ? void 0 : _b.force,
|
|
271
|
+
});
|
|
259
272
|
}
|
|
260
273
|
try {
|
|
261
|
-
const delay = (
|
|
262
|
-
const result = await debouncedFetch(filters,
|
|
274
|
+
const delay = (_c = options === null || options === void 0 ? void 0 : options.delay) !== null && _c !== void 0 ? _c : 300; // respects 0
|
|
275
|
+
const result = await debouncedFetch(filters, {
|
|
276
|
+
debounceDelay: delay,
|
|
277
|
+
meta: options === null || options === void 0 ? void 0 : options.meta,
|
|
278
|
+
});
|
|
263
279
|
if (logger.isLevelEnabled('info')) {
|
|
264
280
|
logger.info('Fetch resolved', {
|
|
265
|
-
rows: (
|
|
281
|
+
rows: (_e = (_d = result === null || result === void 0 ? void 0 : result.data) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0,
|
|
266
282
|
total: result === null || result === void 0 ? void 0 : result.total,
|
|
267
283
|
});
|
|
268
284
|
}
|
|
269
|
-
if (
|
|
285
|
+
if (result && Array.isArray(result.data) && result.total !== undefined) {
|
|
270
286
|
setServerData(result.data);
|
|
271
287
|
setServerTotal(result.total);
|
|
272
288
|
}
|
|
@@ -288,6 +304,21 @@ logging, }, ref) {
|
|
|
288
304
|
debouncedFetch,
|
|
289
305
|
logger,
|
|
290
306
|
]);
|
|
307
|
+
const normalizeRefreshOptions = (0, react_1.useCallback)((options, fallbackReason = 'refresh') => {
|
|
308
|
+
var _a, _b, _c;
|
|
309
|
+
if (typeof options === 'boolean') {
|
|
310
|
+
return {
|
|
311
|
+
resetPagination: options,
|
|
312
|
+
force: false,
|
|
313
|
+
reason: fallbackReason,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
resetPagination: (_a = options === null || options === void 0 ? void 0 : options.resetPagination) !== null && _a !== void 0 ? _a : false,
|
|
318
|
+
force: (_b = options === null || options === void 0 ? void 0 : options.force) !== null && _b !== void 0 ? _b : false,
|
|
319
|
+
reason: (_c = options === null || options === void 0 ? void 0 : options.reason) !== null && _c !== void 0 ? _c : fallbackReason,
|
|
320
|
+
};
|
|
321
|
+
}, []);
|
|
291
322
|
const handleSelectionStateChange = (0, react_1.useCallback)((updaterOrValue) => {
|
|
292
323
|
setSelectionState((prevState) => {
|
|
293
324
|
const next = typeof updaterOrValue === 'function' ? updaterOrValue(prevState) : updaterOrValue;
|
|
@@ -525,12 +556,21 @@ logging, }, ref) {
|
|
|
525
556
|
// -------------------------------
|
|
526
557
|
// Effects (after callbacks)
|
|
527
558
|
// -------------------------------
|
|
559
|
+
(0, react_1.useEffect)(() => {
|
|
560
|
+
if (!isExternallyControlledData || serverData === null)
|
|
561
|
+
return;
|
|
562
|
+
setServerData(null);
|
|
563
|
+
setServerTotal(0);
|
|
564
|
+
}, [isExternallyControlledData, serverData]);
|
|
528
565
|
(0, react_1.useEffect)(() => {
|
|
529
566
|
if (initialLoadData && onFetchData) {
|
|
530
567
|
if (logger.isLevelEnabled('info')) {
|
|
531
568
|
logger.info('Initial data load triggered', { initialLoadData });
|
|
532
569
|
}
|
|
533
|
-
fetchData({}
|
|
570
|
+
fetchData({}, {
|
|
571
|
+
delay: 0,
|
|
572
|
+
meta: { reason: 'initial' },
|
|
573
|
+
});
|
|
534
574
|
}
|
|
535
575
|
else if (logger.isLevelEnabled('debug')) {
|
|
536
576
|
logger.debug('Skipping initial data load', {
|
|
@@ -559,12 +599,13 @@ logging, }, ref) {
|
|
|
559
599
|
if (!onDataStateChange)
|
|
560
600
|
return;
|
|
561
601
|
const live = table.getState();
|
|
602
|
+
const liveColumnFilter = live.columnFilter;
|
|
562
603
|
// only keep what you persist/store
|
|
563
604
|
const payload = {
|
|
564
605
|
sorting: live.sorting,
|
|
565
606
|
pagination: live.pagination,
|
|
566
607
|
globalFilter: live.globalFilter,
|
|
567
|
-
columnFilter:
|
|
608
|
+
columnFilter: liveColumnFilter,
|
|
568
609
|
columnVisibility: live.columnVisibility,
|
|
569
610
|
columnSizing: live.columnSizing,
|
|
570
611
|
columnOrder: live.columnOrder,
|
|
@@ -593,7 +634,7 @@ logging, }, ref) {
|
|
|
593
634
|
var _a;
|
|
594
635
|
const resetSorting = initialStateConfig.sorting || [];
|
|
595
636
|
const resetGlobalFilter = (_a = initialStateConfig.globalFilter) !== null && _a !== void 0 ? _a : '';
|
|
596
|
-
const resetColumnFilter = initialStateConfig.columnFilter
|
|
637
|
+
const resetColumnFilter = initialStateConfig.columnFilter;
|
|
597
638
|
const resetPagination = enablePagination
|
|
598
639
|
? (initialStateConfig.pagination || { pageIndex: 0, pageSize: 10 })
|
|
599
640
|
: undefined;
|
|
@@ -604,14 +645,109 @@ logging, }, ref) {
|
|
|
604
645
|
...(resetPagination ? { pagination: resetPagination } : {}),
|
|
605
646
|
};
|
|
606
647
|
}, [initialStateConfig, enablePagination]);
|
|
648
|
+
const applyDataMutation = (0, react_1.useCallback)((action, updater, details = {}) => {
|
|
649
|
+
const previousData = [...tableData];
|
|
650
|
+
const nextData = updater(previousData);
|
|
651
|
+
if (nextData === previousData)
|
|
652
|
+
return nextData;
|
|
653
|
+
const nextTotal = Math.max(0, tableTotalRow + (nextData.length - previousData.length));
|
|
654
|
+
if (!isExternallyControlledData) {
|
|
655
|
+
setServerData(nextData);
|
|
656
|
+
setServerTotal(nextTotal);
|
|
657
|
+
}
|
|
658
|
+
onDataChange === null || onDataChange === void 0 ? void 0 : onDataChange(nextData, {
|
|
659
|
+
action,
|
|
660
|
+
previousData,
|
|
661
|
+
nextData,
|
|
662
|
+
totalRow: nextTotal,
|
|
663
|
+
...details,
|
|
664
|
+
});
|
|
665
|
+
if (logger.isLevelEnabled('debug')) {
|
|
666
|
+
logger.debug('Applied data mutation', {
|
|
667
|
+
action,
|
|
668
|
+
previousCount: previousData.length,
|
|
669
|
+
nextCount: nextData.length,
|
|
670
|
+
totalRow: nextTotal,
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
return nextData;
|
|
674
|
+
}, [isExternallyControlledData, logger, onDataChange, tableData, tableTotalRow]);
|
|
675
|
+
const buildRefreshContext = (0, react_1.useCallback)((options, paginationOverride) => {
|
|
676
|
+
const state = table.getState();
|
|
677
|
+
const nextPagination = paginationOverride || state.pagination || pagination;
|
|
678
|
+
return {
|
|
679
|
+
filters: {
|
|
680
|
+
globalFilter,
|
|
681
|
+
pagination: nextPagination,
|
|
682
|
+
columnFilter,
|
|
683
|
+
sorting,
|
|
684
|
+
},
|
|
685
|
+
state: {
|
|
686
|
+
sorting,
|
|
687
|
+
pagination: nextPagination,
|
|
688
|
+
globalFilter,
|
|
689
|
+
columnFilter,
|
|
690
|
+
columnVisibility: state.columnVisibility,
|
|
691
|
+
columnSizing: state.columnSizing,
|
|
692
|
+
columnOrder: state.columnOrder,
|
|
693
|
+
columnPinning: state.columnPinning,
|
|
694
|
+
},
|
|
695
|
+
options,
|
|
696
|
+
};
|
|
697
|
+
}, [table, pagination, globalFilter, columnFilter, sorting]);
|
|
698
|
+
const triggerRefresh = (0, react_1.useCallback)(async (options, fallbackReason = 'refresh') => {
|
|
699
|
+
const normalizedOptions = normalizeRefreshOptions(options, fallbackReason);
|
|
700
|
+
const nextPagination = enablePagination
|
|
701
|
+
? {
|
|
702
|
+
pageIndex: normalizedOptions.resetPagination ? 0 : pagination.pageIndex,
|
|
703
|
+
pageSize: pagination.pageSize,
|
|
704
|
+
}
|
|
705
|
+
: undefined;
|
|
706
|
+
const shouldUpdatePagination = !!nextPagination
|
|
707
|
+
&& (nextPagination.pageIndex !== pagination.pageIndex || nextPagination.pageSize !== pagination.pageSize);
|
|
708
|
+
if (nextPagination && shouldUpdatePagination) {
|
|
709
|
+
setPagination(nextPagination);
|
|
710
|
+
onPaginationChange === null || onPaginationChange === void 0 ? void 0 : onPaginationChange(nextPagination);
|
|
711
|
+
}
|
|
712
|
+
const refreshContext = buildRefreshContext(normalizedOptions, nextPagination);
|
|
713
|
+
if (onRefreshData) {
|
|
714
|
+
await onRefreshData(refreshContext);
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
if (onFetchData) {
|
|
718
|
+
await fetchData(nextPagination ? { pagination: nextPagination } : {}, {
|
|
719
|
+
delay: 0,
|
|
720
|
+
meta: {
|
|
721
|
+
reason: normalizedOptions.reason,
|
|
722
|
+
force: normalizedOptions.force,
|
|
723
|
+
},
|
|
724
|
+
});
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
if (logger.isLevelEnabled('debug')) {
|
|
728
|
+
logger.debug('Refresh skipped because no refresh handler is configured', refreshContext);
|
|
729
|
+
}
|
|
730
|
+
}, [
|
|
731
|
+
normalizeRefreshOptions,
|
|
732
|
+
enablePagination,
|
|
733
|
+
pagination,
|
|
734
|
+
onPaginationChange,
|
|
735
|
+
buildRefreshContext,
|
|
736
|
+
onRefreshData,
|
|
737
|
+
onFetchData,
|
|
738
|
+
fetchData,
|
|
739
|
+
logger,
|
|
740
|
+
]);
|
|
607
741
|
const resetAllAndReload = (0, react_1.useCallback)(() => {
|
|
608
742
|
var _a;
|
|
609
743
|
const resetState = getResetState();
|
|
610
744
|
setSorting(resetState.sorting || []);
|
|
611
745
|
setGlobalFilter((_a = resetState.globalFilter) !== null && _a !== void 0 ? _a : '');
|
|
612
746
|
setColumnFilter(resetState.columnFilter);
|
|
613
|
-
if (resetState.pagination)
|
|
747
|
+
if (resetState.pagination) {
|
|
614
748
|
setPagination(resetState.pagination);
|
|
749
|
+
onPaginationChange === null || onPaginationChange === void 0 ? void 0 : onPaginationChange(resetState.pagination);
|
|
750
|
+
}
|
|
615
751
|
setSelectionState(initialSelectionState);
|
|
616
752
|
setExpanded({});
|
|
617
753
|
// layout state
|
|
@@ -619,9 +755,114 @@ logging, }, ref) {
|
|
|
619
755
|
setColumnSizing(initialStateConfig.columnSizing || {});
|
|
620
756
|
setColumnOrder(initialStateConfig.columnOrder || []);
|
|
621
757
|
setColumnPinning(initialStateConfig.columnPinning || { left: [], right: [] });
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
758
|
+
const resetOptions = normalizeRefreshOptions({
|
|
759
|
+
resetPagination: true,
|
|
760
|
+
force: true,
|
|
761
|
+
reason: 'reset',
|
|
762
|
+
}, 'reset');
|
|
763
|
+
const refreshContext = buildRefreshContext(resetOptions, resetState.pagination);
|
|
764
|
+
if (onRefreshData) {
|
|
765
|
+
void onRefreshData(refreshContext);
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
if (onFetchData) {
|
|
769
|
+
void fetchData(resetState, {
|
|
770
|
+
delay: 0,
|
|
771
|
+
meta: {
|
|
772
|
+
reason: resetOptions.reason,
|
|
773
|
+
force: resetOptions.force,
|
|
774
|
+
},
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
}, [
|
|
778
|
+
getResetState,
|
|
779
|
+
initialSelectionState,
|
|
780
|
+
initialStateConfig,
|
|
781
|
+
onPaginationChange,
|
|
782
|
+
normalizeRefreshOptions,
|
|
783
|
+
buildRefreshContext,
|
|
784
|
+
onRefreshData,
|
|
785
|
+
onFetchData,
|
|
786
|
+
fetchData,
|
|
787
|
+
]);
|
|
788
|
+
const setExportControllerSafely = (0, react_1.useCallback)((value) => {
|
|
789
|
+
setExportController((current) => {
|
|
790
|
+
const next = typeof value === 'function' ? value(current) : value;
|
|
791
|
+
exportControllerRef.current = next;
|
|
792
|
+
return next;
|
|
793
|
+
});
|
|
794
|
+
}, []);
|
|
795
|
+
const handleExportProgressInternal = (0, react_1.useCallback)((progress) => {
|
|
796
|
+
setExportProgress(progress || {});
|
|
797
|
+
onExportProgress === null || onExportProgress === void 0 ? void 0 : onExportProgress(progress);
|
|
798
|
+
}, [onExportProgress]);
|
|
799
|
+
const handleExportStateChangeInternal = (0, react_1.useCallback)((state) => {
|
|
800
|
+
setExportPhase(state.phase);
|
|
801
|
+
if (state.processedRows !== undefined
|
|
802
|
+
|| state.totalRows !== undefined
|
|
803
|
+
|| state.percentage !== undefined) {
|
|
804
|
+
setExportProgress({
|
|
805
|
+
processedRows: state.processedRows,
|
|
806
|
+
totalRows: state.totalRows,
|
|
807
|
+
percentage: state.percentage,
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
onExportStateChange === null || onExportStateChange === void 0 ? void 0 : onExportStateChange(state);
|
|
811
|
+
}, [onExportStateChange]);
|
|
812
|
+
const runExportWithPolicy = (0, react_1.useCallback)(async (options) => {
|
|
813
|
+
const { format, filename, mode, execute } = options;
|
|
814
|
+
const startExecution = async () => {
|
|
815
|
+
const controller = new AbortController();
|
|
816
|
+
setExportProgress({});
|
|
817
|
+
setExportControllerSafely(controller);
|
|
818
|
+
try {
|
|
819
|
+
await execute(controller);
|
|
820
|
+
}
|
|
821
|
+
finally {
|
|
822
|
+
setExportControllerSafely((current) => (current === controller ? null : current));
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
if (exportConcurrency === 'queue') {
|
|
826
|
+
setQueuedExportCount((prev) => prev + 1);
|
|
827
|
+
const runQueued = async () => {
|
|
828
|
+
setQueuedExportCount((prev) => Math.max(0, prev - 1));
|
|
829
|
+
await startExecution();
|
|
830
|
+
};
|
|
831
|
+
const queuedPromise = exportQueueRef.current
|
|
832
|
+
.catch(() => undefined)
|
|
833
|
+
.then(runQueued);
|
|
834
|
+
exportQueueRef.current = queuedPromise;
|
|
835
|
+
return queuedPromise;
|
|
836
|
+
}
|
|
837
|
+
const activeController = exportControllerRef.current;
|
|
838
|
+
if (activeController) {
|
|
839
|
+
if (exportConcurrency === 'ignoreIfRunning') {
|
|
840
|
+
handleExportStateChangeInternal({
|
|
841
|
+
phase: 'error',
|
|
842
|
+
mode,
|
|
843
|
+
format,
|
|
844
|
+
filename,
|
|
845
|
+
message: 'An export is already running',
|
|
846
|
+
code: 'EXPORT_IN_PROGRESS',
|
|
847
|
+
endedAt: Date.now(),
|
|
848
|
+
});
|
|
849
|
+
onExportError === null || onExportError === void 0 ? void 0 : onExportError({
|
|
850
|
+
message: 'An export is already running',
|
|
851
|
+
code: 'EXPORT_IN_PROGRESS',
|
|
852
|
+
});
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (exportConcurrency === 'cancelAndRestart') {
|
|
856
|
+
activeController.abort();
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
await startExecution();
|
|
860
|
+
}, [
|
|
861
|
+
exportConcurrency,
|
|
862
|
+
handleExportStateChangeInternal,
|
|
863
|
+
onExportError,
|
|
864
|
+
setExportControllerSafely,
|
|
865
|
+
]);
|
|
625
866
|
const dataTableApi = (0, react_1.useMemo)(() => {
|
|
626
867
|
// helpers (avoid repeating boilerplate)
|
|
627
868
|
const buildInitialOrder = () => enhancedColumns.map((col, index) => {
|
|
@@ -654,6 +895,12 @@ logging, }, ref) {
|
|
|
654
895
|
const applyGlobalFilter = (next) => {
|
|
655
896
|
handleGlobalFilterChange(next);
|
|
656
897
|
};
|
|
898
|
+
const getRowIndexById = (rowsToSearch, rowId) => rowsToSearch.findIndex((row, index) => String((0, utils_1.generateRowId)(row, index, idKey)) === rowId);
|
|
899
|
+
const clampInsertIndex = (rowsToMutate, insertIndex) => {
|
|
900
|
+
if (insertIndex === undefined)
|
|
901
|
+
return rowsToMutate.length;
|
|
902
|
+
return Math.max(0, Math.min(insertIndex, rowsToMutate.length));
|
|
903
|
+
};
|
|
657
904
|
return {
|
|
658
905
|
table: {
|
|
659
906
|
getTable: () => table,
|
|
@@ -935,129 +1182,135 @@ logging, }, ref) {
|
|
|
935
1182
|
// Data Management (kept same, but ensure state changes go through handlers)
|
|
936
1183
|
// -------------------------------
|
|
937
1184
|
data: {
|
|
938
|
-
refresh: (
|
|
939
|
-
|
|
940
|
-
const allState = table.getState();
|
|
941
|
-
const current = allState.pagination;
|
|
942
|
-
const nextPagination = {
|
|
943
|
-
pageIndex: resetPagination ? 0 : (_a = current === null || current === void 0 ? void 0 : current.pageIndex) !== null && _a !== void 0 ? _a : 0,
|
|
944
|
-
pageSize: (_d = (_b = current === null || current === void 0 ? void 0 : current.pageSize) !== null && _b !== void 0 ? _b : (_c = initialStateConfig.pagination) === null || _c === void 0 ? void 0 : _c.pageSize) !== null && _d !== void 0 ? _d : 10,
|
|
945
|
-
};
|
|
946
|
-
// must go through handler so server fetch triggers
|
|
947
|
-
applyPagination(nextPagination);
|
|
948
|
-
// emit persisted state (your emitTableState effect will also do it)
|
|
949
|
-
onDataStateChange === null || onDataStateChange === void 0 ? void 0 : onDataStateChange({ ...allState, pagination: nextPagination });
|
|
950
|
-
fetchData === null || fetchData === void 0 ? void 0 : fetchData({ pagination: nextPagination });
|
|
951
|
-
if (logger.isLevelEnabled("debug")) {
|
|
952
|
-
logger.debug("Refreshing data", { nextPagination, allState });
|
|
953
|
-
}
|
|
1185
|
+
refresh: (options) => {
|
|
1186
|
+
void triggerRefresh(options, 'refresh');
|
|
954
1187
|
},
|
|
955
|
-
reload: () => {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
}
|
|
1188
|
+
reload: (options = {}) => {
|
|
1189
|
+
var _a, _b;
|
|
1190
|
+
void triggerRefresh({
|
|
1191
|
+
...options,
|
|
1192
|
+
resetPagination: (_a = options.resetPagination) !== null && _a !== void 0 ? _a : false,
|
|
1193
|
+
reason: (_b = options.reason) !== null && _b !== void 0 ? _b : 'reload',
|
|
1194
|
+
}, 'reload');
|
|
962
1195
|
},
|
|
963
|
-
resetAll: () => resetAllAndReload(
|
|
964
|
-
getAllData: () =>
|
|
965
|
-
getRowData: (rowId) => {
|
|
966
|
-
|
|
1196
|
+
resetAll: () => resetAllAndReload(),
|
|
1197
|
+
getAllData: () => [...tableData],
|
|
1198
|
+
getRowData: (rowId) => {
|
|
1199
|
+
const rowIndex = getRowIndexById(tableData, rowId);
|
|
1200
|
+
return rowIndex === -1 ? undefined : tableData[rowIndex];
|
|
1201
|
+
},
|
|
1202
|
+
getRowByIndex: (index) => tableData[index],
|
|
967
1203
|
updateRow: (rowId, updates) => {
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1204
|
+
applyDataMutation('updateRow', (rowsToMutate) => {
|
|
1205
|
+
const rowIndex = getRowIndexById(rowsToMutate, rowId);
|
|
1206
|
+
if (rowIndex === -1)
|
|
1207
|
+
return rowsToMutate;
|
|
1208
|
+
const nextData = [...rowsToMutate];
|
|
1209
|
+
nextData[rowIndex] = { ...nextData[rowIndex], ...updates };
|
|
1210
|
+
return nextData;
|
|
1211
|
+
}, { rowId });
|
|
973
1212
|
},
|
|
974
1213
|
updateRowByIndex: (index, updates) => {
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
}
|
|
1214
|
+
applyDataMutation('updateRowByIndex', (rowsToMutate) => {
|
|
1215
|
+
if (!rowsToMutate[index])
|
|
1216
|
+
return rowsToMutate;
|
|
1217
|
+
const nextData = [...rowsToMutate];
|
|
1218
|
+
nextData[index] = { ...nextData[index], ...updates };
|
|
1219
|
+
return nextData;
|
|
1220
|
+
}, { index });
|
|
983
1221
|
},
|
|
984
1222
|
insertRow: (newRow, index) => {
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
newData.push(newRow);
|
|
991
|
-
setServerData(newData || []);
|
|
992
|
-
if (logger.isLevelEnabled("debug"))
|
|
993
|
-
logger.debug("Inserting row", newRow);
|
|
1223
|
+
applyDataMutation('insertRow', (rowsToMutate) => {
|
|
1224
|
+
const nextData = [...rowsToMutate];
|
|
1225
|
+
nextData.splice(clampInsertIndex(nextData, index), 0, newRow);
|
|
1226
|
+
return nextData;
|
|
1227
|
+
}, { index });
|
|
994
1228
|
},
|
|
995
1229
|
deleteRow: (rowId) => {
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1230
|
+
applyDataMutation('deleteRow', (rowsToMutate) => {
|
|
1231
|
+
const rowIndex = getRowIndexById(rowsToMutate, rowId);
|
|
1232
|
+
if (rowIndex === -1)
|
|
1233
|
+
return rowsToMutate;
|
|
1234
|
+
const nextData = [...rowsToMutate];
|
|
1235
|
+
nextData.splice(rowIndex, 1);
|
|
1236
|
+
return nextData;
|
|
1237
|
+
}, { rowId });
|
|
1000
1238
|
},
|
|
1001
1239
|
deleteRowByIndex: (index) => {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1240
|
+
applyDataMutation('deleteRowByIndex', (rowsToMutate) => {
|
|
1241
|
+
if (index < 0 || index >= rowsToMutate.length)
|
|
1242
|
+
return rowsToMutate;
|
|
1243
|
+
const nextData = [...rowsToMutate];
|
|
1244
|
+
nextData.splice(index, 1);
|
|
1245
|
+
return nextData;
|
|
1246
|
+
}, { index });
|
|
1007
1247
|
},
|
|
1008
1248
|
deleteSelectedRows: () => {
|
|
1009
|
-
var _a, _b;
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1249
|
+
var _a, _b, _c;
|
|
1250
|
+
const currentSelection = ((_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table)) || selectionState;
|
|
1251
|
+
const selectedIds = new Set((currentSelection.ids || []).map((id) => String(id)));
|
|
1252
|
+
const loadedRowIds = tableData.map((row, index) => String((0, utils_1.generateRowId)(row, index, idKey)));
|
|
1253
|
+
const deletableRowIds = currentSelection.type === 'exclude'
|
|
1254
|
+
? loadedRowIds.filter((rowId) => !selectedIds.has(rowId))
|
|
1255
|
+
: loadedRowIds.filter((rowId) => selectedIds.has(rowId));
|
|
1256
|
+
if (deletableRowIds.length === 0)
|
|
1012
1257
|
return;
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
.
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1258
|
+
if (currentSelection.type === 'exclude'
|
|
1259
|
+
&& table.getRowCount() > loadedRowIds.length
|
|
1260
|
+
&& logger.isLevelEnabled('info')) {
|
|
1261
|
+
logger.info('deleteSelectedRows in exclude mode removed currently loaded rows only', {
|
|
1262
|
+
removedRows: deletableRowIds.length,
|
|
1263
|
+
totalSelected: (_b = table.getSelectedCount) === null || _b === void 0 ? void 0 : _b.call(table),
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
const deletableRowIdSet = new Set(deletableRowIds);
|
|
1267
|
+
applyDataMutation('deleteSelectedRows', (rowsToMutate) => rowsToMutate.filter((row, index) => !deletableRowIdSet.has(String((0, utils_1.generateRowId)(row, index, idKey)))), { rowIds: deletableRowIds });
|
|
1268
|
+
(_c = table.deselectAll) === null || _c === void 0 ? void 0 : _c.call(table);
|
|
1269
|
+
},
|
|
1270
|
+
replaceAllData: (newData) => {
|
|
1271
|
+
applyDataMutation('replaceAllData', () => [...newData]);
|
|
1021
1272
|
},
|
|
1022
|
-
replaceAllData: (newData) => setServerData === null || setServerData === void 0 ? void 0 : setServerData(newData),
|
|
1023
1273
|
updateMultipleRows: (updates) => {
|
|
1024
|
-
const updateMap = new Map(updates.map((
|
|
1025
|
-
|
|
1026
|
-
const
|
|
1027
|
-
const updateData = updateMap.get(
|
|
1028
|
-
return updateData ? { ...row
|
|
1029
|
-
});
|
|
1030
|
-
setServerData(newData || []);
|
|
1274
|
+
const updateMap = new Map(updates.map((update) => [update.rowId, update.data]));
|
|
1275
|
+
applyDataMutation('updateMultipleRows', (rowsToMutate) => rowsToMutate.map((row, index) => {
|
|
1276
|
+
const currentRowId = String((0, utils_1.generateRowId)(row, index, idKey));
|
|
1277
|
+
const updateData = updateMap.get(currentRowId);
|
|
1278
|
+
return updateData ? { ...row, ...updateData } : row;
|
|
1279
|
+
}));
|
|
1031
1280
|
},
|
|
1032
1281
|
insertMultipleRows: (newRows, startIndex) => {
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
setServerData === null || setServerData === void 0 ? void 0 : setServerData(newData);
|
|
1282
|
+
applyDataMutation('insertMultipleRows', (rowsToMutate) => {
|
|
1283
|
+
const nextData = [...rowsToMutate];
|
|
1284
|
+
nextData.splice(clampInsertIndex(nextData, startIndex), 0, ...newRows);
|
|
1285
|
+
return nextData;
|
|
1286
|
+
}, { index: startIndex });
|
|
1039
1287
|
},
|
|
1040
1288
|
deleteMultipleRows: (rowIds) => {
|
|
1041
1289
|
const idsToDelete = new Set(rowIds);
|
|
1042
|
-
|
|
1043
|
-
.filter((row) => !idsToDelete.has(String(row.original[idKey])))
|
|
1044
|
-
.map((row) => row.original);
|
|
1045
|
-
setServerData(newData);
|
|
1290
|
+
applyDataMutation('deleteMultipleRows', (rowsToMutate) => rowsToMutate.filter((row, index) => !idsToDelete.has(String((0, utils_1.generateRowId)(row, index, idKey)))), { rowIds });
|
|
1046
1291
|
},
|
|
1047
1292
|
updateField: (rowId, fieldName, value) => {
|
|
1048
|
-
|
|
1049
|
-
|
|
1293
|
+
applyDataMutation('updateField', (rowsToMutate) => {
|
|
1294
|
+
const rowIndex = getRowIndexById(rowsToMutate, rowId);
|
|
1295
|
+
if (rowIndex === -1)
|
|
1296
|
+
return rowsToMutate;
|
|
1297
|
+
const nextData = [...rowsToMutate];
|
|
1298
|
+
nextData[rowIndex] = { ...nextData[rowIndex], [fieldName]: value };
|
|
1299
|
+
return nextData;
|
|
1300
|
+
}, { rowId });
|
|
1050
1301
|
},
|
|
1051
1302
|
updateFieldByIndex: (index, fieldName, value) => {
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1303
|
+
applyDataMutation('updateFieldByIndex', (rowsToMutate) => {
|
|
1304
|
+
if (!rowsToMutate[index])
|
|
1305
|
+
return rowsToMutate;
|
|
1306
|
+
const nextData = [...rowsToMutate];
|
|
1307
|
+
nextData[index] = { ...nextData[index], [fieldName]: value };
|
|
1308
|
+
return nextData;
|
|
1309
|
+
}, { index });
|
|
1057
1310
|
},
|
|
1058
|
-
findRows: (predicate) =>
|
|
1059
|
-
findRowIndex: (predicate) =>
|
|
1060
|
-
getDataCount: () =>
|
|
1311
|
+
findRows: (predicate) => tableData.filter(predicate),
|
|
1312
|
+
findRowIndex: (predicate) => tableData.findIndex(predicate),
|
|
1313
|
+
getDataCount: () => tableData.length,
|
|
1061
1314
|
getFilteredDataCount: () => table.getFilteredRowModel().rows.length,
|
|
1062
1315
|
},
|
|
1063
1316
|
// -------------------------------
|
|
@@ -1072,7 +1325,7 @@ logging, }, ref) {
|
|
|
1072
1325
|
applySorting(initialStateConfig.sorting || []);
|
|
1073
1326
|
applyGlobalFilter((_a = initialStateConfig.globalFilter) !== null && _a !== void 0 ? _a : "");
|
|
1074
1327
|
},
|
|
1075
|
-
resetAll: () => resetAllAndReload(
|
|
1328
|
+
resetAll: () => resetAllAndReload(),
|
|
1076
1329
|
saveLayout: () => ({
|
|
1077
1330
|
columnVisibility: table.getState().columnVisibility,
|
|
1078
1331
|
columnSizing: table.getState().columnSizing,
|
|
@@ -1117,141 +1370,212 @@ logging, }, ref) {
|
|
|
1117
1370
|
// -------------------------------
|
|
1118
1371
|
export: {
|
|
1119
1372
|
exportCSV: async (options = {}) => {
|
|
1120
|
-
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1373
|
+
const { filename = exportFilename, chunkSize = exportChunkSize, strictTotalCheck = exportStrictTotalCheck, sanitizeCSV = exportSanitizeCSV, } = options;
|
|
1374
|
+
const mode = dataMode === "server" && !!onServerExport ? 'server' : 'client';
|
|
1375
|
+
await runExportWithPolicy({
|
|
1376
|
+
format: 'csv',
|
|
1377
|
+
filename,
|
|
1378
|
+
mode,
|
|
1379
|
+
execute: async (controller) => {
|
|
1380
|
+
var _a;
|
|
1381
|
+
const toStateChange = (state) => {
|
|
1382
|
+
const isFinalPhase = state.phase === 'completed' || state.phase === 'cancelled' || state.phase === 'error';
|
|
1383
|
+
handleExportStateChangeInternal({
|
|
1384
|
+
phase: state.phase,
|
|
1385
|
+
mode,
|
|
1386
|
+
format: 'csv',
|
|
1387
|
+
filename,
|
|
1388
|
+
processedRows: state.processedRows,
|
|
1389
|
+
totalRows: state.totalRows,
|
|
1390
|
+
percentage: state.percentage,
|
|
1391
|
+
message: state.message,
|
|
1392
|
+
code: state.code,
|
|
1393
|
+
startedAt: state.phase === 'starting' ? Date.now() : undefined,
|
|
1394
|
+
endedAt: isFinalPhase ? Date.now() : undefined,
|
|
1395
|
+
queueLength: queuedExportCount,
|
|
1396
|
+
});
|
|
1397
|
+
if (state.phase === 'cancelled') {
|
|
1398
|
+
onExportCancel === null || onExportCancel === void 0 ? void 0 : onExportCancel();
|
|
1399
|
+
}
|
|
1131
1400
|
};
|
|
1132
|
-
if (
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1401
|
+
if (mode === 'server' && onServerExport) {
|
|
1402
|
+
const currentFilters = {
|
|
1403
|
+
globalFilter: table.getState().globalFilter,
|
|
1404
|
+
columnFilter: table.getState().columnFilter,
|
|
1405
|
+
sorting: table.getState().sorting,
|
|
1406
|
+
pagination: table.getState().pagination,
|
|
1407
|
+
};
|
|
1408
|
+
if (logger.isLevelEnabled("debug"))
|
|
1409
|
+
logger.debug("Server export CSV", { currentFilters });
|
|
1410
|
+
await (0, utils_1.exportServerData)(table, {
|
|
1411
|
+
format: "csv",
|
|
1412
|
+
filename,
|
|
1413
|
+
fetchData: (filters, selection, signal) => onServerExport(filters, selection, signal),
|
|
1414
|
+
currentFilters,
|
|
1415
|
+
selection: (_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table),
|
|
1416
|
+
onProgress: handleExportProgressInternal,
|
|
1417
|
+
onComplete: onExportComplete,
|
|
1418
|
+
onError: onExportError,
|
|
1419
|
+
onStateChange: toStateChange,
|
|
1420
|
+
signal: controller.signal,
|
|
1421
|
+
chunkSize,
|
|
1422
|
+
strictTotalCheck,
|
|
1423
|
+
sanitizeCSV,
|
|
1424
|
+
});
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1146
1427
|
await (0, utils_1.exportClientData)(table, {
|
|
1147
1428
|
format: "csv",
|
|
1148
1429
|
filename,
|
|
1149
|
-
onProgress:
|
|
1430
|
+
onProgress: handleExportProgressInternal,
|
|
1150
1431
|
onComplete: onExportComplete,
|
|
1151
1432
|
onError: onExportError,
|
|
1433
|
+
onStateChange: toStateChange,
|
|
1434
|
+
signal: controller.signal,
|
|
1435
|
+
sanitizeCSV,
|
|
1152
1436
|
});
|
|
1153
1437
|
if (logger.isLevelEnabled("debug"))
|
|
1154
1438
|
logger.debug("Client export CSV", filename);
|
|
1155
1439
|
}
|
|
1156
|
-
}
|
|
1157
|
-
catch (error) {
|
|
1158
|
-
onExportError === null || onExportError === void 0 ? void 0 : onExportError({ message: error.message || "Export failed", code: "EXPORT_ERROR" });
|
|
1159
|
-
}
|
|
1160
|
-
finally {
|
|
1161
|
-
setExportController === null || setExportController === void 0 ? void 0 : setExportController(null);
|
|
1162
|
-
}
|
|
1440
|
+
});
|
|
1163
1441
|
},
|
|
1164
1442
|
exportExcel: async (options = {}) => {
|
|
1165
|
-
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1443
|
+
const { filename = exportFilename, chunkSize = exportChunkSize, strictTotalCheck = exportStrictTotalCheck, sanitizeCSV = exportSanitizeCSV, } = options;
|
|
1444
|
+
const mode = dataMode === "server" && !!onServerExport ? 'server' : 'client';
|
|
1445
|
+
await runExportWithPolicy({
|
|
1446
|
+
format: 'excel',
|
|
1447
|
+
filename,
|
|
1448
|
+
mode,
|
|
1449
|
+
execute: async (controller) => {
|
|
1450
|
+
var _a;
|
|
1451
|
+
const toStateChange = (state) => {
|
|
1452
|
+
const isFinalPhase = state.phase === 'completed' || state.phase === 'cancelled' || state.phase === 'error';
|
|
1453
|
+
handleExportStateChangeInternal({
|
|
1454
|
+
phase: state.phase,
|
|
1455
|
+
mode,
|
|
1456
|
+
format: 'excel',
|
|
1457
|
+
filename,
|
|
1458
|
+
processedRows: state.processedRows,
|
|
1459
|
+
totalRows: state.totalRows,
|
|
1460
|
+
percentage: state.percentage,
|
|
1461
|
+
message: state.message,
|
|
1462
|
+
code: state.code,
|
|
1463
|
+
startedAt: state.phase === 'starting' ? Date.now() : undefined,
|
|
1464
|
+
endedAt: isFinalPhase ? Date.now() : undefined,
|
|
1465
|
+
queueLength: queuedExportCount,
|
|
1466
|
+
});
|
|
1467
|
+
if (state.phase === 'cancelled') {
|
|
1468
|
+
onExportCancel === null || onExportCancel === void 0 ? void 0 : onExportCancel();
|
|
1469
|
+
}
|
|
1176
1470
|
};
|
|
1177
|
-
if (
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1471
|
+
if (mode === 'server' && onServerExport) {
|
|
1472
|
+
const currentFilters = {
|
|
1473
|
+
globalFilter: table.getState().globalFilter,
|
|
1474
|
+
columnFilter: table.getState().columnFilter,
|
|
1475
|
+
sorting: table.getState().sorting,
|
|
1476
|
+
pagination: table.getState().pagination,
|
|
1477
|
+
};
|
|
1478
|
+
if (logger.isLevelEnabled("debug"))
|
|
1479
|
+
logger.debug("Server export Excel", { currentFilters });
|
|
1480
|
+
await (0, utils_1.exportServerData)(table, {
|
|
1481
|
+
format: "excel",
|
|
1482
|
+
filename,
|
|
1483
|
+
fetchData: (filters, selection, signal) => onServerExport(filters, selection, signal),
|
|
1484
|
+
currentFilters,
|
|
1485
|
+
selection: (_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table),
|
|
1486
|
+
onProgress: handleExportProgressInternal,
|
|
1487
|
+
onComplete: onExportComplete,
|
|
1488
|
+
onError: onExportError,
|
|
1489
|
+
onStateChange: toStateChange,
|
|
1490
|
+
signal: controller.signal,
|
|
1491
|
+
chunkSize,
|
|
1492
|
+
strictTotalCheck,
|
|
1493
|
+
sanitizeCSV,
|
|
1494
|
+
});
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1191
1497
|
await (0, utils_1.exportClientData)(table, {
|
|
1192
1498
|
format: "excel",
|
|
1193
1499
|
filename,
|
|
1194
|
-
onProgress:
|
|
1500
|
+
onProgress: handleExportProgressInternal,
|
|
1195
1501
|
onComplete: onExportComplete,
|
|
1196
1502
|
onError: onExportError,
|
|
1503
|
+
onStateChange: toStateChange,
|
|
1504
|
+
signal: controller.signal,
|
|
1505
|
+
sanitizeCSV,
|
|
1197
1506
|
});
|
|
1198
1507
|
if (logger.isLevelEnabled("debug"))
|
|
1199
1508
|
logger.debug("Client export Excel", filename);
|
|
1200
1509
|
}
|
|
1201
|
-
}
|
|
1202
|
-
catch (error) {
|
|
1203
|
-
onExportError === null || onExportError === void 0 ? void 0 : onExportError({ message: error.message || "Export failed", code: "EXPORT_ERROR" });
|
|
1204
|
-
if (logger.isLevelEnabled("debug"))
|
|
1205
|
-
logger.debug("Server export Excel failed", error);
|
|
1206
|
-
}
|
|
1207
|
-
finally {
|
|
1208
|
-
setExportController === null || setExportController === void 0 ? void 0 : setExportController(null);
|
|
1209
|
-
}
|
|
1510
|
+
});
|
|
1210
1511
|
},
|
|
1211
1512
|
exportServerData: async (options) => {
|
|
1212
|
-
|
|
1213
|
-
const { format, filename = exportFilename, fetchData: fetchFn = onServerExport } = options;
|
|
1513
|
+
const { format, filename = exportFilename, fetchData: fetchFn = onServerExport, chunkSize = exportChunkSize, strictTotalCheck = exportStrictTotalCheck, sanitizeCSV = exportSanitizeCSV, } = options;
|
|
1214
1514
|
if (!fetchFn) {
|
|
1215
1515
|
onExportError === null || onExportError === void 0 ? void 0 : onExportError({ message: "No server export function provided", code: "NO_SERVER_EXPORT" });
|
|
1216
1516
|
if (logger.isLevelEnabled("debug"))
|
|
1217
1517
|
logger.debug("Server export data failed", "No server export function provided");
|
|
1218
1518
|
return;
|
|
1219
1519
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1520
|
+
await runExportWithPolicy({
|
|
1521
|
+
format,
|
|
1522
|
+
filename,
|
|
1523
|
+
mode: 'server',
|
|
1524
|
+
execute: async (controller) => {
|
|
1525
|
+
var _a;
|
|
1526
|
+
const currentFilters = {
|
|
1527
|
+
globalFilter: table.getState().globalFilter,
|
|
1528
|
+
columnFilter: table.getState().columnFilter,
|
|
1529
|
+
sorting: table.getState().sorting,
|
|
1530
|
+
pagination: table.getState().pagination,
|
|
1531
|
+
};
|
|
1532
|
+
if (logger.isLevelEnabled("debug"))
|
|
1533
|
+
logger.debug("Server export data", { currentFilters });
|
|
1534
|
+
await (0, utils_1.exportServerData)(table, {
|
|
1535
|
+
format,
|
|
1536
|
+
filename,
|
|
1537
|
+
fetchData: (filters, selection, signal) => fetchFn(filters, selection, signal),
|
|
1538
|
+
currentFilters,
|
|
1539
|
+
selection: (_a = table.getSelectionState) === null || _a === void 0 ? void 0 : _a.call(table),
|
|
1540
|
+
onProgress: handleExportProgressInternal,
|
|
1541
|
+
onComplete: onExportComplete,
|
|
1542
|
+
onError: onExportError,
|
|
1543
|
+
onStateChange: (state) => {
|
|
1544
|
+
const isFinalPhase = state.phase === 'completed' || state.phase === 'cancelled' || state.phase === 'error';
|
|
1545
|
+
handleExportStateChangeInternal({
|
|
1546
|
+
phase: state.phase,
|
|
1547
|
+
mode: 'server',
|
|
1548
|
+
format,
|
|
1549
|
+
filename,
|
|
1550
|
+
processedRows: state.processedRows,
|
|
1551
|
+
totalRows: state.totalRows,
|
|
1552
|
+
percentage: state.percentage,
|
|
1553
|
+
message: state.message,
|
|
1554
|
+
code: state.code,
|
|
1555
|
+
startedAt: state.phase === 'starting' ? Date.now() : undefined,
|
|
1556
|
+
endedAt: isFinalPhase ? Date.now() : undefined,
|
|
1557
|
+
queueLength: queuedExportCount,
|
|
1558
|
+
});
|
|
1559
|
+
if (state.phase === 'cancelled') {
|
|
1560
|
+
onExportCancel === null || onExportCancel === void 0 ? void 0 : onExportCancel();
|
|
1561
|
+
}
|
|
1562
|
+
},
|
|
1563
|
+
signal: controller.signal,
|
|
1564
|
+
chunkSize,
|
|
1565
|
+
strictTotalCheck,
|
|
1566
|
+
sanitizeCSV,
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1250
1570
|
},
|
|
1251
1571
|
isExporting: () => isExporting || false,
|
|
1252
1572
|
cancelExport: () => {
|
|
1253
|
-
|
|
1254
|
-
|
|
1573
|
+
const activeController = exportControllerRef.current;
|
|
1574
|
+
if (!activeController) {
|
|
1575
|
+
return;
|
|
1576
|
+
}
|
|
1577
|
+
activeController.abort();
|
|
1578
|
+
setExportControllerSafely((current) => (current === activeController ? null : current));
|
|
1255
1579
|
if (logger.isLevelEnabled("debug"))
|
|
1256
1580
|
logger.debug("Export cancelled");
|
|
1257
1581
|
},
|
|
@@ -1272,17 +1596,26 @@ logging, }, ref) {
|
|
|
1272
1596
|
initialStateConfig,
|
|
1273
1597
|
enablePagination,
|
|
1274
1598
|
idKey,
|
|
1275
|
-
|
|
1276
|
-
|
|
1599
|
+
triggerRefresh,
|
|
1600
|
+
applyDataMutation,
|
|
1601
|
+
tableData,
|
|
1602
|
+
selectionState,
|
|
1277
1603
|
// export
|
|
1278
1604
|
exportFilename,
|
|
1279
|
-
|
|
1605
|
+
exportChunkSize,
|
|
1606
|
+
exportStrictTotalCheck,
|
|
1607
|
+
exportSanitizeCSV,
|
|
1280
1608
|
onExportComplete,
|
|
1281
1609
|
onExportError,
|
|
1610
|
+
onExportCancel,
|
|
1282
1611
|
onServerExport,
|
|
1283
|
-
|
|
1612
|
+
queuedExportCount,
|
|
1284
1613
|
isExporting,
|
|
1285
1614
|
dataMode,
|
|
1615
|
+
handleExportProgressInternal,
|
|
1616
|
+
handleExportStateChangeInternal,
|
|
1617
|
+
runExportWithPolicy,
|
|
1618
|
+
setExportControllerSafely,
|
|
1286
1619
|
logger,
|
|
1287
1620
|
resetAllAndReload,
|
|
1288
1621
|
]);
|
|
@@ -1343,14 +1676,12 @@ logging, }, ref) {
|
|
|
1343
1676
|
// Export cancel callback
|
|
1344
1677
|
// -------------------------------
|
|
1345
1678
|
const handleCancelExport = (0, react_1.useCallback)(() => {
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
onExportCancel();
|
|
1351
|
-
}
|
|
1679
|
+
const activeController = exportControllerRef.current;
|
|
1680
|
+
if (activeController) {
|
|
1681
|
+
activeController.abort();
|
|
1682
|
+
setExportControllerSafely((current) => (current === activeController ? null : current));
|
|
1352
1683
|
}
|
|
1353
|
-
}, [
|
|
1684
|
+
}, [setExportControllerSafely]);
|
|
1354
1685
|
// -------------------------------
|
|
1355
1686
|
// Slot components
|
|
1356
1687
|
// -------------------------------
|
|
@@ -1367,7 +1698,7 @@ logging, }, ref) {
|
|
|
1367
1698
|
// -------------------------------
|
|
1368
1699
|
return ((0, jsx_runtime_1.jsx)(data_table_context_1.DataTableProvider, { table: table, apiRef: internalApiRef, dataMode: dataMode, tableSize: tableSize, onTableSizeChange: (size) => {
|
|
1369
1700
|
setTableSize(size);
|
|
1370
|
-
}, columnFilter: columnFilter, onChangeColumnFilter: handleColumnFilterStateChange, slots: slots, slotProps: slotProps, isExporting: isExporting, exportController: exportController, onCancelExport: handleCancelExport, exportFilename: exportFilename, onExportProgress: onExportProgress, onExportComplete: onExportComplete, onExportError: onExportError, onServerExport: onServerExport, children: (0, jsx_runtime_1.jsxs)(RootComponent, { ...rootSlotProps, children: [(enableGlobalFilter || extraFilter) ? ((0, jsx_runtime_1.jsx)(ToolbarComponent, { extraFilter: extraFilter, enableGlobalFilter: enableGlobalFilter, enableColumnVisibility: enableColumnVisibility, enableColumnFilter: enableColumnFilter, enableExport: enableExport, enableReset: enableReset, enableTableSizeControl: enableTableSizeControl, enableColumnPinning: enableColumnPinning, enableRefresh: enableRefresh, ...toolbarSlotProps, refreshButtonProps: {
|
|
1701
|
+
}, columnFilter: columnFilter, onChangeColumnFilter: handleColumnFilterStateChange, slots: slots, slotProps: slotProps, isExporting: isExporting, exportController: exportController, exportPhase: exportPhase, exportProgress: exportProgress, onCancelExport: handleCancelExport, exportFilename: exportFilename, onExportProgress: onExportProgress, onExportComplete: onExportComplete, onExportError: onExportError, onServerExport: onServerExport, children: (0, jsx_runtime_1.jsxs)(RootComponent, { ...rootSlotProps, children: [(enableGlobalFilter || extraFilter) ? ((0, jsx_runtime_1.jsx)(ToolbarComponent, { extraFilter: extraFilter, enableGlobalFilter: enableGlobalFilter, enableColumnVisibility: enableColumnVisibility, enableColumnFilter: enableColumnFilter, enableExport: enableExport, enableReset: enableReset, enableTableSizeControl: enableTableSizeControl, enableColumnPinning: enableColumnPinning, enableRefresh: enableRefresh, ...toolbarSlotProps, refreshButtonProps: {
|
|
1371
1702
|
loading: tableLoading, // disable while fetching
|
|
1372
1703
|
showSpinnerWhileLoading: false,
|
|
1373
1704
|
onRefresh: () => { var _a, _b, _c; return (_c = (_b = (_a = internalApiRef.current) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.refresh) === null || _c === void 0 ? void 0 : _c.call(_b, true); },
|