️(frontend) improve fallback width calculation

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.
This commit is contained in:
Anthony LC
2025-09-03 18:11:43 +02:00
parent 814eb1f1a1
commit 726b50d6b5
3 changed files with 100 additions and 9 deletions

View File

@@ -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

View File

@@ -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);
});
});

View File

@@ -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 (
<Table style={[styles.tableContainer, { width: `${tableScale}%` }]}>
@@ -124,3 +119,34 @@ export const blockMappingTablePDF: DocsExporterPDF['mappings']['blockMapping']['
</Table>
);
};
/**
* 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,
};
};