1 | "use strict";
|
2 |
|
3 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
4 | Object.defineProperty(exports, "__esModule", {
|
5 | value: true
|
6 | });
|
7 | exports.buildExcel = buildExcel;
|
8 | exports.getDataForValueOptionsSheet = getDataForValueOptionsSheet;
|
9 | exports.serializeColumn = void 0;
|
10 | exports.serializeColumns = serializeColumns;
|
11 | exports.serializeRowUnsafe = void 0;
|
12 | exports.setupExcelExportWebWorker = setupExcelExportWebWorker;
|
13 | var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
14 | var _interopRequireWildcard2 = _interopRequireDefault(require("@babel/runtime/helpers/interopRequireWildcard"));
|
15 | var _xDataGridPro = require("@mui/x-data-grid-pro");
|
16 | var _internals = require("@mui/x-data-grid/internals");
|
17 | var _warning = require("@mui/x-internals/warning");
|
18 | const getExcelJs = async () => {
|
19 | const excelJsModule = await Promise.resolve().then(() => (0, _interopRequireWildcard2.default)(require('exceljs')));
|
20 | return excelJsModule.default ?? excelJsModule;
|
21 | };
|
22 | const getFormattedValueOptions = (colDef, row, valueOptions, api) => {
|
23 | if (!colDef.valueOptions) {
|
24 | return [];
|
25 | }
|
26 | let valueOptionsFormatted = valueOptions;
|
27 | if (colDef.valueFormatter) {
|
28 | valueOptionsFormatted = valueOptionsFormatted.map(option => {
|
29 | if (typeof option === 'object') {
|
30 | return option;
|
31 | }
|
32 | return String(colDef.valueFormatter(option, row, colDef, {
|
33 | current: api
|
34 | }));
|
35 | });
|
36 | }
|
37 | return valueOptionsFormatted.map(option => typeof option === 'object' ? option.label : option);
|
38 | };
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | const serializeRowUnsafe = (id, columns, apiRef, defaultValueOptionsFormulae, options) => {
|
46 | const row = {};
|
47 | const dataValidation = {};
|
48 | const mergedCells = [];
|
49 | const firstCellParams = apiRef.current.getCellParams(id, columns[0].field);
|
50 | const outlineLevel = firstCellParams.rowNode.depth;
|
51 | const hasColSpan = (0, _internals.gridHasColSpanSelector)(apiRef);
|
52 | if (hasColSpan) {
|
53 |
|
54 | apiRef.current.calculateColSpan({
|
55 | rowId: id,
|
56 | minFirstColumn: 0,
|
57 | maxLastColumn: columns.length,
|
58 | columns
|
59 | });
|
60 | }
|
61 | columns.forEach((column, colIndex) => {
|
62 | const colSpanInfo = hasColSpan ? apiRef.current.unstable_getCellColSpanInfo(id, colIndex) : undefined;
|
63 | if (colSpanInfo && colSpanInfo.spannedByColSpan) {
|
64 | return;
|
65 | }
|
66 | if (colSpanInfo && colSpanInfo.cellProps.colSpan > 1) {
|
67 | mergedCells.push({
|
68 | leftIndex: colIndex + 1,
|
69 | rightIndex: colIndex + colSpanInfo.cellProps.colSpan
|
70 | });
|
71 | }
|
72 | const cellParams = apiRef.current.getCellParams(id, column.field);
|
73 | let cellValue;
|
74 | switch (cellParams.colDef.type) {
|
75 | case 'singleSelect':
|
76 | {
|
77 | const castColumn = cellParams.colDef;
|
78 | if (typeof castColumn.valueOptions === 'function') {
|
79 |
|
80 |
|
81 | const valueOptions = castColumn.valueOptions({
|
82 | id,
|
83 | row,
|
84 | field: cellParams.field
|
85 | });
|
86 | const formattedValueOptions = getFormattedValueOptions(castColumn, row, valueOptions, apiRef.current);
|
87 | dataValidation[castColumn.field] = {
|
88 | type: 'list',
|
89 | allowBlank: true,
|
90 | formulae: [`"${formattedValueOptions.map(x => x.toString().replaceAll(',', 'CHAR(44)')).join(',')}"`]
|
91 | };
|
92 | } else {
|
93 | const address = defaultValueOptionsFormulae[column.field].address;
|
94 |
|
95 |
|
96 | dataValidation[castColumn.field] = {
|
97 | type: 'list',
|
98 | allowBlank: true,
|
99 | formulae: [address]
|
100 | };
|
101 | }
|
102 | const formattedValue = apiRef.current.getCellParams(id, castColumn.field).formattedValue;
|
103 | if (process.env.NODE_ENV !== 'production') {
|
104 | if (String(cellParams.formattedValue) === '[object Object]') {
|
105 | (0, _warning.warnOnce)(['MUI X: When the value of a field is an object or a `renderCell` is provided, the Excel export might not display the value correctly.', 'You can provide a `valueFormatter` with a string representation to be used.']);
|
106 | }
|
107 | }
|
108 | if ((0, _internals.isObject)(formattedValue)) {
|
109 | row[castColumn.field] = formattedValue?.label;
|
110 | } else {
|
111 | row[castColumn.field] = formattedValue;
|
112 | }
|
113 | break;
|
114 | }
|
115 | case 'boolean':
|
116 | case 'number':
|
117 | cellValue = apiRef.current.getCellParams(id, column.field).value;
|
118 | break;
|
119 | case 'date':
|
120 | case 'dateTime':
|
121 | {
|
122 |
|
123 |
|
124 |
|
125 | const value = apiRef.current.getCellParams(id, column.field).value;
|
126 |
|
127 | if (!value) {
|
128 | break;
|
129 | }
|
130 | const utcDate = new Date(Date.UTC(value.getFullYear(), value.getMonth(), value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds()));
|
131 | row[column.field] = utcDate;
|
132 | break;
|
133 | }
|
134 | case 'actions':
|
135 | break;
|
136 | default:
|
137 | cellValue = apiRef.current.getCellParams(id, column.field).formattedValue;
|
138 | if (process.env.NODE_ENV !== 'production') {
|
139 | if (String(cellParams.formattedValue) === '[object Object]') {
|
140 | (0, _warning.warnOnce)(['MUI X: When the value of a field is an object or a `renderCell` is provided, the Excel export might not display the value correctly.', 'You can provide a `valueFormatter` with a string representation to be used.']);
|
141 | }
|
142 | }
|
143 | break;
|
144 | }
|
145 | if (typeof cellValue === 'string' && options.escapeFormulas) {
|
146 |
|
147 | if (['=', '+', '-', '@', '\t', '\r'].includes(cellValue[0])) {
|
148 | cellValue = `'${cellValue}`;
|
149 | }
|
150 | }
|
151 | if (typeof cellValue !== 'undefined') {
|
152 | row[column.field] = cellValue;
|
153 | }
|
154 | });
|
155 | return {
|
156 | row,
|
157 | dataValidation,
|
158 | outlineLevel,
|
159 | mergedCells
|
160 | };
|
161 | };
|
162 | exports.serializeRowUnsafe = serializeRowUnsafe;
|
163 | const defaultColumnsStyles = {
|
164 | [_xDataGridPro.GRID_DATE_COL_DEF.type]: {
|
165 | numFmt: 'dd.mm.yyyy'
|
166 | },
|
167 | [_xDataGridPro.GRID_DATETIME_COL_DEF.type]: {
|
168 | numFmt: 'dd.mm.yyyy hh:mm'
|
169 | }
|
170 | };
|
171 | const serializeColumn = (column, columnsStyles) => {
|
172 | const {
|
173 | field,
|
174 | type
|
175 | } = column;
|
176 | return {
|
177 | key: field,
|
178 | headerText: column.headerName ?? column.field,
|
179 |
|
180 |
|
181 |
|
182 | width: Math.min(255, column.width ? column.width / 7.5 : 8.43),
|
183 | style: (0, _extends2.default)({}, type && defaultColumnsStyles?.[type], columnsStyles?.[field])
|
184 | };
|
185 | };
|
186 | exports.serializeColumn = serializeColumn;
|
187 | const addColumnGroupingHeaders = (worksheet, columns, columnGroupPaths, columnGroupDetails) => {
|
188 | const maxDepth = Math.max(...columns.map(({
|
189 | key
|
190 | }) => columnGroupPaths[key]?.length ?? 0));
|
191 | if (maxDepth === 0) {
|
192 | return;
|
193 | }
|
194 | for (let rowIndex = 0; rowIndex < maxDepth; rowIndex += 1) {
|
195 | const row = columns.map(({
|
196 | key
|
197 | }) => {
|
198 | const groupingPath = columnGroupPaths[key];
|
199 | if (groupingPath.length <= rowIndex) {
|
200 | return {
|
201 | groupId: null,
|
202 | parents: groupingPath
|
203 | };
|
204 | }
|
205 | return (0, _extends2.default)({}, columnGroupDetails[groupingPath[rowIndex]], {
|
206 | parents: groupingPath.slice(0, rowIndex)
|
207 | });
|
208 | });
|
209 | const newRow = worksheet.addRow(row.map(group => group.groupId === null ? null : group?.headerName ?? group.groupId));
|
210 |
|
211 |
|
212 | const lastRowIndex = newRow.worksheet.rowCount;
|
213 | let leftIndex = 0;
|
214 | let rightIndex = 1;
|
215 | while (rightIndex < columns.length) {
|
216 | const {
|
217 | groupId: leftGroupId,
|
218 | parents: leftParents
|
219 | } = row[leftIndex];
|
220 | const {
|
221 | groupId: rightGroupId,
|
222 | parents: rightParents
|
223 | } = row[rightIndex];
|
224 | const areInSameGroup = leftGroupId === rightGroupId && leftParents.length === rightParents.length && leftParents.every((leftParent, index) => rightParents[index] === leftParent);
|
225 | if (areInSameGroup) {
|
226 | rightIndex += 1;
|
227 | } else {
|
228 | if (rightIndex - leftIndex > 1) {
|
229 | worksheet.mergeCells(lastRowIndex, leftIndex + 1, lastRowIndex, rightIndex);
|
230 | }
|
231 | leftIndex = rightIndex;
|
232 | rightIndex += 1;
|
233 | }
|
234 | }
|
235 | if (rightIndex - leftIndex > 1) {
|
236 | worksheet.mergeCells(lastRowIndex, leftIndex + 1, lastRowIndex, rightIndex);
|
237 | }
|
238 | }
|
239 | };
|
240 | function serializeColumns(columns, styles) {
|
241 | return columns.map(column => serializeColumn(column, styles));
|
242 | }
|
243 | async function getDataForValueOptionsSheet(columns, valueOptionsSheetName, api) {
|
244 | const candidateColumns = columns.filter(column => (0, _internals.isSingleSelectColDef)(column) && Array.isArray(column.valueOptions));
|
245 |
|
246 |
|
247 | const excelJS = await getExcelJs();
|
248 | const workbook = new excelJS.Workbook();
|
249 | const worksheet = workbook.addWorksheet('Sheet1');
|
250 | worksheet.columns = candidateColumns.map(column => ({
|
251 | key: column.field
|
252 | }));
|
253 | return candidateColumns.reduce((acc, column) => {
|
254 | const singleSelectColumn = column;
|
255 | const formattedValueOptions = getFormattedValueOptions(singleSelectColumn, {}, singleSelectColumn.valueOptions, api);
|
256 | const header = column.headerName ?? column.field;
|
257 | const values = [header, ...formattedValueOptions];
|
258 | const letter = worksheet.getColumn(column.field).letter;
|
259 | const address = `${valueOptionsSheetName}!$${letter}$2:$${letter}$${values.length}`;
|
260 | acc[column.field] = {
|
261 | values,
|
262 | address
|
263 | };
|
264 | return acc;
|
265 | }, {});
|
266 | }
|
267 | function addSerializedRowToWorksheet(serializedRow, worksheet) {
|
268 | const {
|
269 | row,
|
270 | dataValidation,
|
271 | outlineLevel,
|
272 | mergedCells
|
273 | } = serializedRow;
|
274 | const newRow = worksheet.addRow(row);
|
275 | Object.keys(dataValidation).forEach(field => {
|
276 | newRow.getCell(field).dataValidation = (0, _extends2.default)({}, dataValidation[field]);
|
277 | });
|
278 | if (outlineLevel) {
|
279 | newRow.outlineLevel = outlineLevel;
|
280 | }
|
281 |
|
282 |
|
283 | const lastRowIndex = newRow.worksheet.rowCount;
|
284 | mergedCells.forEach(mergedCell => {
|
285 | worksheet.mergeCells(lastRowIndex, mergedCell.leftIndex, lastRowIndex, mergedCell.rightIndex);
|
286 | });
|
287 | }
|
288 | async function createValueOptionsSheetIfNeeded(valueOptionsData, sheetName, workbook) {
|
289 | if (Object.keys(valueOptionsData).length === 0) {
|
290 | return;
|
291 | }
|
292 | const valueOptionsWorksheet = workbook.addWorksheet(sheetName);
|
293 | valueOptionsWorksheet.columns = Object.keys(valueOptionsData).map(key => ({
|
294 | key
|
295 | }));
|
296 | Object.entries(valueOptionsData).forEach(([field, {
|
297 | values
|
298 | }]) => {
|
299 | valueOptionsWorksheet.getColumn(field).values = values;
|
300 | });
|
301 | }
|
302 | async function buildExcel(options, apiRef) {
|
303 | const {
|
304 | columns,
|
305 | rowIds,
|
306 | includeHeaders,
|
307 | includeColumnGroupsHeaders,
|
308 | valueOptionsSheetName = 'Options',
|
309 | exceljsPreProcess,
|
310 | exceljsPostProcess,
|
311 | columnsStyles = {}
|
312 | } = options;
|
313 | const excelJS = await getExcelJs();
|
314 | const workbook = new excelJS.Workbook();
|
315 | const worksheet = workbook.addWorksheet('Sheet1');
|
316 | const serializedColumns = serializeColumns(columns, columnsStyles);
|
317 | worksheet.columns = serializedColumns;
|
318 | if (exceljsPreProcess) {
|
319 | await exceljsPreProcess({
|
320 | workbook,
|
321 | worksheet
|
322 | });
|
323 | }
|
324 | if (includeColumnGroupsHeaders) {
|
325 | const columnGroupPaths = columns.reduce((acc, column) => {
|
326 | acc[column.field] = apiRef.current.getColumnGroupPath(column.field);
|
327 | return acc;
|
328 | }, {});
|
329 | addColumnGroupingHeaders(worksheet, serializedColumns, columnGroupPaths, apiRef.current.getAllGroupDetails());
|
330 | }
|
331 | if (includeHeaders) {
|
332 | worksheet.addRow(columns.map(column => column.headerName ?? column.field));
|
333 | }
|
334 | const valueOptionsData = await getDataForValueOptionsSheet(columns, valueOptionsSheetName, apiRef.current);
|
335 | createValueOptionsSheetIfNeeded(valueOptionsData, valueOptionsSheetName, workbook);
|
336 | apiRef.current.resetColSpan();
|
337 | rowIds.forEach(id => {
|
338 | const serializedRow = serializeRowUnsafe(id, columns, apiRef, valueOptionsData, options);
|
339 | addSerializedRowToWorksheet(serializedRow, worksheet);
|
340 | });
|
341 | apiRef.current.resetColSpan();
|
342 | if (exceljsPostProcess) {
|
343 | await exceljsPostProcess({
|
344 | workbook,
|
345 | worksheet
|
346 | });
|
347 | }
|
348 | return workbook;
|
349 | }
|
350 | function setupExcelExportWebWorker(workerOptions = {}) {
|
351 |
|
352 | addEventListener('message', async event => {
|
353 | const {
|
354 | serializedColumns,
|
355 | serializedRows,
|
356 | options,
|
357 | valueOptionsSheetName,
|
358 | valueOptionsData,
|
359 | columnGroupDetails,
|
360 | columnGroupPaths
|
361 | } = event.data;
|
362 | const {
|
363 | exceljsPostProcess,
|
364 | exceljsPreProcess
|
365 | } = workerOptions;
|
366 | const excelJS = await getExcelJs();
|
367 | const workbook = new excelJS.Workbook();
|
368 | const worksheet = workbook.addWorksheet('Sheet1');
|
369 | worksheet.columns = serializedColumns;
|
370 | if (exceljsPreProcess) {
|
371 | await exceljsPreProcess({
|
372 | workbook,
|
373 | worksheet
|
374 | });
|
375 | }
|
376 | if (options.includeColumnGroupsHeaders) {
|
377 | addColumnGroupingHeaders(worksheet, serializedColumns, columnGroupPaths, columnGroupDetails);
|
378 | }
|
379 | const includeHeaders = options.includeHeaders ?? true;
|
380 | if (includeHeaders) {
|
381 | worksheet.addRow(serializedColumns.map(column => column.headerText));
|
382 | }
|
383 | createValueOptionsSheetIfNeeded(valueOptionsData, valueOptionsSheetName, workbook);
|
384 | serializedRows.forEach(serializedRow => {
|
385 | addSerializedRowToWorksheet(serializedRow, worksheet);
|
386 | });
|
387 | if (exceljsPostProcess) {
|
388 | await exceljsPostProcess({
|
389 | workbook,
|
390 | worksheet
|
391 | });
|
392 | }
|
393 | postMessage(await workbook.xlsx.writeBuffer());
|
394 | });
|
395 | } |
\ | No newline at end of file |