@ackplus/react-tanstack-data-table 1.1.11 → 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/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-export-control.d.ts.map +1 -1
- package/dist/lib/components/toolbar/table-export-control.js +46 -12
- 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/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 +1110 -946
- 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 +25 -18
- package/dist/lib/types/data-table-api.d.ts.map +1 -1
- package/dist/lib/types/data-table.types.d.ts +37 -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 +12 -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/dist/lib/utils/slot-helpers.d.ts +1 -1
- package/dist/lib/utils/slot-helpers.d.ts.map +1 -1
- 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/data-table-toolbar.tsx +15 -1
- package/src/lib/components/toolbar/table-export-control.tsx +65 -9
- package/src/lib/components/toolbar/table-refresh-control.tsx +58 -0
- package/src/lib/contexts/data-table-context.tsx +16 -2
- package/src/lib/data-table.tsx +1282 -932
- 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 +37 -15
- package/src/lib/types/data-table.types.ts +59 -3
- package/src/lib/types/export.types.ts +79 -10
- package/src/lib/types/slots.types.ts +11 -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/src/lib/utils/slot-helpers.tsx +1 -1
|
@@ -36,6 +36,135 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.exportClientData = exportClientData;
|
|
37
37
|
exports.exportServerData = exportServerData;
|
|
38
38
|
const XLSX = __importStar(require("xlsx"));
|
|
39
|
+
const EXPORT_CANCELLED_CODE = 'CANCELLED';
|
|
40
|
+
const DEFAULT_CHUNK_SIZE = 1000;
|
|
41
|
+
const MAX_SERVER_EXPORT_PAGES = 10000;
|
|
42
|
+
function createCancelledExportError() {
|
|
43
|
+
const error = new Error('Export cancelled');
|
|
44
|
+
error.name = 'AbortError';
|
|
45
|
+
error.code = EXPORT_CANCELLED_CODE;
|
|
46
|
+
return error;
|
|
47
|
+
}
|
|
48
|
+
function isCancelledError(error) {
|
|
49
|
+
if (!(error instanceof Error))
|
|
50
|
+
return false;
|
|
51
|
+
return error.name === 'AbortError' || error.code === EXPORT_CANCELLED_CODE;
|
|
52
|
+
}
|
|
53
|
+
function throwIfExportCancelled(signal) {
|
|
54
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
55
|
+
throw createCancelledExportError();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function waitWithAbort(ms, signal) {
|
|
59
|
+
if (!signal) {
|
|
60
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
61
|
+
}
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const timer = setTimeout(() => {
|
|
64
|
+
signal.removeEventListener('abort', onAbort);
|
|
65
|
+
resolve();
|
|
66
|
+
}, ms);
|
|
67
|
+
const onAbort = () => {
|
|
68
|
+
clearTimeout(timer);
|
|
69
|
+
signal.removeEventListener('abort', onAbort);
|
|
70
|
+
reject(createCancelledExportError());
|
|
71
|
+
};
|
|
72
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function notifyState(onStateChange, state) {
|
|
76
|
+
onStateChange === null || onStateChange === void 0 ? void 0 : onStateChange(state);
|
|
77
|
+
}
|
|
78
|
+
function isServerExportDataResult(result) {
|
|
79
|
+
return (!!result
|
|
80
|
+
&& typeof result === 'object'
|
|
81
|
+
&& 'data' in result
|
|
82
|
+
&& Array.isArray(result.data));
|
|
83
|
+
}
|
|
84
|
+
function isServerExportBlobResult(result) {
|
|
85
|
+
return (!!result
|
|
86
|
+
&& typeof result === 'object'
|
|
87
|
+
&& 'blob' in result
|
|
88
|
+
&& result.blob instanceof Blob);
|
|
89
|
+
}
|
|
90
|
+
function isServerExportFileUrlResult(result) {
|
|
91
|
+
return (!!result
|
|
92
|
+
&& typeof result === 'object'
|
|
93
|
+
&& typeof result.fileUrl === 'string');
|
|
94
|
+
}
|
|
95
|
+
function resolveExportHeader(columnDef, columnId) {
|
|
96
|
+
var _a;
|
|
97
|
+
const defaultHeader = typeof (columnDef === null || columnDef === void 0 ? void 0 : columnDef.header) === 'string' ? columnDef.header : columnId;
|
|
98
|
+
if ((columnDef === null || columnDef === void 0 ? void 0 : columnDef.exportHeader) === undefined || (columnDef === null || columnDef === void 0 ? void 0 : columnDef.exportHeader) === null) {
|
|
99
|
+
return defaultHeader;
|
|
100
|
+
}
|
|
101
|
+
if (typeof columnDef.exportHeader === 'function') {
|
|
102
|
+
return String((_a = columnDef.exportHeader({
|
|
103
|
+
columnId,
|
|
104
|
+
defaultHeader,
|
|
105
|
+
columnDef,
|
|
106
|
+
})) !== null && _a !== void 0 ? _a : defaultHeader);
|
|
107
|
+
}
|
|
108
|
+
return String(columnDef.exportHeader);
|
|
109
|
+
}
|
|
110
|
+
function applyExportValueTransform(columnDef, value, row, rowIndex, columnId) {
|
|
111
|
+
if (typeof (columnDef === null || columnDef === void 0 ? void 0 : columnDef.exportValue) === 'function') {
|
|
112
|
+
return columnDef.exportValue({
|
|
113
|
+
value,
|
|
114
|
+
row,
|
|
115
|
+
rowIndex,
|
|
116
|
+
columnId,
|
|
117
|
+
columnDef,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
function applyExportFormatTransform(columnDef, value, row, rowIndex, columnId) {
|
|
123
|
+
const format = columnDef === null || columnDef === void 0 ? void 0 : columnDef.exportFormat;
|
|
124
|
+
if (!format || format === 'auto') {
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
if (typeof format === 'function') {
|
|
128
|
+
return format({
|
|
129
|
+
value,
|
|
130
|
+
row,
|
|
131
|
+
rowIndex,
|
|
132
|
+
columnId,
|
|
133
|
+
columnDef,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (value === null || value === undefined) {
|
|
137
|
+
return '';
|
|
138
|
+
}
|
|
139
|
+
switch (format) {
|
|
140
|
+
case 'string':
|
|
141
|
+
return String(value);
|
|
142
|
+
case 'number':
|
|
143
|
+
return Number(value);
|
|
144
|
+
case 'boolean':
|
|
145
|
+
return Boolean(value);
|
|
146
|
+
case 'json':
|
|
147
|
+
return JSON.stringify(value);
|
|
148
|
+
case 'date':
|
|
149
|
+
if (value instanceof Date)
|
|
150
|
+
return value.toISOString();
|
|
151
|
+
return String(value);
|
|
152
|
+
default:
|
|
153
|
+
return value;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function normalizeExportValue(value) {
|
|
157
|
+
if (value === null || value === undefined) {
|
|
158
|
+
return '';
|
|
159
|
+
}
|
|
160
|
+
if (value instanceof Date) {
|
|
161
|
+
return value.toISOString();
|
|
162
|
+
}
|
|
163
|
+
if (typeof value === 'object') {
|
|
164
|
+
return JSON.stringify(value);
|
|
165
|
+
}
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
39
168
|
/**
|
|
40
169
|
* Export data for client-side tables
|
|
41
170
|
* - If rows are selected, export only selected rows
|
|
@@ -43,8 +172,11 @@ const XLSX = __importStar(require("xlsx"));
|
|
|
43
172
|
* - Only export visible columns
|
|
44
173
|
*/
|
|
45
174
|
async function exportClientData(table, options) {
|
|
46
|
-
|
|
175
|
+
var _a;
|
|
176
|
+
const { format, filename, onProgress, onComplete, onError, onStateChange, signal, sanitizeCSV = true } = options;
|
|
47
177
|
try {
|
|
178
|
+
throwIfExportCancelled(signal);
|
|
179
|
+
notifyState(onStateChange, { phase: 'starting' });
|
|
48
180
|
// Get selected rows if any are selected
|
|
49
181
|
// const selectedRowIds = Object.keys(table.getState().rowSelection).filter(
|
|
50
182
|
// key => table.getState().rowSelection[key]
|
|
@@ -56,36 +188,64 @@ async function exportClientData(table, options) {
|
|
|
56
188
|
const hasSelectedRows = selectedRows.length > 0;
|
|
57
189
|
const rowsToExport = hasSelectedRows ? selectedRows : table.getFilteredRowModel().rows;
|
|
58
190
|
// Prepare data for export - get all visible columns and their values, excluding hideInExport columns
|
|
59
|
-
const exportData =
|
|
191
|
+
const exportData = [];
|
|
192
|
+
const visibleColumns = table.getVisibleLeafColumns().filter((col) => col.columnDef.hideInExport !== true);
|
|
193
|
+
for (let index = 0; index < rowsToExport.length; index++) {
|
|
194
|
+
throwIfExportCancelled(signal);
|
|
195
|
+
const row = rowsToExport[index];
|
|
60
196
|
onProgress === null || onProgress === void 0 ? void 0 : onProgress({
|
|
61
197
|
processedRows: index + 1,
|
|
62
198
|
totalRows: rowsToExport.length,
|
|
63
199
|
percentage: Math.round(((index + 1) / rowsToExport.length) * 100),
|
|
64
200
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (columnDef.hideInExport === true) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const header = typeof columnDef.header === 'string' ? columnDef.header : cell.column.id;
|
|
74
|
-
// Use getValue() - it already handles all formatting
|
|
75
|
-
rowData[header] = cell.getValue() || '';
|
|
201
|
+
notifyState(onStateChange, {
|
|
202
|
+
phase: 'processing',
|
|
203
|
+
processedRows: index + 1,
|
|
204
|
+
totalRows: rowsToExport.length,
|
|
205
|
+
percentage: Math.round(((index + 1) / rowsToExport.length) * 100),
|
|
76
206
|
});
|
|
77
|
-
|
|
78
|
-
|
|
207
|
+
const rowData = {};
|
|
208
|
+
for (const column of visibleColumns) {
|
|
209
|
+
const columnDef = column.columnDef;
|
|
210
|
+
const header = resolveExportHeader(columnDef, column.id);
|
|
211
|
+
const cell = row.getVisibleCells().find((visibleCell) => visibleCell.column.id === column.id);
|
|
212
|
+
const baseValue = cell ? cell.getValue() : (_a = row === null || row === void 0 ? void 0 : row.original) === null || _a === void 0 ? void 0 : _a[column.id];
|
|
213
|
+
const transformedValue = applyExportFormatTransform(columnDef, applyExportValueTransform(columnDef, baseValue, row.original, index, column.id), row.original, index, column.id);
|
|
214
|
+
rowData[header] = normalizeExportValue(transformedValue);
|
|
215
|
+
}
|
|
216
|
+
exportData.push(rowData);
|
|
217
|
+
}
|
|
79
218
|
// Export the data
|
|
80
|
-
|
|
219
|
+
notifyState(onStateChange, {
|
|
220
|
+
phase: 'downloading',
|
|
221
|
+
processedRows: exportData.length,
|
|
222
|
+
totalRows: exportData.length,
|
|
223
|
+
percentage: 100,
|
|
224
|
+
});
|
|
225
|
+
await exportToFile(exportData, format, filename, signal, sanitizeCSV);
|
|
81
226
|
onComplete === null || onComplete === void 0 ? void 0 : onComplete({
|
|
82
227
|
success: true,
|
|
83
228
|
filename: `${filename}.${format === 'excel' ? 'xlsx' : 'csv'}`,
|
|
84
229
|
totalRows: exportData.length,
|
|
85
230
|
});
|
|
231
|
+
notifyState(onStateChange, {
|
|
232
|
+
phase: 'completed',
|
|
233
|
+
processedRows: exportData.length,
|
|
234
|
+
totalRows: exportData.length,
|
|
235
|
+
percentage: 100,
|
|
236
|
+
});
|
|
86
237
|
}
|
|
87
238
|
catch (error) {
|
|
239
|
+
if (isCancelledError(error)) {
|
|
240
|
+
notifyState(onStateChange, { phase: 'cancelled', code: EXPORT_CANCELLED_CODE });
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
88
243
|
console.error('Client export failed:', error);
|
|
244
|
+
notifyState(onStateChange, {
|
|
245
|
+
phase: 'error',
|
|
246
|
+
message: error instanceof Error ? error.message : 'Export failed',
|
|
247
|
+
code: 'CLIENT_EXPORT_ERROR',
|
|
248
|
+
});
|
|
89
249
|
onError === null || onError === void 0 ? void 0 : onError({
|
|
90
250
|
message: error instanceof Error ? error.message : 'Export failed',
|
|
91
251
|
code: 'CLIENT_EXPORT_ERROR',
|
|
@@ -99,49 +259,126 @@ async function exportClientData(table, options) {
|
|
|
99
259
|
* - Export all returned data (server handles selection/filtering)
|
|
100
260
|
*/
|
|
101
261
|
async function exportServerData(table, options) {
|
|
102
|
-
|
|
262
|
+
var _a, _b, _c, _d;
|
|
263
|
+
const { format, filename, fetchData, currentFilters, selection, onProgress, onComplete, onError, onStateChange, signal, chunkSize = DEFAULT_CHUNK_SIZE, strictTotalCheck = false, sanitizeCSV = true, } = options;
|
|
103
264
|
try {
|
|
265
|
+
throwIfExportCancelled(signal);
|
|
266
|
+
notifyState(onStateChange, { phase: 'starting' });
|
|
104
267
|
// Initial progress
|
|
105
268
|
onProgress === null || onProgress === void 0 ? void 0 : onProgress({});
|
|
269
|
+
notifyState(onStateChange, { phase: 'fetching' });
|
|
106
270
|
// First, get total count to determine if we need chunking
|
|
107
271
|
const initialResponse = await fetchData({
|
|
108
272
|
...currentFilters,
|
|
109
273
|
pagination: { pageIndex: 0, pageSize: 1 }
|
|
110
|
-
}, selection);
|
|
111
|
-
if (
|
|
274
|
+
}, selection, signal);
|
|
275
|
+
if (isServerExportBlobResult(initialResponse)) {
|
|
276
|
+
throwIfExportCancelled(signal);
|
|
277
|
+
const resolvedName = initialResponse.filename || `${filename}.${format === 'excel' ? 'xlsx' : 'csv'}`;
|
|
278
|
+
notifyState(onStateChange, { phase: 'downloading' });
|
|
279
|
+
downloadFile(initialResponse.blob, resolvedName, initialResponse.mimeType || initialResponse.blob.type || 'application/octet-stream');
|
|
280
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete({
|
|
281
|
+
success: true,
|
|
282
|
+
filename: resolvedName,
|
|
283
|
+
totalRows: (_a = initialResponse.total) !== null && _a !== void 0 ? _a : 0,
|
|
284
|
+
});
|
|
285
|
+
notifyState(onStateChange, { phase: 'completed' });
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (isServerExportFileUrlResult(initialResponse)) {
|
|
289
|
+
throwIfExportCancelled(signal);
|
|
290
|
+
const resolvedName = initialResponse.filename || `${filename}.${format === 'excel' ? 'xlsx' : 'csv'}`;
|
|
291
|
+
notifyState(onStateChange, { phase: 'downloading' });
|
|
292
|
+
await downloadFromUrl(initialResponse.fileUrl, resolvedName, initialResponse.mimeType || 'application/octet-stream', signal);
|
|
293
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete({
|
|
294
|
+
success: true,
|
|
295
|
+
filename: resolvedName,
|
|
296
|
+
totalRows: (_b = initialResponse.total) !== null && _b !== void 0 ? _b : 0,
|
|
297
|
+
});
|
|
298
|
+
notifyState(onStateChange, { phase: 'completed' });
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (!isServerExportDataResult(initialResponse)) {
|
|
112
302
|
throw new Error('Invalid data received from server');
|
|
113
303
|
}
|
|
114
|
-
const totalRows = initialResponse.total
|
|
115
|
-
const CHUNK_SIZE = 1000; // Fetch 1000 rows per request
|
|
116
|
-
const needsChunking = totalRows > CHUNK_SIZE;
|
|
304
|
+
const totalRows = typeof initialResponse.total === 'number' ? initialResponse.total : initialResponse.data.length;
|
|
117
305
|
let allData = [];
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
306
|
+
const hasTotal = typeof totalRows === 'number' && totalRows >= 0;
|
|
307
|
+
for (let page = 0; page < MAX_SERVER_EXPORT_PAGES; page++) {
|
|
308
|
+
throwIfExportCancelled(signal);
|
|
309
|
+
const chunkFilters = {
|
|
310
|
+
...currentFilters,
|
|
311
|
+
pagination: {
|
|
312
|
+
pageIndex: page,
|
|
313
|
+
pageSize: chunkSize,
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
const chunkResponse = await fetchData(chunkFilters, selection, signal);
|
|
317
|
+
if (isServerExportBlobResult(chunkResponse)) {
|
|
318
|
+
throwIfExportCancelled(signal);
|
|
319
|
+
const resolvedName = chunkResponse.filename || `${filename}.${format === 'excel' ? 'xlsx' : 'csv'}`;
|
|
320
|
+
notifyState(onStateChange, { phase: 'downloading' });
|
|
321
|
+
downloadFile(chunkResponse.blob, resolvedName, chunkResponse.mimeType || chunkResponse.blob.type || 'application/octet-stream');
|
|
322
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete({
|
|
323
|
+
success: true,
|
|
324
|
+
filename: resolvedName,
|
|
325
|
+
totalRows: (_c = chunkResponse.total) !== null && _c !== void 0 ? _c : allData.length,
|
|
326
|
+
});
|
|
327
|
+
notifyState(onStateChange, { phase: 'completed' });
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (isServerExportFileUrlResult(chunkResponse)) {
|
|
331
|
+
throwIfExportCancelled(signal);
|
|
332
|
+
const resolvedName = chunkResponse.filename || `${filename}.${format === 'excel' ? 'xlsx' : 'csv'}`;
|
|
333
|
+
notifyState(onStateChange, { phase: 'downloading' });
|
|
334
|
+
await downloadFromUrl(chunkResponse.fileUrl, resolvedName, chunkResponse.mimeType || 'application/octet-stream', signal);
|
|
335
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete({
|
|
336
|
+
success: true,
|
|
337
|
+
filename: resolvedName,
|
|
338
|
+
totalRows: (_d = chunkResponse.total) !== null && _d !== void 0 ? _d : allData.length,
|
|
339
|
+
});
|
|
340
|
+
notifyState(onStateChange, { phase: 'completed' });
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (!isServerExportDataResult(chunkResponse)) {
|
|
344
|
+
throw new Error(`Failed to fetch chunk ${page + 1}`);
|
|
345
|
+
}
|
|
346
|
+
const chunkData = chunkResponse.data;
|
|
347
|
+
if (chunkData.length === 0) {
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
allData.push(...chunkData);
|
|
351
|
+
const percentage = hasTotal && totalRows > 0
|
|
352
|
+
? Math.min(100, Math.round((allData.length / totalRows) * 100))
|
|
353
|
+
: undefined;
|
|
354
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress({
|
|
355
|
+
processedRows: allData.length,
|
|
356
|
+
totalRows: hasTotal ? totalRows : undefined,
|
|
357
|
+
percentage,
|
|
358
|
+
});
|
|
359
|
+
notifyState(onStateChange, {
|
|
360
|
+
phase: 'fetching',
|
|
361
|
+
processedRows: allData.length,
|
|
362
|
+
totalRows: hasTotal ? totalRows : undefined,
|
|
363
|
+
percentage,
|
|
364
|
+
});
|
|
365
|
+
if (hasTotal) {
|
|
366
|
+
if (allData.length >= totalRows) {
|
|
367
|
+
break;
|
|
138
368
|
}
|
|
139
369
|
}
|
|
370
|
+
else if (chunkData.length < chunkSize) {
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
await waitWithAbort(100, signal);
|
|
374
|
+
}
|
|
375
|
+
if (hasTotal && allData.length > totalRows) {
|
|
376
|
+
allData = allData.slice(0, totalRows);
|
|
140
377
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
allData = initialResponse.data;
|
|
378
|
+
if (hasTotal && strictTotalCheck && allData.length < totalRows) {
|
|
379
|
+
throw new Error(`Expected ${totalRows} rows for export but received ${allData.length}`);
|
|
144
380
|
}
|
|
381
|
+
throwIfExportCancelled(signal);
|
|
145
382
|
// Get visible columns for proper headers and data processing, excluding hideInExport columns
|
|
146
383
|
const visibleColumns = table.getVisibleLeafColumns().filter(col => {
|
|
147
384
|
const columnDef = col.columnDef;
|
|
@@ -150,44 +387,59 @@ async function exportServerData(table, options) {
|
|
|
150
387
|
// Prepare data for export with proper column processing
|
|
151
388
|
const exportData = [];
|
|
152
389
|
for (let index = 0; index < allData.length; index++) {
|
|
390
|
+
throwIfExportCancelled(signal);
|
|
153
391
|
const rowData = allData[index];
|
|
154
392
|
const exportRow = {};
|
|
155
393
|
visibleColumns.forEach(column => {
|
|
156
|
-
var _a;
|
|
157
394
|
const columnId = column.id;
|
|
158
395
|
const columnDef = column.columnDef;
|
|
159
|
-
const header =
|
|
160
|
-
? columnDef.header
|
|
161
|
-
: columnId;
|
|
396
|
+
const header = resolveExportHeader(columnDef, columnId);
|
|
162
397
|
// Get value from raw data
|
|
163
398
|
let value = rowData[columnId];
|
|
164
399
|
// Apply accessorFn if defined
|
|
165
400
|
if (column.accessorFn && typeof column.accessorFn === 'function') {
|
|
166
|
-
value =
|
|
167
|
-
}
|
|
168
|
-
// Convert to string for export
|
|
169
|
-
if (value === null || value === undefined) {
|
|
170
|
-
value = '';
|
|
171
|
-
}
|
|
172
|
-
else if (typeof value === 'object') {
|
|
173
|
-
value = JSON.stringify(value);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
value = String(value);
|
|
401
|
+
value = column.accessorFn(rowData, index);
|
|
177
402
|
}
|
|
403
|
+
value = applyExportValueTransform(columnDef, value, rowData, index, columnId);
|
|
404
|
+
value = applyExportFormatTransform(columnDef, value, rowData, index, columnId);
|
|
405
|
+
value = normalizeExportValue(value);
|
|
178
406
|
exportRow[header] = value;
|
|
179
407
|
});
|
|
180
408
|
exportData.push(exportRow);
|
|
409
|
+
if (allData.length > 0) {
|
|
410
|
+
notifyState(onStateChange, {
|
|
411
|
+
phase: 'processing',
|
|
412
|
+
processedRows: index + 1,
|
|
413
|
+
totalRows: allData.length,
|
|
414
|
+
percentage: Math.round(((index + 1) / allData.length) * 100),
|
|
415
|
+
});
|
|
416
|
+
}
|
|
181
417
|
}
|
|
182
|
-
|
|
418
|
+
notifyState(onStateChange, { phase: 'downloading' });
|
|
419
|
+
await exportToFile(exportData, format, filename, signal, sanitizeCSV);
|
|
183
420
|
onComplete === null || onComplete === void 0 ? void 0 : onComplete({
|
|
184
421
|
success: true,
|
|
185
422
|
filename: `${filename}.${format === 'excel' ? 'xlsx' : 'csv'}`,
|
|
186
423
|
totalRows: exportData.length,
|
|
187
424
|
});
|
|
425
|
+
notifyState(onStateChange, {
|
|
426
|
+
phase: 'completed',
|
|
427
|
+
processedRows: exportData.length,
|
|
428
|
+
totalRows: exportData.length,
|
|
429
|
+
percentage: 100,
|
|
430
|
+
});
|
|
188
431
|
}
|
|
189
432
|
catch (error) {
|
|
433
|
+
if (isCancelledError(error)) {
|
|
434
|
+
notifyState(onStateChange, { phase: 'cancelled', code: EXPORT_CANCELLED_CODE });
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
190
437
|
console.error('Server export failed:', error);
|
|
438
|
+
notifyState(onStateChange, {
|
|
439
|
+
phase: 'error',
|
|
440
|
+
message: error instanceof Error ? error.message : 'Export failed',
|
|
441
|
+
code: 'SERVER_EXPORT_ERROR',
|
|
442
|
+
});
|
|
191
443
|
onError === null || onError === void 0 ? void 0 : onError({
|
|
192
444
|
message: error instanceof Error ? error.message : 'Export failed',
|
|
193
445
|
code: 'SERVER_EXPORT_ERROR',
|
|
@@ -197,12 +449,14 @@ async function exportServerData(table, options) {
|
|
|
197
449
|
/**
|
|
198
450
|
* Export data to file (CSV or Excel)
|
|
199
451
|
*/
|
|
200
|
-
async function exportToFile(data, format, filename) {
|
|
452
|
+
async function exportToFile(data, format, filename, signal, sanitizeCSV = true) {
|
|
453
|
+
throwIfExportCancelled(signal);
|
|
201
454
|
if (data.length === 0) {
|
|
202
455
|
throw new Error('No data to export');
|
|
203
456
|
}
|
|
204
457
|
if (format === 'csv') {
|
|
205
|
-
const csv = convertToCSV(data);
|
|
458
|
+
const csv = convertToCSV(data, sanitizeCSV);
|
|
459
|
+
throwIfExportCancelled(signal);
|
|
206
460
|
downloadFile(csv, `${filename}.csv`, 'text/csv');
|
|
207
461
|
}
|
|
208
462
|
else {
|
|
@@ -211,22 +465,28 @@ async function exportToFile(data, format, filename) {
|
|
|
211
465
|
XLSX.utils.book_append_sheet(workbook, worksheet, 'Data');
|
|
212
466
|
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
|
|
213
467
|
const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
|
468
|
+
throwIfExportCancelled(signal);
|
|
214
469
|
downloadFile(blob, `${filename}.xlsx`, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
|
215
470
|
}
|
|
216
471
|
}
|
|
217
472
|
/**
|
|
218
473
|
* Convert data to CSV format
|
|
219
474
|
*/
|
|
220
|
-
function convertToCSV(data) {
|
|
475
|
+
function convertToCSV(data, sanitizeCSV) {
|
|
221
476
|
if (data.length === 0)
|
|
222
477
|
return '';
|
|
223
478
|
const headers = Object.keys(data[0]);
|
|
224
479
|
const csvRows = [headers.join(',')];
|
|
225
480
|
for (const row of data) {
|
|
226
481
|
const values = headers.map(header => {
|
|
227
|
-
|
|
482
|
+
var _a;
|
|
483
|
+
const rawValue = (_a = row[header]) !== null && _a !== void 0 ? _a : '';
|
|
484
|
+
const normalizedValue = sanitizeCSV ? sanitizeCSVCellValue(rawValue) : rawValue;
|
|
485
|
+
const value = normalizedValue === null || normalizedValue === undefined
|
|
486
|
+
? ''
|
|
487
|
+
: String(normalizedValue);
|
|
228
488
|
// Escape quotes and wrap in quotes if contains comma or quote
|
|
229
|
-
if (
|
|
489
|
+
if (value.includes(',') || value.includes('"') || value.includes('\n')) {
|
|
230
490
|
return `"${value.replace(/"/g, '""')}"`;
|
|
231
491
|
}
|
|
232
492
|
return value;
|
|
@@ -235,6 +495,42 @@ function convertToCSV(data) {
|
|
|
235
495
|
}
|
|
236
496
|
return csvRows.join('\n');
|
|
237
497
|
}
|
|
498
|
+
function sanitizeCSVCellValue(value) {
|
|
499
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
500
|
+
return value;
|
|
501
|
+
}
|
|
502
|
+
const firstCharacter = value[0];
|
|
503
|
+
if (firstCharacter === '=' || firstCharacter === '+' || firstCharacter === '-' || firstCharacter === '@') {
|
|
504
|
+
return `'${value}`;
|
|
505
|
+
}
|
|
506
|
+
return value;
|
|
507
|
+
}
|
|
508
|
+
async function downloadFromUrl(url, filename, mimeType, signal) {
|
|
509
|
+
throwIfExportCancelled(signal);
|
|
510
|
+
try {
|
|
511
|
+
const response = await fetch(url, { signal });
|
|
512
|
+
if (!response.ok) {
|
|
513
|
+
throw new Error(`Failed to download export file from URL (${response.status})`);
|
|
514
|
+
}
|
|
515
|
+
const blob = await response.blob();
|
|
516
|
+
throwIfExportCancelled(signal);
|
|
517
|
+
downloadFile(blob, filename, mimeType || blob.type || 'application/octet-stream');
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
catch (error) {
|
|
521
|
+
if (isCancelledError(error)) {
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
524
|
+
// Fallback for URLs that block fetch due to CORS - browser handles URL directly.
|
|
525
|
+
const link = document.createElement('a');
|
|
526
|
+
link.href = url;
|
|
527
|
+
link.download = filename;
|
|
528
|
+
link.style.display = 'none';
|
|
529
|
+
document.body.appendChild(link);
|
|
530
|
+
link.click();
|
|
531
|
+
document.body.removeChild(link);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
238
534
|
/**
|
|
239
535
|
* Download file to user's device
|
|
240
536
|
*/
|
|
@@ -45,7 +45,7 @@ export declare function validateSlotProps<T, K extends keyof DataTableSlots<T>>(
|
|
|
45
45
|
/**
|
|
46
46
|
* Helper to create slot props with proper typing
|
|
47
47
|
*/
|
|
48
|
-
export declare function createSlotProps
|
|
48
|
+
export declare function createSlotProps(table: any, additionalProps?: Record<string, any>): Record<string, any>;
|
|
49
49
|
/**
|
|
50
50
|
* Enhanced slot component wrapper that handles all prop merging automatically
|
|
51
51
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slot-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/slot-helpers.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAiB,MAAM,OAAO,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,EACjE,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,EAC7C,QAAQ,EAAE,CAAC,EACX,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,GAC7B,aAAa,CAAC,GAAG,CAAC,CAEpB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC1B,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EACtC,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EACnC,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GACpC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA2CrB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,EAC1E,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,EAC7C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EACnC,QAAQ,EAAE,CAAC,EACX,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,EAC5B,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GACvC;IACC,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B,CASA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,EACjE,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,EAC7C,QAAQ,EAAE,CAAC,GACZ,OAAO,CAET;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAChC,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,GAC9C,KAAK,CAAC,MAAM,cAAc,CAAC,CAAC,CAAC,CAAC,CAGhC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,EACjE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EAC1C,QAAQ,EAAE,CAAC,GACZ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAErB;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,EAC5E,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,EAC7C,QAAQ,EAAE,CAAC,EACX,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,EAC5B,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GACpC,aAAa,CAAC,GAAG,CAAC,CAOpB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,EAClE,QAAQ,EAAE,CAAC,EACX,KAAK,EAAE,GAAG,EACV,aAAa,GAAE,MAAM,EAAO,GAC7B,OAAO,CAST;AAED;;GAEG;AACH,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"slot-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/slot-helpers.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ackplus/react-tanstack-data-table",
|
|
3
3
|
"type": "commonjs",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.13",
|
|
5
5
|
"description": "A powerful React data table component built with MUI and TanStack Table",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"react",
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
"src"
|
|
43
43
|
],
|
|
44
44
|
"scripts": {
|
|
45
|
-
"build": "tsc -p tsconfig.build.json"
|
|
45
|
+
"build": "tsc -p tsconfig.build.json",
|
|
46
|
+
"lint": "tsc -p tsconfig.build.json --noEmit",
|
|
47
|
+
"test": "pnpm run build && node --test tests/column-filter.feature.test.cjs"
|
|
46
48
|
},
|
|
47
49
|
"dependencies": {
|
|
48
50
|
"lodash": "^4.17.21",
|
|
@@ -36,10 +36,10 @@ export function MenuDropdown({
|
|
|
36
36
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
|
37
37
|
const isOpen = useMemo(() => Boolean(anchorEl), [anchorEl]);
|
|
38
38
|
const handleClick = useCallback(
|
|
39
|
-
(event: React.MouseEvent<
|
|
39
|
+
(event: React.MouseEvent<HTMLElement>) => {
|
|
40
40
|
event.preventDefault();
|
|
41
41
|
event.stopPropagation();
|
|
42
|
-
setAnchorEl(event.currentTarget);
|
|
42
|
+
setAnchorEl(event.currentTarget as HTMLElement);
|
|
43
43
|
},
|
|
44
44
|
[],
|
|
45
45
|
);
|
|
@@ -54,8 +54,14 @@ export function MenuDropdown({
|
|
|
54
54
|
if (typeof anchor === 'function') {
|
|
55
55
|
node = anchor({ isOpen: isOpen });
|
|
56
56
|
}
|
|
57
|
+
const existingOnClick = (node as ReactElement<any>).props?.onClick;
|
|
57
58
|
return cloneElement(node as ReactElement<any>, {
|
|
58
|
-
onClick:
|
|
59
|
+
onClick: (event: React.MouseEvent<HTMLElement>) => {
|
|
60
|
+
existingOnClick?.(event);
|
|
61
|
+
if (!event.defaultPrevented) {
|
|
62
|
+
handleClick(event);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
59
65
|
});
|
|
60
66
|
}
|
|
61
67
|
return <Button onClick={handleClick}>{label as any}</Button>;
|
|
@@ -100,8 +100,8 @@ export function FilterValueInput<T>(props: FilterValueInputProps<T>): ReactEleme
|
|
|
100
100
|
|
|
101
101
|
// Select type with options
|
|
102
102
|
if (options && options.length > 0) {
|
|
103
|
-
// Multi-select for
|
|
104
|
-
if (operator === 'in') {
|
|
103
|
+
// Multi-select for set operators
|
|
104
|
+
if (operator === 'in' || operator === 'notIn') {
|
|
105
105
|
const currentValue = Array.isArray(filter.value) ? filter.value : [];
|
|
106
106
|
|
|
107
107
|
return (
|