From 726b50d6b5f14816a47a2aa1e268cfa3449ef32d Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 3 Sep 2025 18:11:43 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F(frontend)=20improve=20fallba?= =?UTF-8?q?ck=20width=20calculation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes we do not have the width of some columns in a table. In such cases, we need to calculate a fallback width to ensure the table is rendered correctly. We were previously using 120 points as the fallback width, but this has been improved to better fit the content. We now check the size left and distribute it among the unknown columns. --- CHANGELOG.md | 1 + .../doc-export/__tests__/TablePDF.test.tsx | 64 +++++++++++++++++++ .../doc-export/blocks-mapping/tablePDF.tsx | 44 ++++++++++--- 3 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-export/__tests__/TablePDF.test.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a13501965..672f4847e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to - #1282 - ♻️(backend) fallback to email identifier when no name #1298 - 🐛(backend) allow ASCII characters in user sub field #1295 +- ⚡️(frontend) improve fallback width calculation #1333 ### Fixed diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/__tests__/TablePDF.test.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/__tests__/TablePDF.test.tsx new file mode 100644 index 0000000000..bc33b12ec5 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-export/__tests__/TablePDF.test.tsx @@ -0,0 +1,64 @@ +import { describe, expect, it } from 'vitest'; + +import { utilTable } from '../blocks-mapping/tablePDF'; + +/** + * Tests for utilTable utility. + * Scenarios covered: + * - All widths specified and below full width + * - Mix of known / unknown widths (fallback distribution) + * - All widths unknown + * - Widths exceeding full table width (clamping & scale=100) + * - Sum exceeding full width without unknowns (no division by zero side-effects) + */ + +describe('utilTable', () => { + it('returns unchanged widths and correct scale when all widths are known and below full width', () => { + const input = [165, 200]; + const { columnWidths, tableScale } = utilTable(730, input); + expect(columnWidths).toEqual(input); // unchanged + expect(tableScale).toBe(50); + }); + + it('distributes fallback width equally among unknown columns', () => { + const input: (number | undefined)[] = [100, undefined, 200, undefined]; + const { columnWidths, tableScale } = utilTable(730, input); + expect(columnWidths).toEqual([100, 215, 200, 215]); + expect(tableScale).toBe(100); // fills full width exactly + }); + + it('handles all columns unknown', () => { + const input: (number | undefined)[] = [undefined, undefined]; + const { columnWidths, tableScale } = utilTable(730, input); + expect(columnWidths).toEqual([365, 365]); + expect(tableScale).toBe(100); + }); + + it('clamps total width to full width when sum exceeds it (single large column)', () => { + const input = [800]; + const { columnWidths, tableScale } = utilTable(730, input); + expect(columnWidths).toEqual([800]); + expect(tableScale).toBe(100); + }); + + it('clamps total width to full width when multiple columns exceed it', () => { + const input = [500, 300]; // sum = 800 > 730 + const { columnWidths, tableScale } = utilTable(730, input); + expect(columnWidths).toEqual([500, 300]); + expect(tableScale).toBe(100); + }); + + it('does not assign fallback when there are no unknown widths (avoid division by zero impact)', () => { + const input = [400, 400]; + const { columnWidths, tableScale } = utilTable(730, input); + expect(columnWidths).toEqual([400, 400]); + expect(tableScale).toBe(100); + }); + + it('computes proportional scale with custom fullWidth', () => { + const input = [100, 200]; // total 300 + const { columnWidths, tableScale } = utilTable(1000, input); + expect(columnWidths).toEqual([100, 200]); + expect(tableScale).toBe(30); + }); +}); diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/tablePDF.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/tablePDF.tsx index 878c88ea5e..d33a29cd35 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/tablePDF.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/tablePDF.tsx @@ -13,6 +13,7 @@ import { StyleSheet, Text } from '@react-pdf/renderer'; import { DocsExporterPDF } from '../types'; const PIXELS_PER_POINT = 0.75; +const FULL_WIDTH = 730; const styles = StyleSheet.create({ tableContainer: { border: '1px solid #ddd', @@ -47,16 +48,10 @@ export const blockMappingTablePDF: DocsExporterPDF['mappings']['blockMapping'][' true, ) as boolean[]; - /** - * Calculate the table scale based on the column widths. - */ - const columnWidths = blockContent.columnWidths.map((w) => w || 120); - const fullWidth = 730; - const totalWidth = Math.min( - columnWidths.reduce((sum, w) => sum + w, 0), - fullWidth, + const { columnWidths, tableScale } = utilTable( + FULL_WIDTH, + blockContent.columnWidths, ); - const tableScale = (totalWidth * 100) / fullWidth; return ( @@ -124,3 +119,34 @@ export const blockMappingTablePDF: DocsExporterPDF['mappings']['blockMapping']['
); }; + +/** + * Utility function to calculate the table column widths and scale. + * @param columnWidths - Array of column widths. + * @returns An object containing the resized column widths and the table scale. + */ +export const utilTable = ( + fullWidth: number, + columnWidths: (number | undefined)[], +) => { + const totalColumnWidthKnown = columnWidths.reduce( + (sum: number, w) => sum + (w ?? 0), + 0, + ); + const nbColumnWidthUnknown = columnWidths.filter((w) => !w).length; + + const fallbackWidth = + (fullWidth - totalColumnWidthKnown) / nbColumnWidthUnknown; + + const columnWidthsResized = columnWidths.map((w) => w || fallbackWidth); + const totalWidth = Math.min( + columnWidthsResized.reduce((sum: number, w) => sum + w, 0), + fullWidth, + ); + const tableScale = Math.round(((totalWidth * 100) / fullWidth) * 1000) / 1000; + + return { + columnWidths: columnWidthsResized, + tableScale, + }; +};