-
Notifications
You must be signed in to change notification settings - Fork 156
feat(excel exporter): making fflate dynamic import #16561
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
…gniteUI/igniteui-angular into copilot/add-pdf-export-feature
Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
- Added indentation support for TreeGrid and HierarchicalGrid records in PDF export - Records with level property now indent by 15pt per level in first column - Skip hidden records (collapsed hierarchy nodes) from export - Added jspdf to ng-add schematic dependencies map for automatic installation Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Grids are typically wide, so landscape orientation is more suitable as the default for grid exports. Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Created a comprehensive demo showing IgxPdfExporterService API usage: - Interactive configuration panel for all export options - Examples with regular grid, tree grid, and hierarchical grid - Direct service API usage (not through toolbar UI) - Live configuration of orientation, page size, borders, and font size - Located at /gridPdfExport route Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
For IgxHierarchicalGridComponent exports, child records now display in separate child tables with their own headers beneath each parent row that has children: - Child tables are indented to show hierarchy - Each child table includes proper column headers - Child tables automatically paginate if needed - Extracted reusable methods for drawing headers and rows Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Added comment to clarify that TreeGrid PDF export indentation works for both: - Hierarchical data binding - Flat self-referencing data with foreignKey The implementation already handles both cases correctly since the base exporter normalizes both modes into TreeGridRecord with proper level property. Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Updated drawDataRow to properly handle SummaryRecord types: - Detects when record is a SummaryRecord - Extracts label and value/summaryResult from summary objects - Formats as "label: value" similar to Excel export - Falls back to just value if no label present - Prevents "[object Object]" display in PDF exports Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Implemented multi-level header support for column groups: - Detects when columns have multi-level headers (column groups) - Draws headers level by level from parent to child groups - Properly handles columnSpan for grouped headers - Respects startIndex for correct positioning - Redraws multi-level headers on page breaks - Maintains compatibility with simple single-level headers Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Fixed bug where column headers at level 2 and beyond were not rendered: - Updated filter logic to include headers at each specific level - Now correctly includes both MultiColumnHeader and ColumnHeader types at any level - Maintains proper spanning behavior for leaf columns from earlier levels - Simplified logic for better clarity and correctness Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Added extensive test coverage for PDF export functionality: PDF Exporter Service Tests (pdf-exporter.spec.ts): - Portrait orientation export - Various page sizes (a3, a5, legal) - Different font sizes - Large datasets requiring pagination - Long text truncation - Mixed data types handling - Custom filename - Empty rows in data - exportStarted event emission - exportEnded event with pdf object PDF Grid Exporter Tests (pdf-exporter-grid.spec.ts): - Landscape orientation - Table borders disabled - Custom font size - Different page sizes - ignoreColumnsOrder option - ignoreFiltering option - ignoreSorting option - exportStarted event for grid export - Multiple columns handling - Custom filename from options Grid Toolbar Exporter Tests (grid-toolbar.spec.ts): - PDF option displayed by default - PDF option hidden when exportPDF is false - PDF option shown when exportPDF is true - Custom PDF text display - PDF export triggered on click - exportStarted event for PDF export - PDF export cancellation Increased test coverage for newly added PDF export code in both the exporter service and toolbar component. Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Removed tests that referenced the non-existent exportStarted event on IgxPdfExporterService. The base exporter only has exportEnded event, not exportStarted. This matches the pattern used by Excel and CSV exporters. Fixed tests in: - pdf-exporter.spec.ts: Removed exportStarted event test - pdf-exporter-grid.spec.ts: Removed exportStarted event test for grid export Note: The grid-toolbar-exporter component still has its own exportStarted output event which is correct and those tests remain unchanged. Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
…gniteUI/igniteui-angular into copilot/add-pdf-export-feature
…ical and tree grids Added 6 new tests to cover advanced grid export scenarios: 1. Grid with multi-column headers (OneGroupThreeColsGridComponent) - Tests export of grids with column groups 2. Grid with nested multi-column headers (NestedColumnGroupsGridComponent) - Tests export of grids with deeply nested column group hierarchies 3. Grid with summaries (IgxGridFilteringComponent) - Tests export of grids with summary rows - Verifies summary values are properly formatted 4. Hierarchical Grid (IgxHierarchicalGridTestBaseComponent) - Tests export of hierarchical grids with child tables - Verifies child table headers are included 5. Tree Grid with hierarchical data (IgxTreeGridSortingComponent) - Tests export of tree grids with nested data structure - Verifies proper indentation based on level 6. Tree Grid with flat self-referencing data (IgxTreeGridPrimaryForeignKeyComponent) - Tests export of tree grids using primaryKey/foreignKey - Verifies indentation works for flat data with parent-child relationships All tests follow the existing pattern and validate that the PDF exporter correctly handles these advanced grid configurations. Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Implemented text truncation with ellipsis for column headers when text is wider than the available header space. This applies to both: 1. Multi-level column headers (column groups) in drawMultiLevelHeaders 2. Simple column headers in drawTableHeaders The truncation logic: - Calculates max text width as column width minus 10px padding (5px each side) - If header text exceeds available space, truncates character by character - Adds ellipsis (...) to indicate truncation - Similar to existing cell value truncation logic Also added test case to verify truncation works with nested column groups on smaller page size (a5) where truncation is more likely to occur. This prevents header text from overflowing cell boundaries and overlapping with adjacent headers, maintaining proper PDF layout. Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
* refactor(exporters): moving exporters under grids/core * test(excel exporter): fixing import paths from /core
* refactor(exporters): moving exporters under grids/core * test(excel exporter): fixing import paths from /core * feat(pdf exporter): making jsPDF a dynamic import * chore(*): fixing incorrect block indentation
…into fflate-dynamic-import
…into fflate-dynamic-import
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR converts the fflate library from a static import to dynamic imports across the Excel exporter functionality to reduce initial bundle size. The change affects the main exporter service and all Excel file generation classes.
Key Changes:
- Removed static
importstatements forfflatefunctions (strToU8,zip) - Replaced synchronous calls with dynamic
import('fflate').then()patterns - Added a clarifying comment in the main exporter service
Reviewed changes
Copilot reviewed 2 out of 4 changed files in this pull request and generated 14 comments.
| File | Description |
|---|---|
| excel-exporter.ts | Updated main exporter to dynamically import zip function from fflate |
| excel-files.ts | Converted all strToU8 calls to use dynamic imports instead of static import |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export class RootRelsFile implements IExcelFile { | ||
| public writeElement(folder: Object) { | ||
| folder['.rels'] = strToU8(ExcelStrings.getRels()); | ||
| import('fflate').then(({ strToU8 }) => folder['.rels'] = strToU8(ExcelStrings.getRels())); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The writeElement method appears to be synchronous based on its signature, but the dynamic import makes it asynchronous without returning a Promise. Callers expecting synchronous completion will not wait for the file data to be written. Consider changing the method signature to return Promise or ensure the caller awaits completion.
| export class AppFile implements IExcelFile { | ||
| public writeElement(folder: Object, worksheetData: WorksheetData) { | ||
| folder['app.xml'] = strToU8(ExcelStrings.getApp(worksheetData.options.worksheetName)); | ||
| import('fflate').then(({ strToU8 }) => folder['app.xml'] = strToU8(ExcelStrings.getApp(worksheetData.options.worksheetName))); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The writeElement method appears to be synchronous based on its signature, but the dynamic import makes it asynchronous without returning a Promise. Callers expecting synchronous completion will not wait for the file data to be written. Consider changing the method signature to return Promise or ensure the caller awaits completion.
| export class CoreFile implements IExcelFile { | ||
| public writeElement(folder: Object) { | ||
| folder['core.xml'] = strToU8(ExcelStrings.getCore()); | ||
| import('fflate').then(({ strToU8 }) => folder['core.xml'] = strToU8(ExcelStrings.getCore())); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The writeElement method appears to be synchronous based on its signature, but the dynamic import makes it asynchronous without returning a Promise. Callers expecting synchronous completion will not wait for the file data to be written. Consider changing the method signature to return Promise or ensure the caller awaits completion.
| public writeElement(folder: Object, worksheetData: WorksheetData) { | ||
| const hasSharedStrings = !worksheetData.isEmpty || worksheetData.options.alwaysExportHeaders; | ||
| folder['workbook.xml.rels'] = strToU8(ExcelStrings.getWorkbookRels(hasSharedStrings)); | ||
| import('fflate').then(({ strToU8 }) => folder['workbook.xml.rels'] = strToU8(ExcelStrings.getWorkbookRels(hasSharedStrings))); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The writeElement method appears to be synchronous based on its signature, but the dynamic import makes it asynchronous without returning a Promise. Callers expecting synchronous completion will not wait for the file data to be written. Consider changing the method signature to return Promise or ensure the caller awaits completion.
| export class ThemeFile implements IExcelFile { | ||
| public writeElement(folder: Object) { | ||
| folder['theme1.xml'] = strToU8(ExcelStrings.getTheme()); | ||
| import('fflate').then(({ strToU8 }) => folder['theme1.xml'] = strToU8(ExcelStrings.getTheme())); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The writeElement method appears to be synchronous based on its signature, but the dynamic import makes it asynchronous without returning a Promise. Callers expecting synchronous completion will not wait for the file data to be written. Consider changing the method signature to return Promise or ensure the caller awaits completion.
| import('fflate').then(({ strToU8 }) => { | ||
| folder['sharedStrings.xml'] = strToU8(ExcelStrings.getSharedStringXML( | ||
| dict.stringsCount, | ||
| sortedValues.length, | ||
| sharedStrings.join('')) | ||
| ); | ||
| }); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The writeElement method appears to be synchronous based on its signature, but the dynamic import makes it asynchronous without returning a Promise. Callers expecting synchronous completion will not wait for the file data to be written. Consider changing the method signature to return Promise or ensure the caller awaits completion.
| } | ||
|
|
||
| folder['table1.xml'] = strToU8(ExcelStrings.getTablesXML(autoFilterDimension, tableDimension, tableColumns, sortString)); | ||
| import('fflate').then(({ strToU8 }) => folder['table1.xml'] = strToU8(ExcelStrings.getTablesXML(autoFilterDimension, tableDimension, tableColumns, sortString))); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The writeElement method appears to be synchronous based on its signature, but the dynamic import makes it asynchronous without returning a Promise. Callers expecting synchronous completion will not wait for the file data to be written. Consider changing the method signature to return Promise or ensure the caller awaits completion.
| export class WorksheetRelsFile implements IExcelFile { | ||
| public writeElement(folder: Object) { | ||
| folder['sheet1.xml.rels'] = strToU8(ExcelStrings.getWorksheetRels()); | ||
| import('fflate').then(({ strToU8 }) => folder['sheet1.xml.rels'] = strToU8(ExcelStrings.getWorksheetRels())); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The writeElement method appears to be synchronous based on its signature, but the dynamic import makes it asynchronous without returning a Promise. Callers expecting synchronous completion will not wait for the file data to be written. Consider changing the method signature to return Promise or ensure the caller awaits completion.
projects/igniteui-angular/grids/core/src/services/excel/excel-exporter.ts
Show resolved
Hide resolved
| this.exportEnded.emit({ xlsx: fileData }); | ||
| done(); | ||
| // Dynamically import fflate to reduce initial bundle size | ||
| import('fflate').then(({ zip }) => { |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dynamic import of fflate is executed on every export operation. Consider caching the imported module at the class level to avoid redundant imports for subsequent exports within the same session.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to apply changes based on this feedback
…exporter.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Closes #
Additional information (check all that apply):
Checklist:
feature/README.MDupdates for the feature docsREADME.MDCHANGELOG.MDupdates for newly added functionalityng updatemigrations for the breaking changes (migrations guidelines)