@cdmx/wappler_ag_grid 2.1.0 → 2.1.1

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.
@@ -243,6 +243,14 @@
243
243
  "defaultValue": false,
244
244
  "help": "Specifies if Export to PDF to be enabled"
245
245
  },
246
+ {
247
+ "name": "exportToXLS",
248
+ "attribute": "dmx-bind:export_to_xls",
249
+ "title": "XLS Export",
250
+ "type": "boolean",
251
+ "defaultValue": false,
252
+ "help": "Specifies if Export to XLS (Excel) to be enabled"
253
+ },
246
254
  {
247
255
  "name": "exportExcludeHidden",
248
256
  "attribute": "dmx-bind:export_exclude_hidden_fields",
@@ -3700,6 +3708,11 @@
3700
3708
  name: '2', optionName: '2', title: 'PDF', type: 'boolean',
3701
3709
  dataBindings: true, defaultValue: false, required: false,
3702
3710
  help: 'Export Grid data as PDF file.'
3711
+ },
3712
+ {
3713
+ name: '3', optionName: '3', title: 'XLS', type: 'boolean',
3714
+ dataBindings: true, defaultValue: false, required: false,
3715
+ help: 'Export Grid data as Excel (.xlsx) file.'
3703
3716
  }
3704
3717
  ]
3705
3718
  }
@@ -3911,6 +3924,10 @@
3911
3924
  {
3912
3925
  "src": "../../../node_modules/pdfmake/build/vfs_fonts.js",
3913
3926
  "dst": "js/vfs_fonts.js"
3927
+ },
3928
+ {
3929
+ "src": "../../../node_modules/exceljs/dist/exceljs.min.js",
3930
+ "dst": "js/exceljs.min.js"
3914
3931
  }
3915
3932
  ],
3916
3933
  "linkFiles": [
@@ -3954,6 +3971,11 @@
3954
3971
  "type": "js",
3955
3972
  "defer": true
3956
3973
  },
3974
+ {
3975
+ "src": "js/exceljs.min.js",
3976
+ "type": "js",
3977
+ "defer": true
3978
+ },
3957
3979
  {
3958
3980
  "src": "css/ag-theme-alpine.css",
3959
3981
  "type": "css"
@@ -4318,6 +4340,40 @@
4318
4340
  "dmx-ag-grid": true
4319
4341
  }
4320
4342
  },
4343
+ {
4344
+ "name": "dmx-ag-grid-export-xls-filename",
4345
+ "attributeStartsWith": "dmx-bind",
4346
+ "attribute": "export_xls_filename",
4347
+ "title": "Export XLS Filename",
4348
+ "type": "boolean",
4349
+ "display": "fieldset",
4350
+ "icon": "fa fa-lg fa-chevron-right",
4351
+ "groupTitle": "Grid Config",
4352
+ "groupIcon": "fa fa-lg fa-cubes",
4353
+ "defaultValue": false,
4354
+ "show": [
4355
+ "exportXlsFilename"
4356
+ ],
4357
+ "noChangeOnHide": true,
4358
+ "groupEnabler": true,
4359
+ "children": [
4360
+ {
4361
+ "name": "exportXlsFilename",
4362
+ "attributeStartsWith": "dmx-bind",
4363
+ "attribute": "export_xls_filename",
4364
+ "isValue": true,
4365
+ "dataBindings": true,
4366
+ "title": "XLS Filename",
4367
+ "type": "text",
4368
+ "help": "Export XLS filename.",
4369
+ "defaultValue": "export.xlsx",
4370
+ "initDisplay": "none"
4371
+ }
4372
+ ],
4373
+ "allowedOn": {
4374
+ "dmx-ag-grid": true
4375
+ }
4376
+ },
4321
4377
  {
4322
4378
  "name": "dmx-ag-grid-dark-mode",
4323
4379
  "attributeStartsWith": "dmx-bind",
package/dmx-ag-grid.js CHANGED
@@ -94,6 +94,8 @@ dmx.Component('ag-grid', {
94
94
  export_csv_filename: { type: String, default: 'export.csv' },
95
95
  export_to_pdf: { type: Boolean, default: false },
96
96
  export_pdf_filename: { type: String, default: 'export.pdf' },
97
+ export_to_xls: { type: Boolean, default: false },
98
+ export_xls_filename: { type: String, default: 'export.xlsx' },
97
99
  fixed_header: { type: Boolean, default: false },
98
100
  topbar_class: { type: String, default: 'topbar' },
99
101
  fixed_header_offset: { type: Number, default: 100 },
@@ -353,9 +355,9 @@ dmx.Component('ag-grid', {
353
355
  if (gridInstance) gridInstance.destroy();
354
356
  }, this);
355
357
  },
356
- exportGrid: function (Csv, Pdf) {
357
- // Default Csv to true if both Csv and Pdf are false
358
- if (!Csv && !Pdf) {
358
+ exportGrid: function (Csv, Pdf, Xls) {
359
+ // Default Csv to true if none specified
360
+ if (!Csv && !Pdf && !Xls) {
359
361
  Csv = true;
360
362
  }
361
363
  dmx.nextTick(() => {
@@ -365,6 +367,8 @@ dmx.Component('ag-grid', {
365
367
  exportGridData(gridInst, gridCfg);
366
368
  } else if (Pdf) {
367
369
  exportGridDataToPDF(gridInst, gridCfg);
370
+ } else if (Xls) {
371
+ exportGridDataToXLS(gridInst, gridCfg);
368
372
  } else {
369
373
  console.error('Grid not loaded to perform the requested export');
370
374
  }
@@ -607,6 +611,7 @@ dmx.Component('ag-grid', {
607
611
  let groupedColumnDefs = [];
608
612
  let exportToCSV = this.props.export_to_csv;
609
613
  let exportToPDF = this.props.export_to_pdf;
614
+ let exportToXLS = this.props.export_to_xls;
610
615
  let cellRenderer;
611
616
 
612
617
  const gridThemeClass = options.dark_mode ? `${options.grid_theme}-dark` : options.grid_theme;
@@ -2049,6 +2054,7 @@ dmx.Component('ag-grid', {
2049
2054
  exportConfig: {
2050
2055
  export_csv_filename: options.export_csv_filename,
2051
2056
  export_pdf_filename: options.export_pdf_filename,
2057
+ export_xls_filename: options.export_xls_filename,
2052
2058
  export_remove_html: options.export_remove_html,
2053
2059
  export_trim_data: options.export_trim_data,
2054
2060
  export_exclude_fields: options.export_exclude_fields,
@@ -2660,6 +2666,221 @@ dmx.Component('ag-grid', {
2660
2666
  exportPdfButton.style.marginBottom = '10px';
2661
2667
  }
2662
2668
  }
2669
+ // XLS Export Function using ExcelJS
2670
+ exportGridDataToXLS = async (currentGridInstance, currentGridConfig) => {
2671
+ if (!currentGridInstance || currentGridInstance.isDestroyed()) {
2672
+ console.error('Grid API is destroyed or not initialized.');
2673
+ return;
2674
+ }
2675
+ if (typeof ExcelJS === 'undefined') {
2676
+ console.error('ExcelJS library is not loaded. Make sure exceljs.min.js is included.');
2677
+ return;
2678
+ }
2679
+ const exportConfig = currentGridConfig.context.exportConfig;
2680
+ const excludedColumnIds = ['checkboxColumn', 'actionsColumn'];
2681
+ const exportExcludeFieldsArray = exportConfig.export_exclude_fields ? exportConfig.export_exclude_fields.split(',') : [];
2682
+
2683
+ // Determine fields to export (reuse same logic as CSV)
2684
+ let fieldsToExport = [];
2685
+ const pageId = getPageId();
2686
+ const storageKey = exportConfig.column_state_storage_key || pageId;
2687
+ const savedColumnState = localStorage.getItem(`dmxState-${storageKey}`);
2688
+
2689
+ if (savedColumnState) {
2690
+ try {
2691
+ const parsedState = JSON.parse(savedColumnState);
2692
+ fieldsToExport = parsedState
2693
+ .filter((col) => {
2694
+ if (excludedColumnIds.includes(col.colId)) return false;
2695
+ if (col.hide) return false;
2696
+ return true;
2697
+ })
2698
+ .map((col) => {
2699
+ const columnDef = findColumnDefByColId(col.colId, exportConfig, currentGridConfig);
2700
+ return columnDef ? columnDef.field : col.colId;
2701
+ })
2702
+ .filter((field) => !exportExcludeFieldsArray.includes(field));
2703
+ } catch (err) {
2704
+ console.warn(`Failed to parse saved column state for key: dmxState-${storageKey}`, err);
2705
+ fieldsToExport = [];
2706
+ }
2707
+ }
2708
+
2709
+ function findColumnDefByColId(colId, expConfig, gridCfg) {
2710
+ if (expConfig.group_config) {
2711
+ const traverseColumns = (columns) => {
2712
+ for (const column of columns) {
2713
+ if (column.children) {
2714
+ const result = traverseColumns(column.children);
2715
+ if (result) return result;
2716
+ } else if (column.colId === colId) {
2717
+ return column;
2718
+ }
2719
+ }
2720
+ return null;
2721
+ };
2722
+ return traverseColumns(gridCfg.columnDefs);
2723
+ } else {
2724
+ return gridCfg.columnDefs.find((column) => column.colId === colId);
2725
+ }
2726
+ }
2727
+
2728
+ if (!fieldsToExport || fieldsToExport.length === 0) {
2729
+ let fieldsAndColIds;
2730
+ if (exportConfig.group_config) {
2731
+ const traverseColumns = (columns) => {
2732
+ const result = [];
2733
+ columns.forEach((column) => {
2734
+ if (column.children) {
2735
+ result.push(...traverseColumns(column.children));
2736
+ } else {
2737
+ result.push({ field: column.field, colId: column.colId, hide: column.hide });
2738
+ }
2739
+ });
2740
+ return result;
2741
+ };
2742
+ fieldsAndColIds = traverseColumns(currentGridConfig.columnDefs);
2743
+ } else {
2744
+ fieldsAndColIds = currentGridConfig.columnDefs.map((column) => ({
2745
+ field: column.field, colId: column.colId, hide: column.hide,
2746
+ }));
2747
+ }
2748
+ fieldsToExport = fieldsAndColIds.filter((column) => {
2749
+ return !excludedColumnIds.includes(column.colId) &&
2750
+ (!exportConfig.export_exclude_hidden_fields || !column.hide) &&
2751
+ !exportExcludeFieldsArray.includes(column.field);
2752
+ }).map((column) => column.field);
2753
+ }
2754
+
2755
+ // Build headers
2756
+ const headers = fieldsToExport.map(field => {
2757
+ return cnames.hasOwnProperty(field) ? cnames[field].custom_name : humanize(field);
2758
+ });
2759
+
2760
+ // Build rows
2761
+ const rows = [];
2762
+ currentGridInstance.forEachNode(node => {
2763
+ const row = fieldsToExport.map(field => {
2764
+ const columns = currentGridInstance.getColumnState();
2765
+ const col = columns.find(c => c.colId === field);
2766
+ const colDef = col ? currentGridInstance.getColumnDefs().find(def => def.colId === col.colId) : {};
2767
+ const params = {
2768
+ value: currentGridInstance.getCellValue({ rowNode: node, colKey: field }) ?? '-',
2769
+ data: node.data,
2770
+ node,
2771
+ colDef,
2772
+ column: col,
2773
+ api: currentGridInstance,
2774
+ context: currentGridInstance.getContext ? currentGridInstance.getContext() : undefined,
2775
+ };
2776
+
2777
+ let displayValue;
2778
+ if (colDef.cellRenderer && typeof colDef.cellRenderer === 'function') {
2779
+ displayValue = colDef.cellRenderer(params);
2780
+ } else if (colDef.valueFormatter && typeof colDef.valueFormatter === 'function') {
2781
+ displayValue = colDef.valueFormatter(params);
2782
+ } else {
2783
+ displayValue = params.value;
2784
+ }
2785
+
2786
+ if (exportConfig.export_remove_html && typeof displayValue === 'string') {
2787
+ displayValue = removeHtmlTags(displayValue);
2788
+ }
2789
+ if (exportConfig.export_trim_data && typeof displayValue === 'string') {
2790
+ displayValue = displayValue.trim();
2791
+ }
2792
+ return displayValue;
2793
+ });
2794
+ rows.push(row);
2795
+ });
2796
+
2797
+ // Create workbook and worksheet using ExcelJS
2798
+ const workbook = new ExcelJS.Workbook();
2799
+ const worksheet = workbook.addWorksheet('Export');
2800
+
2801
+ // Add header row
2802
+ worksheet.addRow(headers);
2803
+ // Style header row
2804
+ const headerRow = worksheet.getRow(1);
2805
+ headerRow.font = { bold: true };
2806
+ headerRow.eachCell((cell) => {
2807
+ cell.fill = {
2808
+ type: 'pattern',
2809
+ pattern: 'solid',
2810
+ fgColor: { argb: 'FFE0E0E0' }
2811
+ };
2812
+ });
2813
+
2814
+ // Add data rows
2815
+ rows.forEach(row => worksheet.addRow(row));
2816
+
2817
+ // Auto-fit column widths
2818
+ worksheet.columns.forEach((column, i) => {
2819
+ let maxLength = headers[i] ? headers[i].length : 10;
2820
+ rows.forEach(row => {
2821
+ const cellValue = row[i];
2822
+ if (cellValue != null) {
2823
+ const len = String(cellValue).length;
2824
+ if (len > maxLength) maxLength = len;
2825
+ }
2826
+ });
2827
+ column.width = Math.min(maxLength + 2, 50);
2828
+ });
2829
+
2830
+ // Generate and download
2831
+ const buffer = await workbook.xlsx.writeBuffer();
2832
+ const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
2833
+ const url = window.URL.createObjectURL(blob);
2834
+ const a = document.createElement('a');
2835
+ a.href = url;
2836
+ a.download = exportConfig.export_xls_filename;
2837
+ document.body.appendChild(a);
2838
+ a.click();
2839
+ document.body.removeChild(a);
2840
+ window.URL.revokeObjectURL(url);
2841
+ };
2842
+ if (exportToXLS) {
2843
+ let exportXlsButton = document.getElementById(`exportXlsButton-${options.id}`);
2844
+ let isNewXlsButton = false;
2845
+ if (!exportXlsButton) {
2846
+ isNewXlsButton = true;
2847
+ exportXlsButton = document.createElement('button');
2848
+ exportXlsButton.id = `exportXlsButton-${options.id}`;
2849
+ const icon = document.createElement('i');
2850
+ icon.classList.add('fas', 'fa-file-excel');
2851
+ exportXlsButton.appendChild(icon);
2852
+
2853
+ const buttonText = document.createElement('span');
2854
+ buttonText.innerText = ' Export to XLS';
2855
+ exportXlsButton.appendChild(buttonText);
2856
+ exportXlsButton.style.backgroundColor = '#4CAF50';
2857
+ exportXlsButton.style.border = 'none';
2858
+ exportXlsButton.style.color = 'white';
2859
+ exportXlsButton.style.padding = '5px 10px';
2860
+ exportXlsButton.style.textAlign = 'center';
2861
+ exportXlsButton.style.textDecoration = 'none';
2862
+ exportXlsButton.style.display = 'inline-block';
2863
+ exportXlsButton.style.fontSize = '14px';
2864
+ exportXlsButton.style.borderRadius = '5px';
2865
+ exportXlsButton.style.cursor = 'pointer';
2866
+ exportXlsButton.style.marginBottom = '10px';
2867
+ }
2868
+
2869
+ exportXlsButton.onclick = () => {
2870
+ const currentGridInstance = this.get('gridInstance');
2871
+ const currentGridConfig = this.get('gridConfig');
2872
+ if (currentGridInstance && currentGridConfig) {
2873
+ exportGridDataToXLS(currentGridInstance, currentGridConfig);
2874
+ } else {
2875
+ console.error('Grid instance or configuration not available for export');
2876
+ }
2877
+ };
2878
+
2879
+ if (isNewXlsButton) {
2880
+ gridContainer.parentNode.insertBefore(exportXlsButton, gridContainer);
2881
+ exportXlsButton.style.marginBottom = '10px';
2882
+ }
2883
+ }
2663
2884
  const paginationPanelCss = `
2664
2885
  /* Flexbox layout for pagination panel */
2665
2886
  .ag-paging-panel {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdmx/wappler_ag_grid",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "type": "module",
5
5
  "description": "App Connect module for AG Grid v35 - Advanced data grid with enhanced editing, filtering, and tree data capabilities.",
6
6
  "license": "MIT",
@@ -16,6 +16,7 @@
16
16
  "dependencies": {
17
17
  "@ag-grid-community/locale": "~35.1.0",
18
18
  "ag-grid-community": "~35.1.0",
19
+ "exceljs": "^4.4.0",
19
20
  "papaparse": "~5.5.2",
20
21
  "pdfmake": "~0.2.18",
21
22
  "read-excel-file": "~5.8.7"