@cdmx/wappler_ag_grid 2.1.0 → 2.1.2

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 CHANGED
@@ -2,13 +2,14 @@
2
2
 
3
3
  **Major Update:** This release upgrades AG Grid to v35.1.0, bringing continued performance improvements and new features.
4
4
 
5
- ## 🚀 What's New in v2.0.23
5
+ ## 🚀 What's New in v2.1.1
6
6
 
7
7
  1. **🔥 AG Grid v35.1.0** - Latest version with all community features
8
8
  2. **⚡ Smooth Upgrade** - Non-breaking upgrade from v34, all existing configurations continue to work
9
9
  3. **🎨 HTML Tooltips** - Rich HTML tooltip support with JavaScript functions
10
10
  4. **🔧 Enhanced Tooltip System** - Custom tooltip components with automatic HTML detection
11
11
  5. **🚫 Suppress Model Update** - Option to prevent automatic reprocessing after update transactions
12
+ 6. **📤 Simplified Export Action** - Export format now uses a single dropdown selector (CSV, PDF, XLS) instead of separate checkboxes
12
13
 
13
14
  ## 🔄 Migration from v34 to v35
14
15
 
@@ -566,7 +567,11 @@ You can also specify left-only conditions, where only the field name is provided
566
567
 
567
568
  **Export**
568
569
  - To be used if you wish to use a separate Export button instead of using the inbuilt top left-cornered Export button.
569
- - Trigger this action to call Export Data to CSV/PDF download action based on selected file Type.
570
+ - Trigger this action to export grid data in your chosen format.
571
+ - **Format**: Select the export format from the dropdown:
572
+ - `csv` - Export as CSV file (default)
573
+ - `pdf` - Export as PDF file
574
+ - `xls` - Export as Excel (.xlsx) file
570
575
  - **Column State Integration**: When exporting data, the grid automatically respects the saved column state from localStorage. This means:
571
576
  - Columns are exported in the same order as they appear in the grid (based on user's saved column arrangement)
572
577
  - Hidden columns are automatically excluded from export
@@ -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",
@@ -3692,14 +3700,14 @@
3692
3700
  group: 'Properties',
3693
3701
  variables: [
3694
3702
  {
3695
- name: '1', optionName: '1', title: 'CSV', type: 'boolean',
3696
- dataBindings: true, defaultValue: true, required: false,
3697
- help: 'Export Grid data as CSV file.'
3698
- },
3699
- {
3700
- name: '2', optionName: '2', title: 'PDF', type: 'boolean',
3701
- dataBindings: true, defaultValue: false, required: false,
3702
- help: 'Export Grid data as PDF file.'
3703
+ name: '1', optionName: '1', title: 'Format', type: 'droplist',
3704
+ dataBindings: true, defaultValue: 'csv', required: false,
3705
+ "values": [
3706
+ {title: 'CSV', value: 'csv'},
3707
+ {title: 'PDF', value: 'pdf'},
3708
+ {title: 'XLS', value: 'xls'}
3709
+ ],
3710
+ help: 'Export Grid data as CSV, PDF, or XLS file.'
3703
3711
  }
3704
3712
  ]
3705
3713
  }
@@ -3911,6 +3919,10 @@
3911
3919
  {
3912
3920
  "src": "../../../node_modules/pdfmake/build/vfs_fonts.js",
3913
3921
  "dst": "js/vfs_fonts.js"
3922
+ },
3923
+ {
3924
+ "src": "../../../node_modules/exceljs/dist/exceljs.min.js",
3925
+ "dst": "js/exceljs.min.js"
3914
3926
  }
3915
3927
  ],
3916
3928
  "linkFiles": [
@@ -3954,6 +3966,11 @@
3954
3966
  "type": "js",
3955
3967
  "defer": true
3956
3968
  },
3969
+ {
3970
+ "src": "js/exceljs.min.js",
3971
+ "type": "js",
3972
+ "defer": true
3973
+ },
3957
3974
  {
3958
3975
  "src": "css/ag-theme-alpine.css",
3959
3976
  "type": "css"
@@ -4318,6 +4335,40 @@
4318
4335
  "dmx-ag-grid": true
4319
4336
  }
4320
4337
  },
4338
+ {
4339
+ "name": "dmx-ag-grid-export-xls-filename",
4340
+ "attributeStartsWith": "dmx-bind",
4341
+ "attribute": "export_xls_filename",
4342
+ "title": "Export XLS Filename",
4343
+ "type": "boolean",
4344
+ "display": "fieldset",
4345
+ "icon": "fa fa-lg fa-chevron-right",
4346
+ "groupTitle": "Grid Config",
4347
+ "groupIcon": "fa fa-lg fa-cubes",
4348
+ "defaultValue": false,
4349
+ "show": [
4350
+ "exportXlsFilename"
4351
+ ],
4352
+ "noChangeOnHide": true,
4353
+ "groupEnabler": true,
4354
+ "children": [
4355
+ {
4356
+ "name": "exportXlsFilename",
4357
+ "attributeStartsWith": "dmx-bind",
4358
+ "attribute": "export_xls_filename",
4359
+ "isValue": true,
4360
+ "dataBindings": true,
4361
+ "title": "XLS Filename",
4362
+ "type": "text",
4363
+ "help": "Export XLS filename.",
4364
+ "defaultValue": "export.xlsx",
4365
+ "initDisplay": "none"
4366
+ }
4367
+ ],
4368
+ "allowedOn": {
4369
+ "dmx-ag-grid": true
4370
+ }
4371
+ },
4321
4372
  {
4322
4373
  "name": "dmx-ag-grid-dark-mode",
4323
4374
  "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,20 +355,27 @@ 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) {
359
- Csv = true;
360
- }
358
+ exportGrid: function (format) {
359
+ // Default to csv if no format specified
360
+ format = (format || 'csv')
361
361
  dmx.nextTick(() => {
362
362
  const gridInst = this.get('gridInstance');
363
363
  const gridCfg = this.get('gridConfig');
364
- if (Csv) {
365
- exportGridData(gridInst, gridCfg);
366
- } else if (Pdf) {
367
- exportGridDataToPDF(gridInst, gridCfg);
368
- } else {
364
+ if (!gridInst || !gridCfg) {
369
365
  console.error('Grid not loaded to perform the requested export');
366
+ return;
367
+ }
368
+ switch (format) {
369
+ case 'pdf':
370
+ exportGridDataToPDF(gridInst, gridCfg);
371
+ break;
372
+ case 'xls':
373
+ exportGridDataToXLS(gridInst, gridCfg);
374
+ break;
375
+ case 'csv':
376
+ default:
377
+ exportGridData(gridInst, gridCfg);
378
+ break;
370
379
  }
371
380
  }, this);
372
381
  },
@@ -607,6 +616,7 @@ dmx.Component('ag-grid', {
607
616
  let groupedColumnDefs = [];
608
617
  let exportToCSV = this.props.export_to_csv;
609
618
  let exportToPDF = this.props.export_to_pdf;
619
+ let exportToXLS = this.props.export_to_xls;
610
620
  let cellRenderer;
611
621
 
612
622
  const gridThemeClass = options.dark_mode ? `${options.grid_theme}-dark` : options.grid_theme;
@@ -2049,6 +2059,7 @@ dmx.Component('ag-grid', {
2049
2059
  exportConfig: {
2050
2060
  export_csv_filename: options.export_csv_filename,
2051
2061
  export_pdf_filename: options.export_pdf_filename,
2062
+ export_xls_filename: options.export_xls_filename,
2052
2063
  export_remove_html: options.export_remove_html,
2053
2064
  export_trim_data: options.export_trim_data,
2054
2065
  export_exclude_fields: options.export_exclude_fields,
@@ -2660,6 +2671,221 @@ dmx.Component('ag-grid', {
2660
2671
  exportPdfButton.style.marginBottom = '10px';
2661
2672
  }
2662
2673
  }
2674
+ // XLS Export Function using ExcelJS
2675
+ exportGridDataToXLS = async (currentGridInstance, currentGridConfig) => {
2676
+ if (!currentGridInstance || currentGridInstance.isDestroyed()) {
2677
+ console.error('Grid API is destroyed or not initialized.');
2678
+ return;
2679
+ }
2680
+ if (typeof ExcelJS === 'undefined') {
2681
+ console.error('ExcelJS library is not loaded. Make sure exceljs.min.js is included.');
2682
+ return;
2683
+ }
2684
+ const exportConfig = currentGridConfig.context.exportConfig;
2685
+ const excludedColumnIds = ['checkboxColumn', 'actionsColumn'];
2686
+ const exportExcludeFieldsArray = exportConfig.export_exclude_fields ? exportConfig.export_exclude_fields.split(',') : [];
2687
+
2688
+ // Determine fields to export (reuse same logic as CSV)
2689
+ let fieldsToExport = [];
2690
+ const pageId = getPageId();
2691
+ const storageKey = exportConfig.column_state_storage_key || pageId;
2692
+ const savedColumnState = localStorage.getItem(`dmxState-${storageKey}`);
2693
+
2694
+ if (savedColumnState) {
2695
+ try {
2696
+ const parsedState = JSON.parse(savedColumnState);
2697
+ fieldsToExport = parsedState
2698
+ .filter((col) => {
2699
+ if (excludedColumnIds.includes(col.colId)) return false;
2700
+ if (col.hide) return false;
2701
+ return true;
2702
+ })
2703
+ .map((col) => {
2704
+ const columnDef = findColumnDefByColId(col.colId, exportConfig, currentGridConfig);
2705
+ return columnDef ? columnDef.field : col.colId;
2706
+ })
2707
+ .filter((field) => !exportExcludeFieldsArray.includes(field));
2708
+ } catch (err) {
2709
+ console.warn(`Failed to parse saved column state for key: dmxState-${storageKey}`, err);
2710
+ fieldsToExport = [];
2711
+ }
2712
+ }
2713
+
2714
+ function findColumnDefByColId(colId, expConfig, gridCfg) {
2715
+ if (expConfig.group_config) {
2716
+ const traverseColumns = (columns) => {
2717
+ for (const column of columns) {
2718
+ if (column.children) {
2719
+ const result = traverseColumns(column.children);
2720
+ if (result) return result;
2721
+ } else if (column.colId === colId) {
2722
+ return column;
2723
+ }
2724
+ }
2725
+ return null;
2726
+ };
2727
+ return traverseColumns(gridCfg.columnDefs);
2728
+ } else {
2729
+ return gridCfg.columnDefs.find((column) => column.colId === colId);
2730
+ }
2731
+ }
2732
+
2733
+ if (!fieldsToExport || fieldsToExport.length === 0) {
2734
+ let fieldsAndColIds;
2735
+ if (exportConfig.group_config) {
2736
+ const traverseColumns = (columns) => {
2737
+ const result = [];
2738
+ columns.forEach((column) => {
2739
+ if (column.children) {
2740
+ result.push(...traverseColumns(column.children));
2741
+ } else {
2742
+ result.push({ field: column.field, colId: column.colId, hide: column.hide });
2743
+ }
2744
+ });
2745
+ return result;
2746
+ };
2747
+ fieldsAndColIds = traverseColumns(currentGridConfig.columnDefs);
2748
+ } else {
2749
+ fieldsAndColIds = currentGridConfig.columnDefs.map((column) => ({
2750
+ field: column.field, colId: column.colId, hide: column.hide,
2751
+ }));
2752
+ }
2753
+ fieldsToExport = fieldsAndColIds.filter((column) => {
2754
+ return !excludedColumnIds.includes(column.colId) &&
2755
+ (!exportConfig.export_exclude_hidden_fields || !column.hide) &&
2756
+ !exportExcludeFieldsArray.includes(column.field);
2757
+ }).map((column) => column.field);
2758
+ }
2759
+
2760
+ // Build headers
2761
+ const headers = fieldsToExport.map(field => {
2762
+ return cnames.hasOwnProperty(field) ? cnames[field].custom_name : humanize(field);
2763
+ });
2764
+
2765
+ // Build rows
2766
+ const rows = [];
2767
+ currentGridInstance.forEachNode(node => {
2768
+ const row = fieldsToExport.map(field => {
2769
+ const columns = currentGridInstance.getColumnState();
2770
+ const col = columns.find(c => c.colId === field);
2771
+ const colDef = col ? currentGridInstance.getColumnDefs().find(def => def.colId === col.colId) : {};
2772
+ const params = {
2773
+ value: currentGridInstance.getCellValue({ rowNode: node, colKey: field }) ?? '-',
2774
+ data: node.data,
2775
+ node,
2776
+ colDef,
2777
+ column: col,
2778
+ api: currentGridInstance,
2779
+ context: currentGridInstance.getContext ? currentGridInstance.getContext() : undefined,
2780
+ };
2781
+
2782
+ let displayValue;
2783
+ if (colDef.cellRenderer && typeof colDef.cellRenderer === 'function') {
2784
+ displayValue = colDef.cellRenderer(params);
2785
+ } else if (colDef.valueFormatter && typeof colDef.valueFormatter === 'function') {
2786
+ displayValue = colDef.valueFormatter(params);
2787
+ } else {
2788
+ displayValue = params.value;
2789
+ }
2790
+
2791
+ if (exportConfig.export_remove_html && typeof displayValue === 'string') {
2792
+ displayValue = removeHtmlTags(displayValue);
2793
+ }
2794
+ if (exportConfig.export_trim_data && typeof displayValue === 'string') {
2795
+ displayValue = displayValue.trim();
2796
+ }
2797
+ return displayValue;
2798
+ });
2799
+ rows.push(row);
2800
+ });
2801
+
2802
+ // Create workbook and worksheet using ExcelJS
2803
+ const workbook = new ExcelJS.Workbook();
2804
+ const worksheet = workbook.addWorksheet('Export');
2805
+
2806
+ // Add header row
2807
+ worksheet.addRow(headers);
2808
+ // Style header row
2809
+ const headerRow = worksheet.getRow(1);
2810
+ headerRow.font = { bold: true };
2811
+ headerRow.eachCell((cell) => {
2812
+ cell.fill = {
2813
+ type: 'pattern',
2814
+ pattern: 'solid',
2815
+ fgColor: { argb: 'FFE0E0E0' }
2816
+ };
2817
+ });
2818
+
2819
+ // Add data rows
2820
+ rows.forEach(row => worksheet.addRow(row));
2821
+
2822
+ // Auto-fit column widths
2823
+ worksheet.columns.forEach((column, i) => {
2824
+ let maxLength = headers[i] ? headers[i].length : 10;
2825
+ rows.forEach(row => {
2826
+ const cellValue = row[i];
2827
+ if (cellValue != null) {
2828
+ const len = String(cellValue).length;
2829
+ if (len > maxLength) maxLength = len;
2830
+ }
2831
+ });
2832
+ column.width = Math.min(maxLength + 2, 50);
2833
+ });
2834
+
2835
+ // Generate and download
2836
+ const buffer = await workbook.xlsx.writeBuffer();
2837
+ const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
2838
+ const url = window.URL.createObjectURL(blob);
2839
+ const a = document.createElement('a');
2840
+ a.href = url;
2841
+ a.download = exportConfig.export_xls_filename;
2842
+ document.body.appendChild(a);
2843
+ a.click();
2844
+ document.body.removeChild(a);
2845
+ window.URL.revokeObjectURL(url);
2846
+ };
2847
+ if (exportToXLS) {
2848
+ let exportXlsButton = document.getElementById(`exportXlsButton-${options.id}`);
2849
+ let isNewXlsButton = false;
2850
+ if (!exportXlsButton) {
2851
+ isNewXlsButton = true;
2852
+ exportXlsButton = document.createElement('button');
2853
+ exportXlsButton.id = `exportXlsButton-${options.id}`;
2854
+ const icon = document.createElement('i');
2855
+ icon.classList.add('fas', 'fa-file-excel');
2856
+ exportXlsButton.appendChild(icon);
2857
+
2858
+ const buttonText = document.createElement('span');
2859
+ buttonText.innerText = ' Export to XLS';
2860
+ exportXlsButton.appendChild(buttonText);
2861
+ exportXlsButton.style.backgroundColor = '#4CAF50';
2862
+ exportXlsButton.style.border = 'none';
2863
+ exportXlsButton.style.color = 'white';
2864
+ exportXlsButton.style.padding = '5px 10px';
2865
+ exportXlsButton.style.textAlign = 'center';
2866
+ exportXlsButton.style.textDecoration = 'none';
2867
+ exportXlsButton.style.display = 'inline-block';
2868
+ exportXlsButton.style.fontSize = '14px';
2869
+ exportXlsButton.style.borderRadius = '5px';
2870
+ exportXlsButton.style.cursor = 'pointer';
2871
+ exportXlsButton.style.marginBottom = '10px';
2872
+ }
2873
+
2874
+ exportXlsButton.onclick = () => {
2875
+ const currentGridInstance = this.get('gridInstance');
2876
+ const currentGridConfig = this.get('gridConfig');
2877
+ if (currentGridInstance && currentGridConfig) {
2878
+ exportGridDataToXLS(currentGridInstance, currentGridConfig);
2879
+ } else {
2880
+ console.error('Grid instance or configuration not available for export');
2881
+ }
2882
+ };
2883
+
2884
+ if (isNewXlsButton) {
2885
+ gridContainer.parentNode.insertBefore(exportXlsButton, gridContainer);
2886
+ exportXlsButton.style.marginBottom = '10px';
2887
+ }
2888
+ }
2663
2889
  const paginationPanelCss = `
2664
2890
  /* Flexbox layout for pagination panel */
2665
2891
  .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.2",
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"