@ackplus/react-tanstack-data-table
Version:
A powerful React data table component built with MUI and TanStack Table
253 lines (252 loc) • 10.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.exportClientData = exportClientData;
exports.exportServerData = exportServerData;
const XLSX = __importStar(require("xlsx"));
/**
* Export data for client-side tables
* - If rows are selected, export only selected rows
* - Otherwise export all filtered/visible rows
* - Only export visible columns
*/
async function exportClientData(table, options) {
const { format, filename, onProgress, onComplete, onError } = options;
try {
// Get selected rows if any are selected
// const selectedRowIds = Object.keys(table.getState().rowSelection).filter(
// key => table.getState().rowSelection[key]
// );
// const hasSelectedRows = selectedRowIds.length > 0;
// // Get the rows to export
// const rowsToExport = hasSelectedRows ? table.getSelectedRowModel().rows : table.getFilteredRowModel().rows;
const selectedRows = table.getSelectedRows ? table.getSelectedRows() : [];
const hasSelectedRows = selectedRows.length > 0;
const rowsToExport = hasSelectedRows ? selectedRows : table.getFilteredRowModel().rows;
// Prepare data for export - get all visible columns and their values, excluding hideInExport columns
const exportData = rowsToExport.map((row, index) => {
onProgress === null || onProgress === void 0 ? void 0 : onProgress({
processedRows: index + 1,
totalRows: rowsToExport.length,
percentage: Math.round(((index + 1) / rowsToExport.length) * 100),
});
const rowData = {};
// Get all visible cells for this row, excluding columns marked as hideInExport
row.getVisibleCells().forEach(cell => {
const columnDef = cell.column.columnDef;
// Skip columns marked as hideInExport
if (columnDef.hideInExport === true) {
return;
}
const header = typeof columnDef.header === 'string' ? columnDef.header : cell.column.id;
// Use getValue() - it already handles all formatting
rowData[header] = cell.getValue() || '';
});
return rowData;
});
// Export the data
await exportToFile(exportData, format, filename);
onComplete === null || onComplete === void 0 ? void 0 : onComplete({
success: true,
filename: `${filename}.${format === 'excel' ? 'xlsx' : 'csv'}`,
totalRows: exportData.length,
});
}
catch (error) {
console.error('Client export failed:', error);
onError === null || onError === void 0 ? void 0 : onError({
message: error instanceof Error ? error.message : 'Export failed',
code: 'CLIENT_EXPORT_ERROR',
});
}
}
/**
* Export data for server-side tables
* - Fetch data using provided fetchData function
* - Pass selection information to server for filtering
* - Export all returned data (server handles selection/filtering)
*/
async function exportServerData(table, options) {
const { format, filename, fetchData, currentFilters, selection, onProgress, onComplete, onError } = options;
try {
// Initial progress
onProgress === null || onProgress === void 0 ? void 0 : onProgress({});
// First, get total count to determine if we need chunking
const initialResponse = await fetchData({
...currentFilters,
pagination: { pageIndex: 0, pageSize: 1 }
}, selection);
if (!initialResponse || !initialResponse.data || !Array.isArray(initialResponse.data)) {
throw new Error('Invalid data received from server');
}
const totalRows = initialResponse.total || initialResponse.data.length;
const CHUNK_SIZE = 1000; // Fetch 1000 rows per request
const needsChunking = totalRows > CHUNK_SIZE;
let allData = [];
if (needsChunking) {
// Fetch data in chunks (no progress events during fetching)
const totalPages = Math.ceil(totalRows / CHUNK_SIZE);
for (let page = 1; page <= totalPages; page++) {
// Fetch current chunk
const chunkFilters = {
...currentFilters,
pagination: {
pageIndex: page - 1,
pageSize: CHUNK_SIZE,
},
};
const chunkResponse = await fetchData(chunkFilters, selection);
if (!chunkResponse || !chunkResponse.data || !Array.isArray(chunkResponse.data)) {
throw new Error(`Failed to fetch chunk ${page}`);
}
allData = [...allData, ...chunkResponse.data];
// Small delay to prevent overwhelming the server
if (page < totalPages) {
await new Promise(resolve => setTimeout(resolve, 100));
}
}
}
else {
// Small dataset, use single request
allData = initialResponse.data;
}
// Get visible columns for proper headers and data processing, excluding hideInExport columns
const visibleColumns = table.getVisibleLeafColumns().filter(col => {
const columnDef = col.columnDef;
return col.getIsVisible() && columnDef.hideInExport !== true;
});
// Prepare data for export with proper column processing
const exportData = [];
for (let index = 0; index < allData.length; index++) {
const rowData = allData[index];
const exportRow = {};
visibleColumns.forEach(column => {
var _a;
const columnId = column.id;
const columnDef = column.columnDef;
const header = typeof columnDef.header === 'string'
? columnDef.header
: columnId;
// Get value from raw data
let value = rowData[columnId];
// Apply accessorFn if defined
if (column.accessorFn && typeof column.accessorFn === 'function') {
value = ((_a = (column.accessorFn(rowData, index) || '')) === null || _a === void 0 ? void 0 : _a.toString()) || '';
}
// Convert to string for export
if (value === null || value === undefined) {
value = '';
}
else if (typeof value === 'object') {
value = JSON.stringify(value);
}
else {
value = String(value);
}
exportRow[header] = value;
});
exportData.push(exportRow);
}
await exportToFile(exportData, format, filename);
onComplete === null || onComplete === void 0 ? void 0 : onComplete({
success: true,
filename: `${filename}.${format === 'excel' ? 'xlsx' : 'csv'}`,
totalRows: exportData.length,
});
}
catch (error) {
console.error('Server export failed:', error);
onError === null || onError === void 0 ? void 0 : onError({
message: error instanceof Error ? error.message : 'Export failed',
code: 'SERVER_EXPORT_ERROR',
});
}
}
/**
* Export data to file (CSV or Excel)
*/
async function exportToFile(data, format, filename) {
if (data.length === 0) {
throw new Error('No data to export');
}
if (format === 'csv') {
const csv = convertToCSV(data);
downloadFile(csv, `${filename}.csv`, 'text/csv');
}
else {
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.json_to_sheet(data);
XLSX.utils.book_append_sheet(workbook, worksheet, 'Data');
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
downloadFile(blob, `${filename}.xlsx`, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
}
}
/**
* Convert data to CSV format
*/
function convertToCSV(data) {
if (data.length === 0)
return '';
const headers = Object.keys(data[0]);
const csvRows = [headers.join(',')];
for (const row of data) {
const values = headers.map(header => {
const value = row[header] || '';
// Escape quotes and wrap in quotes if contains comma or quote
if (typeof value === 'string' && (value.includes(',') || value.includes('"') || value.includes('\n'))) {
return `"${value.replace(/"/g, '""')}"`;
}
return value;
});
csvRows.push(values.join(','));
}
return csvRows.join('\n');
}
/**
* Download file to user's device
*/
function downloadFile(content, filename, mimeType) {
const blob = content instanceof Blob ? content : new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}