@ackplus/react-tanstack-data-table 1.1.11 → 1.1.12
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/dist/lib/components/toolbar/data-table-toolbar.d.ts.map +1 -1
- package/dist/lib/components/toolbar/data-table-toolbar.js +5 -2
- package/dist/lib/components/toolbar/table-refresh-control.d.ts +15 -0
- package/dist/lib/components/toolbar/table-refresh-control.d.ts.map +1 -0
- package/dist/lib/components/toolbar/table-refresh-control.js +61 -0
- package/dist/lib/data-table.d.ts.map +1 -1
- package/dist/lib/data-table.js +749 -916
- package/dist/lib/types/data-table-api.d.ts +1 -0
- package/dist/lib/types/data-table-api.d.ts.map +1 -1
- package/dist/lib/types/data-table.types.d.ts +1 -0
- package/dist/lib/types/data-table.types.d.ts.map +1 -1
- package/dist/lib/types/slots.types.d.ts +9 -0
- package/dist/lib/types/slots.types.d.ts.map +1 -1
- package/dist/lib/utils/slot-helpers.d.ts +1 -1
- package/dist/lib/utils/slot-helpers.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/lib/components/toolbar/data-table-toolbar.tsx +15 -1
- package/src/lib/components/toolbar/table-refresh-control.tsx +58 -0
- package/src/lib/data-table.tsx +773 -904
- package/src/lib/types/data-table-api.ts +4 -0
- package/src/lib/types/data-table.types.ts +1 -0
- package/src/lib/types/slots.types.ts +8 -0
- package/src/lib/utils/slot-helpers.tsx +1 -1
package/src/lib/data-table.tsx
CHANGED
|
@@ -170,6 +170,7 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
170
170
|
enableTableSizeControl = true,
|
|
171
171
|
enableExport = false,
|
|
172
172
|
enableReset = true,
|
|
173
|
+
enableRefresh = false,
|
|
173
174
|
|
|
174
175
|
// Loading and empty states
|
|
175
176
|
loading = false,
|
|
@@ -324,12 +325,15 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
324
325
|
...overrides,
|
|
325
326
|
};
|
|
326
327
|
|
|
328
|
+
console.log('Fetching data', filters);
|
|
329
|
+
|
|
327
330
|
if (logger.isLevelEnabled('info')) {
|
|
328
331
|
logger.info('Requesting data', { filters });
|
|
329
332
|
}
|
|
330
333
|
|
|
331
334
|
try {
|
|
332
|
-
const
|
|
335
|
+
const delay = options?.delay ?? 300; // respects 0
|
|
336
|
+
const result = await debouncedFetch(filters, delay);
|
|
333
337
|
|
|
334
338
|
if (logger.isLevelEnabled('info')) {
|
|
335
339
|
logger.info('Fetch resolved', {
|
|
@@ -361,75 +365,22 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
361
365
|
]);
|
|
362
366
|
|
|
363
367
|
|
|
364
|
-
const tableStateChange = useCallback((overrides: Partial<TableState> = {}) => {
|
|
365
|
-
if (!onDataStateChange) {
|
|
366
|
-
if (logger.isLevelEnabled('debug')) {
|
|
367
|
-
logger.debug('No onDataStateChange handler registered; skipping state update notification', { overrides });
|
|
368
|
-
}
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
const currentState: Partial<TableState> = {
|
|
373
|
-
globalFilter,
|
|
374
|
-
columnFilter,
|
|
375
|
-
sorting,
|
|
376
|
-
pagination,
|
|
377
|
-
columnOrder,
|
|
378
|
-
columnPinning,
|
|
379
|
-
columnVisibility,
|
|
380
|
-
columnSizing,
|
|
381
|
-
...overrides,
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
if (logger.isLevelEnabled('debug')) {
|
|
385
|
-
logger.debug('Emitting tableStateChange', currentState);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
onDataStateChange?.(currentState);
|
|
389
|
-
}, [
|
|
390
|
-
onDataStateChange,
|
|
391
|
-
globalFilter,
|
|
392
|
-
columnFilter,
|
|
393
|
-
sorting,
|
|
394
|
-
pagination,
|
|
395
|
-
columnOrder,
|
|
396
|
-
columnPinning,
|
|
397
|
-
columnVisibility,
|
|
398
|
-
columnSizing,
|
|
399
|
-
logger,
|
|
400
|
-
]);
|
|
401
|
-
|
|
402
|
-
|
|
403
368
|
const handleSelectionStateChange = useCallback((updaterOrValue) => {
|
|
404
369
|
setSelectionState((prevState) => {
|
|
405
|
-
const
|
|
406
|
-
? updaterOrValue(prevState)
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
if (onSelectionChange) {
|
|
410
|
-
onSelectionChange(newSelectionState);
|
|
411
|
-
}
|
|
412
|
-
if (onDataStateChange) {
|
|
413
|
-
tableStateChange({ selectionState: newSelectionState });
|
|
414
|
-
}
|
|
415
|
-
}, 0);
|
|
416
|
-
return newSelectionState;
|
|
370
|
+
const next =
|
|
371
|
+
typeof updaterOrValue === 'function' ? updaterOrValue(prevState) : updaterOrValue;
|
|
372
|
+
onSelectionChange?.(next);
|
|
373
|
+
return next;
|
|
417
374
|
});
|
|
418
|
-
}, [onSelectionChange
|
|
375
|
+
}, [onSelectionChange]);
|
|
419
376
|
|
|
420
377
|
const handleColumnFilterStateChange = useCallback((filterState: ColumnFilterState) => {
|
|
421
378
|
if (!filterState || typeof filterState !== 'object') return;
|
|
422
379
|
|
|
423
380
|
setColumnFilter(filterState);
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (onDataStateChange) {
|
|
430
|
-
setTimeout(() => tableStateChange({ columnFilter: filterState }), 0);
|
|
431
|
-
}
|
|
432
|
-
}, [onColumnFiltersChange, onDataStateChange, tableStateChange]);
|
|
381
|
+
onColumnFiltersChange?.(filterState);
|
|
382
|
+
return filterState;
|
|
383
|
+
}, [onColumnFiltersChange]);
|
|
433
384
|
|
|
434
385
|
|
|
435
386
|
const resetPageToFirst = useCallback(() => {
|
|
@@ -445,43 +396,20 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
445
396
|
return newPagination;
|
|
446
397
|
}, [pagination, logger, onPaginationChange]);
|
|
447
398
|
|
|
448
|
-
|
|
399
|
+
|
|
449
400
|
const handleSortingChange = useCallback((updaterOrValue: any) => {
|
|
450
|
-
let newSorting = typeof updaterOrValue === 'function'
|
|
451
|
-
? updaterOrValue(sorting)
|
|
452
|
-
: updaterOrValue;
|
|
453
|
-
newSorting = newSorting.filter((sort: any) => sort.id);
|
|
454
|
-
setSorting(newSorting);
|
|
455
|
-
onSortingChange?.(newSorting);
|
|
456
|
-
|
|
457
|
-
if (logger.isLevelEnabled('debug')) {
|
|
458
|
-
logger.debug('Sorting change applied', {
|
|
459
|
-
sorting: newSorting,
|
|
460
|
-
serverMode: isServerMode,
|
|
461
|
-
serverSorting: isServerSorting,
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
401
|
|
|
465
|
-
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
402
|
+
setSorting((prev) => {
|
|
403
|
+
const next = typeof updaterOrValue === 'function' ? updaterOrValue(prev) : updaterOrValue;
|
|
404
|
+
const cleaned = next.filter((s: any) => s?.id);
|
|
405
|
+
onSortingChange?.(cleaned);
|
|
406
|
+
const nextPagination = resetPageToFirst();
|
|
407
|
+
if (isServerMode || isServerSorting) {
|
|
408
|
+
fetchData({ sorting: cleaned, pagination: nextPagination }, { delay: 0 });
|
|
469
409
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
pagination,
|
|
474
|
-
});
|
|
475
|
-
} else if (onDataStateChange) {
|
|
476
|
-
const pagination = resetPageToFirst();
|
|
477
|
-
setTimeout(() => {
|
|
478
|
-
if (logger.isLevelEnabled('debug')) {
|
|
479
|
-
logger.debug('Sorting change notified client state change', { pagination, sorting: newSorting });
|
|
480
|
-
}
|
|
481
|
-
tableStateChange({ sorting: newSorting, pagination });
|
|
482
|
-
}, 0);
|
|
483
|
-
}
|
|
484
|
-
}, [sorting, onSortingChange, logger, isServerMode, isServerSorting, onDataStateChange, resetPageToFirst, tableStateChange, fetchData]);
|
|
410
|
+
return cleaned;
|
|
411
|
+
});
|
|
412
|
+
}, [onSortingChange, isServerMode, isServerSorting, resetPageToFirst, fetchData]);
|
|
485
413
|
|
|
486
414
|
const handleColumnOrderChange = useCallback((updatedColumnOrder: Updater<ColumnOrderState>) => {
|
|
487
415
|
const newColumnOrder = typeof updatedColumnOrder === 'function'
|
|
@@ -493,144 +421,64 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
493
421
|
}
|
|
494
422
|
}, [onColumnDragEnd, columnOrder]);
|
|
495
423
|
|
|
496
|
-
const handleColumnPinningChange = useCallback(
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
424
|
+
const handleColumnPinningChange = useCallback(
|
|
425
|
+
(updater: Updater<ColumnPinningState>) => {
|
|
426
|
+
setColumnPinning((prev) => {
|
|
427
|
+
const next = typeof updater === "function" ? updater(prev) : updater;
|
|
428
|
+
// keep direct callback here (optional)
|
|
429
|
+
onColumnPinningChange?.(next);
|
|
430
|
+
return next;
|
|
431
|
+
});
|
|
432
|
+
},
|
|
433
|
+
[onColumnPinningChange]
|
|
434
|
+
);
|
|
505
435
|
|
|
506
436
|
// Column visibility change handler - same pattern as column order
|
|
507
437
|
const handleColumnVisibilityChange = useCallback((updater: any) => {
|
|
508
|
-
|
|
509
|
-
? updater(
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
setTimeout(() => {
|
|
515
|
-
onColumnVisibilityChange(newVisibility);
|
|
516
|
-
}, 0);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (onDataStateChange) {
|
|
520
|
-
setTimeout(() => {
|
|
521
|
-
tableStateChange({ columnVisibility: newVisibility });
|
|
522
|
-
}, 0);
|
|
523
|
-
}
|
|
524
|
-
}, [onColumnVisibilityChange, onDataStateChange, tableStateChange, columnVisibility]);
|
|
438
|
+
setColumnVisibility((prev) => {
|
|
439
|
+
const next = typeof updater === 'function' ? updater(prev) : updater;
|
|
440
|
+
onColumnVisibilityChange?.(next);
|
|
441
|
+
return next;
|
|
442
|
+
});
|
|
443
|
+
}, [onColumnVisibilityChange]);
|
|
525
444
|
|
|
526
445
|
// Column sizing change handler - same pattern as column order
|
|
527
446
|
const handleColumnSizingChange = useCallback((updater: any) => {
|
|
528
|
-
|
|
529
|
-
? updater(
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
setTimeout(() => {
|
|
535
|
-
onColumnSizingChange(newSizing);
|
|
536
|
-
}, 0);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
if (onDataStateChange) {
|
|
540
|
-
setTimeout(() => {
|
|
541
|
-
tableStateChange({ columnSizing: newSizing });
|
|
542
|
-
}, 0);
|
|
543
|
-
}
|
|
544
|
-
}, [onColumnSizingChange, onDataStateChange, tableStateChange, columnSizing]);
|
|
447
|
+
setColumnSizing((prev) => {
|
|
448
|
+
const next = typeof updater === 'function' ? updater(prev) : updater;
|
|
449
|
+
onColumnSizingChange?.(next);
|
|
450
|
+
return next;
|
|
451
|
+
});
|
|
452
|
+
}, [onColumnSizingChange]);
|
|
545
453
|
|
|
546
454
|
const handlePaginationChange = useCallback((updater: any) => {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
next:
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// Update pagination state
|
|
557
|
-
setPagination(newPagination);
|
|
558
|
-
onPaginationChange?.(newPagination);
|
|
455
|
+
setPagination((prev) => {
|
|
456
|
+
const next = typeof updater === 'function' ? updater(prev) : updater;
|
|
457
|
+
onPaginationChange?.(next);
|
|
458
|
+
if (isServerMode || isServerPagination) {
|
|
459
|
+
fetchData({ pagination: next }, { delay: 0 });
|
|
460
|
+
}
|
|
461
|
+
return next;
|
|
462
|
+
});
|
|
463
|
+
}, [isServerMode, isServerPagination, fetchData, onPaginationChange]);
|
|
559
464
|
|
|
560
|
-
if (logger.isLevelEnabled('debug')) {
|
|
561
|
-
logger.debug('Pagination state updated', newPagination);
|
|
562
|
-
}
|
|
563
465
|
|
|
564
|
-
// Notify state change and fetch data if needed
|
|
565
|
-
if (isServerMode || isServerPagination) {
|
|
566
|
-
setTimeout(() => {
|
|
567
|
-
if (logger.isLevelEnabled('debug')) {
|
|
568
|
-
logger.debug('Notifying server-side pagination change', newPagination);
|
|
569
|
-
}
|
|
570
|
-
tableStateChange({ pagination: newPagination });
|
|
571
|
-
fetchData({ pagination: newPagination });
|
|
572
|
-
}, 0);
|
|
573
|
-
} else if (onDataStateChange) {
|
|
574
|
-
setTimeout(() => {
|
|
575
|
-
if (logger.isLevelEnabled('debug')) {
|
|
576
|
-
logger.debug('Notifying client-side pagination change', newPagination);
|
|
577
|
-
}
|
|
578
|
-
tableStateChange({ pagination: newPagination });
|
|
579
|
-
}, 0);
|
|
580
|
-
}
|
|
581
|
-
}, [
|
|
582
|
-
pagination,
|
|
583
|
-
isServerMode,
|
|
584
|
-
isServerPagination,
|
|
585
|
-
onDataStateChange,
|
|
586
|
-
fetchData,
|
|
587
|
-
tableStateChange,
|
|
588
|
-
logger,
|
|
589
|
-
onPaginationChange,
|
|
590
|
-
]);
|
|
591
466
|
|
|
467
|
+
const handleGlobalFilterChange = useCallback((updaterOrValue: any) => {
|
|
468
|
+
setGlobalFilter((prev) => {
|
|
469
|
+
const next = typeof updaterOrValue === 'function' ? updaterOrValue(prev) : updaterOrValue;
|
|
592
470
|
|
|
471
|
+
onGlobalFilterChange?.(next);
|
|
593
472
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
if (logger.isLevelEnabled('debug')) {
|
|
601
|
-
logger.debug('Global filter change applied', {
|
|
602
|
-
value: newFilter,
|
|
603
|
-
serverMode: isServerMode,
|
|
604
|
-
serverFiltering: isServerFiltering,
|
|
605
|
-
});
|
|
606
|
-
}
|
|
473
|
+
if (isServerMode || isServerFiltering) {
|
|
474
|
+
const nextPagination = { pageIndex: 0, pageSize: pagination.pageSize };
|
|
475
|
+
setPagination(nextPagination);
|
|
476
|
+
fetchData({ globalFilter: next, pagination: nextPagination }, { delay: 0 });
|
|
477
|
+
}
|
|
607
478
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
if (logger.isLevelEnabled('debug')) {
|
|
612
|
-
logger.debug('Global filter change triggering server fetch', {
|
|
613
|
-
pagination,
|
|
614
|
-
value: newFilter,
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
tableStateChange({ globalFilter: newFilter, pagination });
|
|
618
|
-
fetchData({ globalFilter: newFilter, pagination });
|
|
619
|
-
}, 0);
|
|
620
|
-
} else if (onDataStateChange) {
|
|
621
|
-
const pagination = resetPageToFirst();
|
|
622
|
-
setTimeout(() => {
|
|
623
|
-
if (logger.isLevelEnabled('debug')) {
|
|
624
|
-
logger.debug('Global filter change notifying client listeners', {
|
|
625
|
-
pagination,
|
|
626
|
-
value: newFilter,
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
tableStateChange({ globalFilter: newFilter, pagination });
|
|
630
|
-
}, 0);
|
|
631
|
-
}
|
|
632
|
-
onGlobalFilterChange?.(newFilter);
|
|
633
|
-
}, [globalFilter, logger, isServerMode, isServerFiltering, onDataStateChange, onGlobalFilterChange, resetPageToFirst, tableStateChange, fetchData]);
|
|
479
|
+
return next;
|
|
480
|
+
});
|
|
481
|
+
}, [isServerMode, isServerFiltering, onGlobalFilterChange, fetchData, pagination.pageSize]);
|
|
634
482
|
|
|
635
483
|
const onColumnFilterChangeHandler = useCallback((updater: any) => {
|
|
636
484
|
const currentState = columnFilter;
|
|
@@ -648,24 +496,15 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
648
496
|
|
|
649
497
|
const onColumnFilterApplyHandler = useCallback((appliedState: ColumnFilterState) => {
|
|
650
498
|
const pagination = resetPageToFirst();
|
|
651
|
-
|
|
652
499
|
if (isServerFiltering) {
|
|
653
|
-
tableStateChange({
|
|
654
|
-
columnFilter: appliedState,
|
|
655
|
-
pagination,
|
|
656
|
-
});
|
|
657
500
|
fetchData({
|
|
658
501
|
columnFilter: appliedState,
|
|
659
502
|
pagination,
|
|
660
503
|
});
|
|
661
|
-
} else if (onDataStateChange) {
|
|
662
|
-
setTimeout(() => tableStateChange({ columnFilter: appliedState, pagination }), 0);
|
|
663
504
|
}
|
|
664
505
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}, 0);
|
|
668
|
-
}, [resetPageToFirst, isServerFiltering, onDataStateChange, tableStateChange, fetchData, onColumnFiltersChange]);
|
|
506
|
+
onColumnFiltersChange?.(appliedState);
|
|
507
|
+
}, [resetPageToFirst, isServerFiltering, fetchData, onColumnFiltersChange]);
|
|
669
508
|
|
|
670
509
|
// -------------------------------
|
|
671
510
|
// Table creation (after callbacks/memo)
|
|
@@ -825,501 +664,573 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
825
664
|
}, [enableColumnDragging, enhancedColumns, columnOrder.length]);
|
|
826
665
|
|
|
827
666
|
|
|
828
|
-
const
|
|
829
|
-
table: {
|
|
830
|
-
getTable: () => table,
|
|
831
|
-
},
|
|
832
|
-
// Column Management
|
|
833
|
-
columnVisibility: {
|
|
834
|
-
showColumn: (columnId: string) => {
|
|
835
|
-
table.getColumn(columnId)?.toggleVisibility(true);
|
|
836
|
-
},
|
|
837
|
-
hideColumn: (columnId: string) => {
|
|
838
|
-
table.getColumn(columnId)?.toggleVisibility(false);
|
|
839
|
-
},
|
|
840
|
-
toggleColumn: (columnId: string) => {
|
|
841
|
-
table.getColumn(columnId)?.toggleVisibility();
|
|
842
|
-
},
|
|
843
|
-
showAllColumns: () => {
|
|
844
|
-
table.toggleAllColumnsVisible(true);
|
|
845
|
-
},
|
|
846
|
-
hideAllColumns: () => {
|
|
847
|
-
table.toggleAllColumnsVisible(false);
|
|
848
|
-
},
|
|
849
|
-
resetColumnVisibility: () => {
|
|
850
|
-
const initialVisibility = initialStateConfig.columnVisibility || {};
|
|
851
|
-
table.setColumnVisibility(initialVisibility);
|
|
852
|
-
// Manually trigger handler to ensure callbacks are called
|
|
853
|
-
handleColumnVisibilityChange(initialVisibility);
|
|
854
|
-
},
|
|
855
|
-
},
|
|
667
|
+
const lastSentRef = useRef<string>("");
|
|
856
668
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
setColumnOrder: (columnOrder: ColumnOrderState) => {
|
|
860
|
-
table.setColumnOrder(columnOrder);
|
|
861
|
-
},
|
|
862
|
-
moveColumn: (columnId: string, toIndex: number) => {
|
|
863
|
-
const currentOrder = table.getState().columnOrder || [];
|
|
864
|
-
const currentIndex = currentOrder.indexOf(columnId);
|
|
865
|
-
if (currentIndex === -1) return;
|
|
669
|
+
const emitTableState = useCallback(() => {
|
|
670
|
+
if (!onDataStateChange) return;
|
|
866
671
|
|
|
867
|
-
|
|
868
|
-
newOrder.splice(currentIndex, 1);
|
|
869
|
-
newOrder.splice(toIndex, 0, columnId);
|
|
672
|
+
const live = table.getState();
|
|
870
673
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
table.setColumnOrder(initialOrder);
|
|
883
|
-
// Manually trigger handler to ensure callbacks are called
|
|
884
|
-
handleColumnOrderChange(initialOrder);
|
|
885
|
-
},
|
|
886
|
-
},
|
|
674
|
+
// only keep what you persist/store
|
|
675
|
+
const payload = {
|
|
676
|
+
sorting: live.sorting,
|
|
677
|
+
pagination: live.pagination,
|
|
678
|
+
globalFilter: live.globalFilter,
|
|
679
|
+
columnFilter: live.columnFilter,
|
|
680
|
+
columnVisibility: live.columnVisibility,
|
|
681
|
+
columnSizing: live.columnSizing,
|
|
682
|
+
columnOrder: live.columnOrder,
|
|
683
|
+
columnPinning: live.columnPinning,
|
|
684
|
+
};
|
|
887
685
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
pinColumnLeft: (columnId: string) => {
|
|
891
|
-
const currentPinning = table.getState().columnPinning;
|
|
892
|
-
const newPinning = { ...currentPinning };
|
|
686
|
+
const key = JSON.stringify(payload);
|
|
687
|
+
if (key === lastSentRef.current) return;
|
|
893
688
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
newPinning.left = [...(newPinning.left || []).filter(id => id !== columnId), columnId];
|
|
689
|
+
lastSentRef.current = key;
|
|
690
|
+
onDataStateChange(payload);
|
|
691
|
+
}, [onDataStateChange, table]);
|
|
898
692
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
693
|
+
useEffect(() => {
|
|
694
|
+
emitTableState();
|
|
695
|
+
}, [
|
|
696
|
+
emitTableState,
|
|
697
|
+
sorting,
|
|
698
|
+
pagination,
|
|
699
|
+
globalFilter,
|
|
700
|
+
columnFilter,
|
|
701
|
+
columnVisibility,
|
|
702
|
+
columnSizing,
|
|
703
|
+
columnOrder,
|
|
704
|
+
columnPinning,
|
|
705
|
+
]);
|
|
904
706
|
|
|
905
|
-
// Remove from left if exists
|
|
906
|
-
newPinning.left = (newPinning.left || []).filter(id => id !== columnId);
|
|
907
|
-
// Add to right if not exists - prepend to beginning (appears rightmost to leftmost)
|
|
908
|
-
// First column pinned appears rightmost, second appears to its left, etc.
|
|
909
|
-
newPinning.right = [columnId, ...(newPinning.right || []).filter(id => id !== columnId)];
|
|
910
707
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
left: (currentPinning.left || []).filter(id => id !== columnId),
|
|
917
|
-
right: (currentPinning.right || []).filter(id => id !== columnId),
|
|
918
|
-
};
|
|
919
|
-
|
|
920
|
-
table.setColumnPinning(newPinning);
|
|
921
|
-
},
|
|
922
|
-
setPinning: (pinning: ColumnPinningState) => {
|
|
923
|
-
table.setColumnPinning(pinning);
|
|
924
|
-
},
|
|
925
|
-
resetColumnPinning: () => {
|
|
926
|
-
const initialPinning = initialStateConfig.columnPinning || { left: [], right: [] };
|
|
927
|
-
table.setColumnPinning(initialPinning);
|
|
928
|
-
// Manually trigger handler to ensure callbacks are called
|
|
929
|
-
handleColumnPinningChange(initialPinning);
|
|
930
|
-
},
|
|
931
|
-
},
|
|
708
|
+
const getResetState = useCallback((): Partial<TableState> => {
|
|
709
|
+
const resetSorting = initialStateConfig.sorting || [];
|
|
710
|
+
const resetGlobalFilter = initialStateConfig.globalFilter ?? '';
|
|
711
|
+
const resetColumnFilter =
|
|
712
|
+
initialStateConfig.columnFilter || { filters: [], logic: 'AND', pendingFilters: [], pendingLogic: 'AND' };
|
|
932
713
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
// Use table's setColumnSizing method
|
|
937
|
-
const currentSizing = table.getState().columnSizing;
|
|
938
|
-
table.setColumnSizing({
|
|
939
|
-
...currentSizing,
|
|
940
|
-
[columnId]: width,
|
|
941
|
-
});
|
|
942
|
-
},
|
|
943
|
-
autoSizeColumn: (columnId: string) => {
|
|
944
|
-
// TanStack doesn't have built-in auto-size, so reset to default
|
|
945
|
-
table.getColumn(columnId)?.resetSize();
|
|
946
|
-
},
|
|
947
|
-
autoSizeAllColumns: () => {
|
|
948
|
-
const initialSizing = initialStateConfig.columnSizing || {};
|
|
949
|
-
table.setColumnSizing(initialSizing);
|
|
950
|
-
// Manually trigger handler to ensure callbacks are called
|
|
951
|
-
handleColumnSizingChange(initialSizing);
|
|
952
|
-
},
|
|
953
|
-
resetColumnSizing: () => {
|
|
954
|
-
const initialSizing = initialStateConfig.columnSizing || {};
|
|
955
|
-
table.setColumnSizing(initialSizing);
|
|
956
|
-
// Manually trigger handler to ensure callbacks are called
|
|
957
|
-
handleColumnSizingChange(initialSizing);
|
|
958
|
-
},
|
|
959
|
-
},
|
|
714
|
+
const resetPagination = enablePagination
|
|
715
|
+
? (initialStateConfig.pagination || { pageIndex: 0, pageSize: 10 })
|
|
716
|
+
: undefined;
|
|
960
717
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
},
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
},
|
|
969
|
-
setColumnFilters: (filters: ColumnFilterState) => {
|
|
970
|
-
handleColumnFilterStateChange(filters);
|
|
971
|
-
},
|
|
972
|
-
addColumnFilter: (columnId: string, operator: string, value: any) => {
|
|
973
|
-
const newFilter = {
|
|
974
|
-
id: `filter_${Date.now()}`,
|
|
975
|
-
columnId,
|
|
976
|
-
operator,
|
|
977
|
-
value,
|
|
978
|
-
};
|
|
979
|
-
const columnFilter = table.getState().columnFilter;
|
|
980
|
-
|
|
981
|
-
const currentFilters = columnFilter.filters || [];
|
|
982
|
-
const newFilters = [...currentFilters, newFilter];
|
|
983
|
-
handleColumnFilterStateChange({
|
|
984
|
-
filters: newFilters,
|
|
985
|
-
logic: columnFilter.logic,
|
|
986
|
-
pendingFilters: columnFilter.pendingFilters || [],
|
|
987
|
-
pendingLogic: columnFilter.pendingLogic || 'AND',
|
|
988
|
-
});
|
|
989
|
-
if (logger.isLevelEnabled('debug')) {
|
|
990
|
-
logger.debug(`Adding column filter ${columnId} ${operator} ${value}`, newFilters);
|
|
991
|
-
}
|
|
992
|
-
},
|
|
993
|
-
removeColumnFilter: (filterId: string) => {
|
|
994
|
-
const columnFilter = table.getState().columnFilter;
|
|
995
|
-
const currentFilters = columnFilter.filters || [];
|
|
996
|
-
const newFilters = currentFilters.filter((f: any) => f.id !== filterId);
|
|
997
|
-
handleColumnFilterStateChange({
|
|
998
|
-
filters: newFilters,
|
|
999
|
-
logic: columnFilter.logic,
|
|
1000
|
-
pendingFilters: columnFilter.pendingFilters || [],
|
|
1001
|
-
pendingLogic: columnFilter.pendingLogic || 'AND',
|
|
1002
|
-
});
|
|
1003
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1004
|
-
logger.debug(`Removing column filter ${filterId}`, newFilters);
|
|
1005
|
-
}
|
|
1006
|
-
},
|
|
1007
|
-
clearAllFilters: () => {
|
|
1008
|
-
table.setGlobalFilter('');
|
|
1009
|
-
handleColumnFilterStateChange({
|
|
1010
|
-
filters: [],
|
|
1011
|
-
logic: 'AND',
|
|
1012
|
-
pendingFilters: [],
|
|
1013
|
-
pendingLogic: 'AND',
|
|
1014
|
-
});
|
|
1015
|
-
},
|
|
1016
|
-
resetFilters: () => {
|
|
1017
|
-
handleColumnFilterStateChange({
|
|
1018
|
-
filters: [],
|
|
1019
|
-
logic: 'AND',
|
|
1020
|
-
pendingFilters: [],
|
|
1021
|
-
pendingLogic: 'AND',
|
|
1022
|
-
});
|
|
1023
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1024
|
-
logger.debug('Resetting filters');
|
|
1025
|
-
}
|
|
1026
|
-
},
|
|
1027
|
-
},
|
|
718
|
+
return {
|
|
719
|
+
sorting: resetSorting,
|
|
720
|
+
globalFilter: resetGlobalFilter,
|
|
721
|
+
columnFilter: resetColumnFilter,
|
|
722
|
+
...(resetPagination ? { pagination: resetPagination } : {}),
|
|
723
|
+
};
|
|
724
|
+
}, [initialStateConfig, enablePagination]);
|
|
1028
725
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
setSorting: (sortingState: SortingState) => {
|
|
1032
|
-
table.setSorting(sortingState);
|
|
1033
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1034
|
-
logger.debug(`Setting sorting`, sortingState);
|
|
1035
|
-
}
|
|
1036
|
-
},
|
|
1037
|
-
sortColumn: (columnId: string, direction: 'asc' | 'desc' | false) => {
|
|
1038
|
-
const column = table.getColumn(columnId);
|
|
1039
|
-
if (!column) return;
|
|
1040
|
-
|
|
1041
|
-
if (direction === false) {
|
|
1042
|
-
column.clearSorting();
|
|
1043
|
-
} else {
|
|
1044
|
-
column.toggleSorting(direction === 'desc');
|
|
1045
|
-
}
|
|
1046
|
-
},
|
|
1047
|
-
clearSorting: () => {
|
|
1048
|
-
table.setSorting([]);
|
|
1049
|
-
// Manually trigger handler to ensure callbacks are called
|
|
1050
|
-
handleSortingChange([]);
|
|
1051
|
-
},
|
|
1052
|
-
resetSorting: () => {
|
|
1053
|
-
const initialSorting = initialStateConfig.sorting || [];
|
|
1054
|
-
table.setSorting(initialSorting);
|
|
1055
|
-
// Manually trigger handler to ensure callbacks are called
|
|
1056
|
-
handleSortingChange(initialSorting);
|
|
1057
|
-
},
|
|
1058
|
-
},
|
|
726
|
+
const resetAllAndReload = useCallback(() => {
|
|
727
|
+
const resetState = getResetState();
|
|
1059
728
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
if (
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
729
|
+
setSorting(resetState.sorting || []);
|
|
730
|
+
setGlobalFilter(resetState.globalFilter ?? '');
|
|
731
|
+
setColumnFilter(resetState.columnFilter as any);
|
|
732
|
+
|
|
733
|
+
if (resetState.pagination) setPagination(resetState.pagination);
|
|
734
|
+
|
|
735
|
+
setSelectionState(initialSelectionState);
|
|
736
|
+
setExpanded({});
|
|
737
|
+
|
|
738
|
+
// layout state
|
|
739
|
+
setColumnVisibility(initialStateConfig.columnVisibility || {});
|
|
740
|
+
setColumnSizing(initialStateConfig.columnSizing || {});
|
|
741
|
+
setColumnOrder(initialStateConfig.columnOrder || []);
|
|
742
|
+
setColumnPinning(initialStateConfig.columnPinning || { left: [], right: [] });
|
|
743
|
+
|
|
744
|
+
if (onFetchData) fetchData(resetState, { delay: 0 });
|
|
745
|
+
}, [getResetState, initialSelectionState, initialStateConfig, onFetchData, fetchData]);
|
|
746
|
+
|
|
747
|
+
const dataTableApi = useMemo(() => {
|
|
748
|
+
// helpers (avoid repeating boilerplate)
|
|
749
|
+
const buildInitialOrder = () =>
|
|
750
|
+
enhancedColumns.map((col, index) => {
|
|
751
|
+
if ((col as any).id) return (col as any).id as string;
|
|
752
|
+
const anyCol = col as any;
|
|
753
|
+
if (anyCol.accessorKey && typeof anyCol.accessorKey === "string") return anyCol.accessorKey;
|
|
754
|
+
return `column_${index}`;
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
const applyColumnOrder = (next: ColumnOrderState) => {
|
|
758
|
+
// handleColumnOrderChange supports both Updater<ColumnOrderState> and array in your impl
|
|
759
|
+
handleColumnOrderChange(next as any);
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
const applyPinning = (next: ColumnPinningState) => {
|
|
763
|
+
handleColumnPinningChange(next as any);
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
const applyVisibility = (next: Record<string, boolean>) => {
|
|
767
|
+
handleColumnVisibilityChange(next as any);
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
const applySizing = (next: Record<string, number>) => {
|
|
771
|
+
handleColumnSizingChange(next as any);
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
const applyPagination = (next: any) => {
|
|
775
|
+
handlePaginationChange(next);
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
const applySorting = (next: any) => {
|
|
779
|
+
handleSortingChange(next);
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
const applyGlobalFilter = (next: any) => {
|
|
783
|
+
handleGlobalFilterChange(next);
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
return {
|
|
787
|
+
table: {
|
|
788
|
+
getTable: () => table,
|
|
789
|
+
},
|
|
790
|
+
|
|
791
|
+
// -------------------------------
|
|
792
|
+
// Column Management
|
|
793
|
+
// -------------------------------
|
|
794
|
+
columnVisibility: {
|
|
795
|
+
showColumn: (columnId: string) => {
|
|
796
|
+
applyVisibility({ ...table.getState().columnVisibility, [columnId]: true });
|
|
797
|
+
},
|
|
798
|
+
hideColumn: (columnId: string) => {
|
|
799
|
+
applyVisibility({ ...table.getState().columnVisibility, [columnId]: false });
|
|
800
|
+
},
|
|
801
|
+
toggleColumn: (columnId: string) => {
|
|
802
|
+
const curr = table.getState().columnVisibility?.[columnId] ?? true;
|
|
803
|
+
applyVisibility({ ...table.getState().columnVisibility, [columnId]: !curr });
|
|
804
|
+
},
|
|
805
|
+
showAllColumns: () => {
|
|
806
|
+
// set all known columns true
|
|
807
|
+
const all: Record<string, boolean> = {};
|
|
808
|
+
table.getAllLeafColumns().forEach((c) => (all[c.id] = true));
|
|
809
|
+
applyVisibility(all);
|
|
810
|
+
},
|
|
811
|
+
hideAllColumns: () => {
|
|
812
|
+
const all: Record<string, boolean> = {};
|
|
813
|
+
table.getAllLeafColumns().forEach((c) => (all[c.id] = false));
|
|
814
|
+
applyVisibility(all);
|
|
815
|
+
},
|
|
816
|
+
resetColumnVisibility: () => {
|
|
817
|
+
const initialVisibility = initialStateConfig.columnVisibility || {};
|
|
818
|
+
applyVisibility(initialVisibility);
|
|
819
|
+
},
|
|
820
|
+
},
|
|
821
|
+
|
|
822
|
+
// -------------------------------
|
|
823
|
+
// Column Ordering
|
|
824
|
+
// -------------------------------
|
|
825
|
+
columnOrdering: {
|
|
826
|
+
setColumnOrder: (nextOrder: ColumnOrderState) => {
|
|
827
|
+
applyColumnOrder(nextOrder);
|
|
828
|
+
},
|
|
829
|
+
moveColumn: (columnId: string, toIndex: number) => {
|
|
830
|
+
const currentOrder =
|
|
831
|
+
(table.getState().columnOrder?.length ? table.getState().columnOrder : buildInitialOrder()) || [];
|
|
832
|
+
const fromIndex = currentOrder.indexOf(columnId);
|
|
833
|
+
if (fromIndex === -1) return;
|
|
834
|
+
|
|
835
|
+
const next = [...currentOrder];
|
|
836
|
+
next.splice(fromIndex, 1);
|
|
837
|
+
next.splice(toIndex, 0, columnId);
|
|
838
|
+
|
|
839
|
+
applyColumnOrder(next);
|
|
840
|
+
},
|
|
841
|
+
resetColumnOrder: () => {
|
|
842
|
+
applyColumnOrder(buildInitialOrder());
|
|
843
|
+
},
|
|
844
|
+
},
|
|
845
|
+
|
|
846
|
+
// -------------------------------
|
|
847
|
+
// Column Pinning
|
|
848
|
+
// -------------------------------
|
|
849
|
+
columnPinning: {
|
|
850
|
+
pinColumnLeft: (columnId: string) => {
|
|
851
|
+
const current = table.getState().columnPinning || { left: [], right: [] };
|
|
852
|
+
const next: ColumnPinningState = {
|
|
853
|
+
left: [...(current.left || []).filter((id) => id !== columnId), columnId],
|
|
854
|
+
right: (current.right || []).filter((id) => id !== columnId),
|
|
855
|
+
};
|
|
856
|
+
applyPinning(next);
|
|
857
|
+
},
|
|
858
|
+
pinColumnRight: (columnId: string) => {
|
|
859
|
+
const current = table.getState().columnPinning || { left: [], right: [] };
|
|
860
|
+
const next: ColumnPinningState = {
|
|
861
|
+
left: (current.left || []).filter((id) => id !== columnId),
|
|
862
|
+
// keep your "prepend" behavior
|
|
863
|
+
right: [columnId, ...(current.right || []).filter((id) => id !== columnId)],
|
|
864
|
+
};
|
|
865
|
+
applyPinning(next);
|
|
866
|
+
},
|
|
867
|
+
unpinColumn: (columnId: string) => {
|
|
868
|
+
const current = table.getState().columnPinning || { left: [], right: [] };
|
|
869
|
+
const next: ColumnPinningState = {
|
|
870
|
+
left: (current.left || []).filter((id) => id !== columnId),
|
|
871
|
+
right: (current.right || []).filter((id) => id !== columnId),
|
|
872
|
+
};
|
|
873
|
+
applyPinning(next);
|
|
874
|
+
},
|
|
875
|
+
setPinning: (pinning: ColumnPinningState) => {
|
|
876
|
+
applyPinning(pinning);
|
|
877
|
+
},
|
|
878
|
+
resetColumnPinning: () => {
|
|
879
|
+
const initialPinning = initialStateConfig.columnPinning || { left: [], right: [] };
|
|
880
|
+
applyPinning(initialPinning);
|
|
881
|
+
},
|
|
882
|
+
},
|
|
883
|
+
|
|
884
|
+
// -------------------------------
|
|
885
|
+
// Column Resizing
|
|
886
|
+
// -------------------------------
|
|
887
|
+
columnResizing: {
|
|
888
|
+
resizeColumn: (columnId: string, width: number) => {
|
|
889
|
+
const currentSizing = table.getState().columnSizing || {};
|
|
890
|
+
applySizing({ ...currentSizing, [columnId]: width });
|
|
891
|
+
},
|
|
892
|
+
autoSizeColumn: (columnId: string) => {
|
|
893
|
+
// safe to call tanstack helper; it will feed into onColumnSizingChange if wired,
|
|
894
|
+
// but since you're controlled, we still prefer to update through handler:
|
|
895
|
+
const col = table.getColumn(columnId);
|
|
896
|
+
if (!col) return;
|
|
897
|
+
|
|
898
|
+
col.resetSize();
|
|
899
|
+
// after resetSize, read state and emit via handler so controlled stays synced
|
|
900
|
+
applySizing({ ...(table.getState().columnSizing || {}) });
|
|
901
|
+
},
|
|
902
|
+
autoSizeAllColumns: () => {
|
|
903
|
+
const initialSizing = initialStateConfig.columnSizing || {};
|
|
904
|
+
applySizing(initialSizing);
|
|
905
|
+
},
|
|
906
|
+
resetColumnSizing: () => {
|
|
907
|
+
const initialSizing = initialStateConfig.columnSizing || {};
|
|
908
|
+
applySizing(initialSizing);
|
|
909
|
+
},
|
|
910
|
+
},
|
|
911
|
+
|
|
912
|
+
// -------------------------------
|
|
913
|
+
// Filtering
|
|
914
|
+
// -------------------------------
|
|
915
|
+
filtering: {
|
|
916
|
+
setGlobalFilter: (filter: string) => {
|
|
917
|
+
applyGlobalFilter(filter);
|
|
918
|
+
},
|
|
919
|
+
clearGlobalFilter: () => {
|
|
920
|
+
applyGlobalFilter("");
|
|
921
|
+
},
|
|
922
|
+
setColumnFilters: (filters: ColumnFilterState) => {
|
|
923
|
+
handleColumnFilterStateChange(filters);
|
|
924
|
+
},
|
|
925
|
+
addColumnFilter: (columnId: string, operator: string, value: any) => {
|
|
926
|
+
const newFilter = {
|
|
927
|
+
id: `filter_${Date.now()}`,
|
|
928
|
+
columnId,
|
|
929
|
+
operator,
|
|
930
|
+
value,
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
const current = table.getState().columnFilter;
|
|
934
|
+
const currentFilters = current?.filters || [];
|
|
935
|
+
const nextFilters = [...currentFilters, newFilter];
|
|
936
|
+
|
|
937
|
+
handleColumnFilterStateChange({
|
|
938
|
+
filters: nextFilters,
|
|
939
|
+
logic: current?.logic,
|
|
940
|
+
pendingFilters: current?.pendingFilters || [],
|
|
941
|
+
pendingLogic: current?.pendingLogic || "AND",
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
if (logger.isLevelEnabled("debug")) {
|
|
945
|
+
logger.debug(`Adding column filter ${columnId} ${operator} ${value}`, nextFilters);
|
|
1098
946
|
}
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
947
|
+
},
|
|
948
|
+
removeColumnFilter: (filterId: string) => {
|
|
949
|
+
const current = table.getState().columnFilter;
|
|
950
|
+
const currentFilters = current?.filters || [];
|
|
951
|
+
const nextFilters = currentFilters.filter((f: any) => f.id !== filterId);
|
|
952
|
+
|
|
953
|
+
handleColumnFilterStateChange({
|
|
954
|
+
filters: nextFilters,
|
|
955
|
+
logic: current?.logic,
|
|
956
|
+
pendingFilters: current?.pendingFilters || [],
|
|
957
|
+
pendingLogic: current?.pendingLogic || "AND",
|
|
958
|
+
});
|
|
1108
959
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
960
|
+
if (logger.isLevelEnabled("debug")) {
|
|
961
|
+
logger.debug(`Removing column filter ${filterId}`, nextFilters);
|
|
962
|
+
}
|
|
963
|
+
},
|
|
964
|
+
clearAllFilters: () => {
|
|
965
|
+
applyGlobalFilter("");
|
|
966
|
+
handleColumnFilterStateChange({
|
|
967
|
+
filters: [],
|
|
968
|
+
logic: "AND",
|
|
969
|
+
pendingFilters: [],
|
|
970
|
+
pendingLogic: "AND",
|
|
971
|
+
});
|
|
972
|
+
},
|
|
973
|
+
resetFilters: () => {
|
|
974
|
+
handleColumnFilterStateChange({
|
|
975
|
+
filters: [],
|
|
976
|
+
logic: "AND",
|
|
977
|
+
pendingFilters: [],
|
|
978
|
+
pendingLogic: "AND",
|
|
979
|
+
});
|
|
1122
980
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
981
|
+
if (logger.isLevelEnabled("debug")) {
|
|
982
|
+
logger.debug("Resetting filters");
|
|
983
|
+
}
|
|
984
|
+
},
|
|
985
|
+
},
|
|
986
|
+
|
|
987
|
+
// -------------------------------
|
|
988
|
+
// Sorting
|
|
989
|
+
// -------------------------------
|
|
990
|
+
sorting: {
|
|
991
|
+
setSorting: (sortingState: SortingState) => {
|
|
992
|
+
applySorting(sortingState);
|
|
993
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Setting sorting", sortingState);
|
|
994
|
+
},
|
|
995
|
+
|
|
996
|
+
// NOTE: toggleSorting is okay, but can become "one behind" in controlled server mode.
|
|
997
|
+
// So we implement deterministic sorting through handler.
|
|
998
|
+
sortColumn: (columnId: string, direction: "asc" | "desc" | false) => {
|
|
999
|
+
const current = table.getState().sorting || [];
|
|
1000
|
+
const filtered = current.filter((s: any) => s.id !== columnId);
|
|
1001
|
+
|
|
1002
|
+
if (direction === false) {
|
|
1003
|
+
applySorting(filtered);
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1141
1006
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1007
|
+
applySorting([{ id: columnId, desc: direction === "desc" }, ...filtered]);
|
|
1008
|
+
},
|
|
1009
|
+
|
|
1010
|
+
clearSorting: () => {
|
|
1011
|
+
applySorting([]);
|
|
1012
|
+
},
|
|
1013
|
+
resetSorting: () => {
|
|
1014
|
+
const initialSorting = initialStateConfig.sorting || [];
|
|
1015
|
+
applySorting(initialSorting);
|
|
1016
|
+
},
|
|
1017
|
+
},
|
|
1018
|
+
|
|
1019
|
+
// -------------------------------
|
|
1020
|
+
// Pagination
|
|
1021
|
+
// -------------------------------
|
|
1022
|
+
pagination: {
|
|
1023
|
+
goToPage: (pageIndex: number) => {
|
|
1024
|
+
applyPagination((prev: any) => ({ ...prev, pageIndex }));
|
|
1025
|
+
if (logger.isLevelEnabled("debug")) logger.debug(`Going to page ${pageIndex}`);
|
|
1026
|
+
},
|
|
1027
|
+
nextPage: () => {
|
|
1028
|
+
applyPagination((prev: any) => ({ ...prev, pageIndex: (prev?.pageIndex ?? 0) + 1 }));
|
|
1029
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Next page");
|
|
1030
|
+
},
|
|
1031
|
+
previousPage: () => {
|
|
1032
|
+
applyPagination((prev: any) => ({ ...prev, pageIndex: Math.max(0, (prev?.pageIndex ?? 0) - 1) }));
|
|
1033
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Previous page");
|
|
1034
|
+
},
|
|
1035
|
+
setPageSize: (pageSize: number) => {
|
|
1036
|
+
// usually want pageIndex reset
|
|
1037
|
+
applyPagination(() => ({ pageIndex: 0, pageSize }));
|
|
1038
|
+
if (logger.isLevelEnabled("debug")) logger.debug(`Setting page size to ${pageSize}`);
|
|
1039
|
+
},
|
|
1040
|
+
goToFirstPage: () => {
|
|
1041
|
+
applyPagination((prev: any) => ({ ...prev, pageIndex: 0 }));
|
|
1042
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Going to first page");
|
|
1043
|
+
},
|
|
1044
|
+
goToLastPage: () => {
|
|
1045
|
+
// pageCount can be derived; keep safe fallback
|
|
1046
|
+
const pageCount = table.getPageCount?.() ?? 0;
|
|
1047
|
+
if (pageCount > 0) {
|
|
1048
|
+
applyPagination((prev: any) => ({ ...prev, pageIndex: pageCount - 1 }));
|
|
1049
|
+
if (logger.isLevelEnabled("debug")) logger.debug(`Going to last page ${pageCount - 1}`);
|
|
1163
1050
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
}
|
|
1169
|
-
},
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1051
|
+
},
|
|
1052
|
+
resetPagination: () => {
|
|
1053
|
+
const initialPagination = initialStateConfig.pagination || { pageIndex: 0, pageSize: 10 };
|
|
1054
|
+
applyPagination(initialPagination);
|
|
1055
|
+
},
|
|
1056
|
+
},
|
|
1057
|
+
|
|
1058
|
+
// -------------------------------
|
|
1059
|
+
// Selection
|
|
1060
|
+
// -------------------------------
|
|
1061
|
+
selection: {
|
|
1062
|
+
selectRow: (rowId: string) => table.selectRow?.(rowId),
|
|
1063
|
+
deselectRow: (rowId: string) => table.deselectRow?.(rowId),
|
|
1064
|
+
toggleRowSelection: (rowId: string) => table.toggleRowSelected?.(rowId),
|
|
1065
|
+
selectAll: () => table.selectAll?.(),
|
|
1066
|
+
deselectAll: () => table.deselectAll?.(),
|
|
1067
|
+
toggleSelectAll: () => table.toggleAllRowsSelected?.(),
|
|
1068
|
+
getSelectionState: () => table.getSelectionState?.() || ({ ids: [], type: "include" } as const),
|
|
1069
|
+
getSelectedRows: () => table.getSelectedRows(),
|
|
1070
|
+
getSelectedCount: () => table.getSelectedCount(),
|
|
1071
|
+
isRowSelected: (rowId: string) => table.getIsRowSelected(rowId) || false,
|
|
1072
|
+
},
|
|
1073
|
+
|
|
1074
|
+
// -------------------------------
|
|
1075
|
+
// Data Management (kept same, but ensure state changes go through handlers)
|
|
1076
|
+
// -------------------------------
|
|
1077
|
+
data: {
|
|
1078
|
+
refresh: (resetPagination = false) => {
|
|
1079
|
+
const allState = table.getState();
|
|
1080
|
+
const current = allState.pagination;
|
|
1081
|
+
|
|
1082
|
+
const nextPagination = {
|
|
1083
|
+
pageIndex: resetPagination ? 0 : current?.pageIndex ?? 0,
|
|
1084
|
+
pageSize: current?.pageSize ?? initialStateConfig.pagination?.pageSize ?? 10,
|
|
1176
1085
|
};
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1086
|
+
|
|
1087
|
+
// must go through handler so server fetch triggers
|
|
1088
|
+
applyPagination(nextPagination);
|
|
1089
|
+
|
|
1090
|
+
// emit persisted state (your emitTableState effect will also do it)
|
|
1091
|
+
onDataStateChange?.({ ...allState, pagination: nextPagination });
|
|
1092
|
+
|
|
1093
|
+
fetchData?.({ pagination: nextPagination });
|
|
1094
|
+
|
|
1095
|
+
if (logger.isLevelEnabled("debug")) {
|
|
1096
|
+
logger.debug("Refreshing data", { nextPagination, allState });
|
|
1180
1097
|
}
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1098
|
+
},
|
|
1099
|
+
|
|
1100
|
+
reload: () => {
|
|
1101
|
+
const allState = table.getState();
|
|
1102
|
+
onDataStateChange?.(allState);
|
|
1103
|
+
fetchData?.();
|
|
1104
|
+
if (logger.isLevelEnabled("debug")) {
|
|
1105
|
+
logger.info("Reloading data", allState);
|
|
1106
|
+
}
|
|
1107
|
+
},
|
|
1108
|
+
|
|
1109
|
+
resetAll: () => resetAllAndReload({ resetLayout: true }),
|
|
1110
|
+
|
|
1111
|
+
getAllData: () => table.getRowModel().rows?.map((row) => row.original) || [],
|
|
1112
|
+
getRowData: (rowId: string) =>
|
|
1113
|
+
table.getRowModel().rows?.find((row) => String(row.original[idKey]) === rowId)?.original,
|
|
1114
|
+
getRowByIndex: (index: number) => table.getRowModel().rows?.[index]?.original,
|
|
1115
|
+
|
|
1116
|
+
updateRow: (rowId: string, updates: Partial<T>) => {
|
|
1117
|
+
const newData = table.getRowModel().rows?.map((row) =>
|
|
1118
|
+
String(row.original[idKey]) === rowId ? { ...row.original, ...updates } : row.original
|
|
1119
|
+
);
|
|
1120
|
+
setServerData?.(newData || []);
|
|
1121
|
+
if (logger.isLevelEnabled("debug")) logger.debug(`Updating row ${rowId}`, updates);
|
|
1122
|
+
},
|
|
1123
|
+
|
|
1124
|
+
updateRowByIndex: (index: number, updates: Partial<T>) => {
|
|
1125
|
+
const newData = table.getRowModel().rows?.map((row) => row.original) || [];
|
|
1126
|
+
if (newData[index]) {
|
|
1127
|
+
newData[index] = { ...newData[index]!, ...updates };
|
|
1128
|
+
setServerData(newData);
|
|
1129
|
+
if (logger.isLevelEnabled("debug")) logger.debug(`Updating row by index ${index}`, updates);
|
|
1130
|
+
}
|
|
1131
|
+
},
|
|
1132
|
+
|
|
1133
|
+
insertRow: (newRow: T, index?: number) => {
|
|
1134
|
+
const newData = table.getRowModel().rows?.map((row) => row.original) || [];
|
|
1135
|
+
if (index !== undefined) newData.splice(index, 0, newRow);
|
|
1136
|
+
else newData.push(newRow);
|
|
1137
|
+
setServerData(newData || []);
|
|
1138
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Inserting row", newRow);
|
|
1139
|
+
},
|
|
1140
|
+
|
|
1141
|
+
deleteRow: (rowId: string) => {
|
|
1142
|
+
const newData = (table.getRowModel().rows || []).filter((row) => String(row.original[idKey]) !== rowId);
|
|
1143
|
+
setServerData?.(newData.map((r) => r.original) || []);
|
|
1144
|
+
if (logger.isLevelEnabled("debug")) logger.debug(`Deleting row ${rowId}`);
|
|
1145
|
+
},
|
|
1146
|
+
|
|
1147
|
+
deleteRowByIndex: (index: number) => {
|
|
1148
|
+
const newData = (table.getRowModel().rows || []).map((row) => row.original);
|
|
1149
|
+
newData.splice(index, 1);
|
|
1150
|
+
setServerData(newData);
|
|
1151
|
+
if (logger.isLevelEnabled("debug")) logger.debug(`Deleting row by index ${index}`);
|
|
1152
|
+
},
|
|
1213
1153
|
|
|
1214
|
-
|
|
1215
|
-
|
|
1154
|
+
deleteSelectedRows: () => {
|
|
1155
|
+
const selectedRows = table.getSelectedRows?.() || [];
|
|
1156
|
+
if (selectedRows.length === 0) return;
|
|
1216
1157
|
|
|
1217
|
-
|
|
1218
|
-
|
|
1158
|
+
const selectedIds = new Set(selectedRows.map((row) => String(row.original[idKey])));
|
|
1159
|
+
const newData = (table.getRowModel().rows || [])
|
|
1160
|
+
.filter((row) => !selectedIds.has(String(row.original[idKey])))
|
|
1161
|
+
.map((row) => row.original);
|
|
1219
1162
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
}
|
|
1223
|
-
},
|
|
1224
|
-
replaceAllData: (newData: T[]) => {
|
|
1225
|
-
setServerData?.(newData);
|
|
1226
|
-
},
|
|
1163
|
+
setServerData(newData);
|
|
1164
|
+
table.deselectAll?.();
|
|
1227
1165
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
const updateMap = new Map(updates.map(u => [u.rowId, u.data]));
|
|
1231
|
-
const newData = (table.getRowModel().rows || [])?.map(row => {
|
|
1232
|
-
const rowId = String(row.original[idKey]);
|
|
1233
|
-
const updateData = updateMap.get(rowId);
|
|
1234
|
-
return updateData ? {
|
|
1235
|
-
...row.original,
|
|
1236
|
-
...updateData,
|
|
1237
|
-
} : row.original;
|
|
1238
|
-
});
|
|
1239
|
-
setServerData(newData || []);
|
|
1240
|
-
},
|
|
1241
|
-
insertMultipleRows: (newRows: T[], startIndex?: number) => {
|
|
1242
|
-
const newData = (table.getRowModel().rows || [])?.map(row => row.original);
|
|
1243
|
-
if (startIndex !== undefined) {
|
|
1244
|
-
newData.splice(startIndex, 0, ...newRows);
|
|
1245
|
-
} else {
|
|
1246
|
-
newData.push(...newRows);
|
|
1247
|
-
}
|
|
1248
|
-
setServerData?.(newData);
|
|
1249
|
-
},
|
|
1250
|
-
deleteMultipleRows: (rowIds: string[]) => {
|
|
1251
|
-
const idsToDelete = new Set(rowIds);
|
|
1252
|
-
const newData = (table.getRowModel().rows || [])?.filter(row => !idsToDelete.has(String(row.original[idKey])))?.map(row => row.original);
|
|
1253
|
-
setServerData(newData);
|
|
1254
|
-
},
|
|
1166
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Deleting selected rows");
|
|
1167
|
+
},
|
|
1255
1168
|
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
[
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
newData[
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
};
|
|
1169
|
+
replaceAllData: (newData: T[]) => setServerData?.(newData),
|
|
1170
|
+
|
|
1171
|
+
updateMultipleRows: (updates: Array<{ rowId: string; data: Partial<T> }>) => {
|
|
1172
|
+
const updateMap = new Map(updates.map((u) => [u.rowId, u.data]));
|
|
1173
|
+
const newData = (table.getRowModel().rows || []).map((row) => {
|
|
1174
|
+
const rowId = String(row.original[idKey]);
|
|
1175
|
+
const updateData = updateMap.get(rowId);
|
|
1176
|
+
return updateData ? { ...row.original, ...updateData } : row.original;
|
|
1177
|
+
});
|
|
1178
|
+
setServerData(newData || []);
|
|
1179
|
+
},
|
|
1180
|
+
|
|
1181
|
+
insertMultipleRows: (newRows: T[], startIndex?: number) => {
|
|
1182
|
+
const newData = (table.getRowModel().rows || []).map((row) => row.original);
|
|
1183
|
+
if (startIndex !== undefined) newData.splice(startIndex, 0, ...newRows);
|
|
1184
|
+
else newData.push(...newRows);
|
|
1273
1185
|
setServerData?.(newData);
|
|
1274
|
-
}
|
|
1275
|
-
},
|
|
1186
|
+
},
|
|
1276
1187
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
getDataCount: () => {
|
|
1285
|
-
return (table.getRowModel().rows || [])?.length || 0;
|
|
1286
|
-
},
|
|
1287
|
-
getFilteredDataCount: () => {
|
|
1288
|
-
return table.getFilteredRowModel().rows.length;
|
|
1289
|
-
},
|
|
1290
|
-
},
|
|
1188
|
+
deleteMultipleRows: (rowIds: string[]) => {
|
|
1189
|
+
const idsToDelete = new Set(rowIds);
|
|
1190
|
+
const newData = (table.getRowModel().rows || [])
|
|
1191
|
+
.filter((row) => !idsToDelete.has(String(row.original[idKey])))
|
|
1192
|
+
.map((row) => row.original);
|
|
1193
|
+
setServerData(newData);
|
|
1194
|
+
},
|
|
1291
1195
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
table.resetGlobalFilter();
|
|
1299
|
-
},
|
|
1300
|
-
resetAll: () => {
|
|
1301
|
-
// Reset everything to initial state
|
|
1302
|
-
table.resetColumnSizing();
|
|
1303
|
-
table.resetColumnVisibility();
|
|
1304
|
-
table.resetSorting();
|
|
1305
|
-
table.resetGlobalFilter();
|
|
1306
|
-
table.resetColumnOrder();
|
|
1307
|
-
table.resetExpanded();
|
|
1308
|
-
handleSelectionStateChange(initialSelectionState);
|
|
1309
|
-
table.resetColumnPinning();
|
|
1310
|
-
|
|
1311
|
-
handleColumnFilterStateChange(initialStateConfig.columnFilter || { filters: [], logic: 'AND', pendingFilters: [], pendingLogic: 'AND' });
|
|
1312
|
-
|
|
1313
|
-
if (enablePagination) {
|
|
1314
|
-
table.setPagination(initialStateConfig.pagination || { pageIndex: 0, pageSize: 10 });
|
|
1315
|
-
}
|
|
1196
|
+
updateField: (rowId: string, fieldName: keyof T, value: any) => {
|
|
1197
|
+
const newData = (table.getRowModel().rows || []).map((row) =>
|
|
1198
|
+
String(row.original[idKey]) === rowId ? { ...row.original, [fieldName]: value } : row.original
|
|
1199
|
+
);
|
|
1200
|
+
setServerData?.(newData);
|
|
1201
|
+
},
|
|
1316
1202
|
|
|
1317
|
-
|
|
1318
|
-
table.
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1203
|
+
updateFieldByIndex: (index: number, fieldName: keyof T, value: any) => {
|
|
1204
|
+
const newData = (table.getRowModel().rows || []).map((row) => row.original);
|
|
1205
|
+
if (newData[index]) {
|
|
1206
|
+
newData[index] = { ...newData[index], [fieldName]: value };
|
|
1207
|
+
setServerData?.(newData);
|
|
1208
|
+
}
|
|
1209
|
+
},
|
|
1210
|
+
|
|
1211
|
+
findRows: (predicate: (row: T) => boolean) =>
|
|
1212
|
+
(table.getRowModel().rows || []).filter((row) => predicate(row.original)).map((row) => row.original),
|
|
1213
|
+
|
|
1214
|
+
findRowIndex: (predicate: (row: T) => boolean) =>
|
|
1215
|
+
(table.getRowModel().rows || []).findIndex((row) => predicate(row.original)),
|
|
1216
|
+
|
|
1217
|
+
getDataCount: () => (table.getRowModel().rows || []).length || 0,
|
|
1218
|
+
getFilteredDataCount: () => table.getFilteredRowModel().rows.length,
|
|
1219
|
+
},
|
|
1220
|
+
|
|
1221
|
+
// -------------------------------
|
|
1222
|
+
// Layout Management
|
|
1223
|
+
// -------------------------------
|
|
1224
|
+
layout: {
|
|
1225
|
+
resetLayout: () => {
|
|
1226
|
+
// go through handlers so controlled state updates + emit works
|
|
1227
|
+
applySizing(initialStateConfig.columnSizing || {});
|
|
1228
|
+
applyVisibility(initialStateConfig.columnVisibility || {});
|
|
1229
|
+
applySorting(initialStateConfig.sorting || []);
|
|
1230
|
+
applyGlobalFilter(initialStateConfig.globalFilter ?? "");
|
|
1231
|
+
},
|
|
1232
|
+
resetAll: () => resetAllAndReload({ resetLayout: true }),
|
|
1233
|
+
saveLayout: () => ({
|
|
1323
1234
|
columnVisibility: table.getState().columnVisibility,
|
|
1324
1235
|
columnSizing: table.getState().columnSizing,
|
|
1325
1236
|
columnOrder: table.getState().columnOrder,
|
|
@@ -1328,119 +1239,138 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
1328
1239
|
pagination: table.getState().pagination,
|
|
1329
1240
|
globalFilter: table.getState().globalFilter,
|
|
1330
1241
|
columnFilter: table.getState().columnFilter,
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
sorting: table.getState().sorting,
|
|
1397
|
-
pagination: table.getState().pagination,
|
|
1398
|
-
};
|
|
1399
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1400
|
-
logger.debug('Server export CSV', { currentFilters });
|
|
1242
|
+
}),
|
|
1243
|
+
restoreLayout: (layout: Partial<TableState>) => {
|
|
1244
|
+
if (layout.columnVisibility) applyVisibility(layout.columnVisibility as any);
|
|
1245
|
+
if (layout.columnSizing) applySizing(layout.columnSizing as any);
|
|
1246
|
+
if (layout.columnOrder) applyColumnOrder(layout.columnOrder as any);
|
|
1247
|
+
if (layout.columnPinning) applyPinning(layout.columnPinning as any);
|
|
1248
|
+
if (layout.sorting) applySorting(layout.sorting as any);
|
|
1249
|
+
if (layout.pagination && enablePagination) applyPagination(layout.pagination as any);
|
|
1250
|
+
if (layout.globalFilter !== undefined) applyGlobalFilter(layout.globalFilter);
|
|
1251
|
+
if (layout.columnFilter) handleColumnFilterStateChange(layout.columnFilter as any);
|
|
1252
|
+
},
|
|
1253
|
+
},
|
|
1254
|
+
|
|
1255
|
+
// -------------------------------
|
|
1256
|
+
// Table State
|
|
1257
|
+
// -------------------------------
|
|
1258
|
+
state: {
|
|
1259
|
+
getTableState: () => table.getState(),
|
|
1260
|
+
getCurrentFilters: () => table.getState().columnFilter,
|
|
1261
|
+
getCurrentSorting: () => table.getState().sorting,
|
|
1262
|
+
getCurrentPagination: () => table.getState().pagination,
|
|
1263
|
+
getCurrentSelection: () => table.getSelectionState?.(),
|
|
1264
|
+
},
|
|
1265
|
+
|
|
1266
|
+
// -------------------------------
|
|
1267
|
+
// Export (unchanged mostly)
|
|
1268
|
+
// -------------------------------
|
|
1269
|
+
export: {
|
|
1270
|
+
exportCSV: async (options: any = {}) => {
|
|
1271
|
+
const { filename = exportFilename } = options;
|
|
1272
|
+
|
|
1273
|
+
try {
|
|
1274
|
+
const controller = new AbortController();
|
|
1275
|
+
setExportController?.(controller);
|
|
1276
|
+
|
|
1277
|
+
if (dataMode === "server" && onServerExport) {
|
|
1278
|
+
const currentFilters = {
|
|
1279
|
+
globalFilter: table.getState().globalFilter,
|
|
1280
|
+
columnFilter: table.getState().columnFilter,
|
|
1281
|
+
sorting: table.getState().sorting,
|
|
1282
|
+
pagination: table.getState().pagination,
|
|
1283
|
+
};
|
|
1284
|
+
|
|
1285
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Server export CSV", { currentFilters });
|
|
1286
|
+
|
|
1287
|
+
await exportServerData(table, {
|
|
1288
|
+
format: "csv",
|
|
1289
|
+
filename,
|
|
1290
|
+
fetchData: (filters: any, selection: any) => onServerExport(filters, selection),
|
|
1291
|
+
currentFilters,
|
|
1292
|
+
selection: table.getSelectionState?.(),
|
|
1293
|
+
onProgress: onExportProgress,
|
|
1294
|
+
onComplete: onExportComplete,
|
|
1295
|
+
onError: onExportError,
|
|
1296
|
+
});
|
|
1297
|
+
} else {
|
|
1298
|
+
await exportClientData(table, {
|
|
1299
|
+
format: "csv",
|
|
1300
|
+
filename,
|
|
1301
|
+
onProgress: onExportProgress,
|
|
1302
|
+
onComplete: onExportComplete,
|
|
1303
|
+
onError: onExportError,
|
|
1304
|
+
});
|
|
1305
|
+
|
|
1306
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Client export CSV", filename);
|
|
1401
1307
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1308
|
+
} catch (error: any) {
|
|
1309
|
+
onExportError?.({ message: error.message || "Export failed", code: "EXPORT_ERROR" });
|
|
1310
|
+
} finally {
|
|
1311
|
+
setExportController?.(null);
|
|
1312
|
+
}
|
|
1313
|
+
},
|
|
1314
|
+
|
|
1315
|
+
exportExcel: async (options: any = {}) => {
|
|
1316
|
+
const { filename = exportFilename } = options;
|
|
1317
|
+
|
|
1318
|
+
try {
|
|
1319
|
+
const controller = new AbortController();
|
|
1320
|
+
setExportController?.(controller);
|
|
1321
|
+
|
|
1322
|
+
if (dataMode === "server" && onServerExport) {
|
|
1323
|
+
const currentFilters = {
|
|
1324
|
+
globalFilter: table.getState().globalFilter,
|
|
1325
|
+
columnFilter: table.getState().columnFilter,
|
|
1326
|
+
sorting: table.getState().sorting,
|
|
1327
|
+
pagination: table.getState().pagination,
|
|
1328
|
+
};
|
|
1329
|
+
|
|
1330
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Server export Excel", { currentFilters });
|
|
1331
|
+
|
|
1332
|
+
await exportServerData(table, {
|
|
1333
|
+
format: "excel",
|
|
1334
|
+
filename,
|
|
1335
|
+
fetchData: (filters: any, selection: any) => onServerExport(filters, selection),
|
|
1336
|
+
currentFilters,
|
|
1337
|
+
selection: table.getSelectionState?.(),
|
|
1338
|
+
onProgress: onExportProgress,
|
|
1339
|
+
onComplete: onExportComplete,
|
|
1340
|
+
onError: onExportError,
|
|
1341
|
+
});
|
|
1342
|
+
} else {
|
|
1343
|
+
await exportClientData(table, {
|
|
1344
|
+
format: "excel",
|
|
1345
|
+
filename,
|
|
1346
|
+
onProgress: onExportProgress,
|
|
1347
|
+
onComplete: onExportComplete,
|
|
1348
|
+
onError: onExportError,
|
|
1349
|
+
});
|
|
1350
|
+
|
|
1351
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Client export Excel", filename);
|
|
1423
1352
|
}
|
|
1353
|
+
} catch (error: any) {
|
|
1354
|
+
onExportError?.({ message: error.message || "Export failed", code: "EXPORT_ERROR" });
|
|
1355
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Server export Excel failed", error);
|
|
1356
|
+
} finally {
|
|
1357
|
+
setExportController?.(null);
|
|
1424
1358
|
}
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
});
|
|
1430
|
-
} finally {
|
|
1431
|
-
setExportController?.(null);
|
|
1432
|
-
}
|
|
1433
|
-
},
|
|
1434
|
-
exportExcel: async (options: any = {}) => {
|
|
1435
|
-
const { filename = exportFilename } = options;
|
|
1359
|
+
},
|
|
1360
|
+
|
|
1361
|
+
exportServerData: async (options: any) => {
|
|
1362
|
+
const { format, filename = exportFilename, fetchData: fetchFn = onServerExport } = options;
|
|
1436
1363
|
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1364
|
+
if (!fetchFn) {
|
|
1365
|
+
onExportError?.({ message: "No server export function provided", code: "NO_SERVER_EXPORT" });
|
|
1366
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Server export data failed", "No server export function provided");
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
try {
|
|
1371
|
+
const controller = new AbortController();
|
|
1372
|
+
setExportController?.(controller);
|
|
1441
1373
|
|
|
1442
|
-
if (dataMode === 'server' && onServerExport) {
|
|
1443
|
-
// Server export with selection data
|
|
1444
1374
|
const currentFilters = {
|
|
1445
1375
|
globalFilter: table.getState().globalFilter,
|
|
1446
1376
|
columnFilter: table.getState().columnFilter,
|
|
@@ -1448,131 +1378,62 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
1448
1378
|
pagination: table.getState().pagination,
|
|
1449
1379
|
};
|
|
1450
1380
|
|
|
1451
|
-
if (logger.isLevelEnabled(
|
|
1452
|
-
|
|
1453
|
-
}
|
|
1381
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Server export data", { currentFilters });
|
|
1382
|
+
|
|
1454
1383
|
await exportServerData(table, {
|
|
1455
|
-
format
|
|
1384
|
+
format,
|
|
1456
1385
|
filename,
|
|
1457
|
-
fetchData: (filters, selection) =>
|
|
1386
|
+
fetchData: (filters: any, selection: any) => fetchFn(filters, selection),
|
|
1458
1387
|
currentFilters,
|
|
1459
1388
|
selection: table.getSelectionState?.(),
|
|
1460
1389
|
onProgress: onExportProgress,
|
|
1461
1390
|
onComplete: onExportComplete,
|
|
1462
1391
|
onError: onExportError,
|
|
1463
1392
|
});
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
onProgress: onExportProgress,
|
|
1470
|
-
onComplete: onExportComplete,
|
|
1471
|
-
onError: onExportError,
|
|
1472
|
-
});
|
|
1473
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1474
|
-
logger.debug('Client export Excel', filename);
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
} catch (error: any) {
|
|
1478
|
-
onExportError?.({
|
|
1479
|
-
message: error.message || 'Export failed',
|
|
1480
|
-
code: 'EXPORT_ERROR',
|
|
1481
|
-
});
|
|
1482
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1483
|
-
logger.debug('Server export Excel failed', error);
|
|
1393
|
+
} catch (error: any) {
|
|
1394
|
+
onExportError?.({ message: error.message || "Export failed", code: "EXPORT_ERROR" });
|
|
1395
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Server export data failed", error);
|
|
1396
|
+
} finally {
|
|
1397
|
+
setExportController?.(null);
|
|
1484
1398
|
}
|
|
1485
|
-
}
|
|
1486
|
-
setExportController?.(null);
|
|
1487
|
-
}
|
|
1488
|
-
},
|
|
1489
|
-
exportServerData: async (options) => {
|
|
1490
|
-
const {
|
|
1491
|
-
format,
|
|
1492
|
-
filename = exportFilename,
|
|
1493
|
-
fetchData = onServerExport,
|
|
1494
|
-
} = options;
|
|
1495
|
-
|
|
1496
|
-
if (!fetchData) {
|
|
1497
|
-
onExportError?.({
|
|
1498
|
-
message: 'No server export function provided',
|
|
1499
|
-
code: 'NO_SERVER_EXPORT',
|
|
1500
|
-
});
|
|
1501
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1502
|
-
logger.debug('Server export data failed', 'No server export function provided');
|
|
1503
|
-
}
|
|
1504
|
-
return;
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
try {
|
|
1508
|
-
// Create abort controller for this export
|
|
1509
|
-
const controller = new AbortController();
|
|
1510
|
-
setExportController?.(controller);
|
|
1399
|
+
},
|
|
1511
1400
|
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
sorting: table.getState().sorting,
|
|
1516
|
-
pagination: table.getState().pagination,
|
|
1517
|
-
};
|
|
1518
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1519
|
-
logger.debug('Server export data', { currentFilters });
|
|
1520
|
-
}
|
|
1521
|
-
await exportServerData(table, {
|
|
1522
|
-
format,
|
|
1523
|
-
filename,
|
|
1524
|
-
fetchData: (filters, selection) => fetchData(filters, selection),
|
|
1525
|
-
currentFilters,
|
|
1526
|
-
selection: table.getSelectionState?.(),
|
|
1527
|
-
onProgress: onExportProgress,
|
|
1528
|
-
onComplete: onExportComplete,
|
|
1529
|
-
onError: onExportError,
|
|
1530
|
-
});
|
|
1531
|
-
} catch (error: any) {
|
|
1532
|
-
onExportError?.({
|
|
1533
|
-
message: error.message || 'Export failed',
|
|
1534
|
-
code: 'EXPORT_ERROR',
|
|
1535
|
-
});
|
|
1536
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1537
|
-
logger.debug('Server export data failed', error);
|
|
1538
|
-
}
|
|
1539
|
-
} finally {
|
|
1401
|
+
isExporting: () => isExporting || false,
|
|
1402
|
+
cancelExport: () => {
|
|
1403
|
+
exportController?.abort();
|
|
1540
1404
|
setExportController?.(null);
|
|
1541
|
-
|
|
1405
|
+
if (logger.isLevelEnabled("debug")) logger.debug("Export cancelled");
|
|
1406
|
+
},
|
|
1542
1407
|
},
|
|
1543
|
-
|
|
1544
|
-
isExporting: () => isExporting || false,
|
|
1545
|
-
cancelExport: () => {
|
|
1546
|
-
exportController?.abort();
|
|
1547
|
-
setExportController?.(null);
|
|
1548
|
-
if (logger.isLevelEnabled('debug')) {
|
|
1549
|
-
logger.debug('Export cancelled');
|
|
1550
|
-
}
|
|
1551
|
-
},
|
|
1552
|
-
},
|
|
1408
|
+
};
|
|
1553
1409
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1554
|
-
}
|
|
1410
|
+
}, [
|
|
1555
1411
|
table,
|
|
1556
1412
|
enhancedColumns,
|
|
1413
|
+
handleColumnOrderChange,
|
|
1414
|
+
handleColumnPinningChange,
|
|
1415
|
+
handleColumnVisibilityChange,
|
|
1416
|
+
handleColumnSizingChange,
|
|
1417
|
+
handlePaginationChange,
|
|
1418
|
+
handleSortingChange,
|
|
1419
|
+
handleGlobalFilterChange,
|
|
1557
1420
|
handleColumnFilterStateChange,
|
|
1421
|
+
initialStateConfig,
|
|
1422
|
+
enablePagination,
|
|
1558
1423
|
idKey,
|
|
1559
1424
|
onDataStateChange,
|
|
1560
1425
|
fetchData,
|
|
1561
|
-
|
|
1562
|
-
enablePagination,
|
|
1563
|
-
// Export dependencies
|
|
1426
|
+
// export
|
|
1564
1427
|
exportFilename,
|
|
1565
1428
|
onExportProgress,
|
|
1566
1429
|
onExportComplete,
|
|
1567
1430
|
onExportError,
|
|
1568
1431
|
onServerExport,
|
|
1569
1432
|
exportController,
|
|
1570
|
-
setExportController,
|
|
1571
1433
|
isExporting,
|
|
1572
1434
|
dataMode,
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
// Note: custom selection removed from dependency array
|
|
1435
|
+
logger,
|
|
1436
|
+
resetAllAndReload,
|
|
1576
1437
|
]);
|
|
1577
1438
|
|
|
1578
1439
|
internalApiRef.current = dataTableApi;
|
|
@@ -1818,7 +1679,15 @@ export const DataTable = forwardRef<DataTableApi<any>, DataTableProps<any>>(func
|
|
|
1818
1679
|
enableReset={enableReset}
|
|
1819
1680
|
enableTableSizeControl={enableTableSizeControl}
|
|
1820
1681
|
enableColumnPinning={enableColumnPinning}
|
|
1682
|
+
enableRefresh={enableRefresh}
|
|
1821
1683
|
{...toolbarSlotProps}
|
|
1684
|
+
refreshButtonProps={{
|
|
1685
|
+
loading: tableLoading, // disable while fetching
|
|
1686
|
+
showSpinnerWhileLoading: false,
|
|
1687
|
+
onRefresh: () => internalApiRef.current?.data?.refresh?.(true),
|
|
1688
|
+
...toolbarSlotProps.refreshButtonProps,
|
|
1689
|
+
}}
|
|
1690
|
+
|
|
1822
1691
|
/>
|
|
1823
1692
|
) : null}
|
|
1824
1693
|
|