Skip to content

[WC-3441] DG2: export column enhancements#2287

Open
yordan-st wants to merge 5 commits into
mainfrom
feat/WC-3441_DG2-export-column-enhancements
Open

[WC-3441] DG2: export column enhancements#2287
yordan-st wants to merge 5 commits into
mainfrom
feat/WC-3441_DG2-export-column-enhancements

Conversation

@yordan-st

@yordan-st yordan-st commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Pull request type

Bug fix (non-breaking change which fixes an issue)


Description

When export type is set to "Default" for attribute columns, the exported Excel cells now use the attribute's own formatting (number decimals/grouping, date pattern) instead of exporting raw values without formatting.

For numbers, the exported cell mirrors what the grid shows: Mendix Decimal attributes do not expose a fixed decimal precision at runtime (only whether digits are grouped), so the format uses up to 8 fractional digits with trailing zeros suppressed. This keeps 1234.56 as 1234.56, 0.5 as 0.5, and integers as integers — instead of collapsing to whole numbers.

Also hides the export type and format properties in Studio Pro for dynamic text columns, since they have no effect.

What should be covered while testing?

  1. Attribute column with exportType "Default" and a Decimal attribute → exported cell is a numeric cell that mirrors the grid (e.g. 1234.56 stays 1234.56, 0.5 stays 0.5, integers stay integers; thousands grouping applied when the attribute uses it). Excel format: #,##0.######## (grouped) or 0.######## (ungrouped).
  2. Attribute column with exportType "Default" and a DateTime attribute with custom pattern dd/MM/yyyy → exported cell should have Excel format dd/mm/yyyy
  3. Attribute column with exportType "Number" or "Date" (custom) → still uses the manually specified export format (unchanged behavior)
  4. Dynamic text column → Studio Pro should NOT show export type, export number format, or export date format properties
  5. Custom content columns → unchanged behavior, all export types still work
  6. Existing configurations with no changes → no regression, everything exports as before

@yordan-st yordan-st force-pushed the feat/WC-3441_DG2-export-column-enhancements branch from 6696f2e to 39c37d2 Compare June 22, 2026 16:01
@yordan-st yordan-st marked this pull request as ready for review June 22, 2026 16:11
@yordan-st yordan-st requested a review from a team as a code owner June 22, 2026 16:11
@github-actions

This comment has been minimized.

@yordan-st yordan-st force-pushed the feat/WC-3441_DG2-export-column-enhancements branch from 39c37d2 to 96a5c83 Compare June 23, 2026 12:10
@github-actions

This comment has been minimized.

iobuhov
iobuhov previously approved these changes Jun 23, 2026
@yordan-st yordan-st force-pushed the feat/WC-3441_DG2-export-column-enhancements branch from c94f30c to adc9e02 Compare June 24, 2026 12:51
@github-actions

This comment has been minimized.

@yordan-st yordan-st requested a review from iobuhov June 24, 2026 13:11
@yordan-st yordan-st force-pushed the feat/WC-3441_DG2-export-column-enhancements branch from adc9e02 to 1e6e1fd Compare July 1, 2026 13:43
@github-actions

This comment has been minimized.

…trailing dot

A static `{base}.########` mask emits the literal decimal point even when
all fractional `#` digits collapse, so whole numbers exported as `1983.`
and broke the export e2e test. Count the fractional digits from the value
itself instead, so integers use `0` (no dot) and decimals mirror the grid.
@yordan-st yordan-st force-pushed the feat/WC-3441_DG2-export-column-enhancements branch from 827f4bb to d1dd27f Compare July 10, 2026 13:02
@github-actions

Copy link
Copy Markdown
Contributor

AI Code Review

⚠️ Approved with suggestions — low-severity items only, safe to merge


What was reviewed

File Change
packages/pluggableWidgets/datagrid-web/CHANGELOG.md Added entries for the new default-format export and dynamicText property-hide fix
packages/pluggableWidgets/datagrid-web/src/Datagrid.editorConfig.ts Hide exportType/exportNumberFormat/exportDateFormat for dynamicText columns
packages/pluggableWidgets/datagrid-web/src/features/data-export/cell-readers.ts New getAttributeDefaultFormat + countDecimalPlaces; attribute reader now branches on exportType === "default"
packages/pluggableWidgets/datagrid-web/src/features/data-export/__tests__/cell-readers.spec.ts 8 new unit tests covering default-format number/date paths and the whole-number regression
packages/pluggableWidgets/datagrid-web/openspec/*.md Design/proposal/tasks docs (new, non-runtime)

Skipped (out of scope): dist/, pnpm-lock.yaml, openspec/.openspec.yaml


Findings

⚠️ Low — M→m replacement will corrupt minute/second tokens in datetime patterns

File: packages/pluggableWidgets/datagrid-web/src/features/data-export/cell-readers.ts line 130
Note: cfg.pattern.replace(/M/g, "m") converts every uppercase M to m. In Excel format codes m is month (not M), but Mendix patterns also use m for minutes (e.g., MM/dd/yyyy HH:mm:ss). A pattern like "MM/dd/yyyy HH:mm:ss" would pass through unchanged since there are no uppercase Ms — however a Java-style pattern "dd/MM/yyyy HH:mm" contains uppercase M for months; converting all of them is correct if no other uppercase tokens use M. The real risk is a pattern such as "MMMM d, yyyy" (full month name) — Excel doesn't support the full-name form — the replacement converts it to "mmmm d, yyyy" which is valid Excel and maps to minute (not month name). This is a niche edge case, but it's worth a code comment to signal the known limitation, especially since the existing getDefaultDateFormat does the same replacement at line 78 and deserves the same note.
Fix: Add a brief inline comment above each replace(/M/g, "m") call noting that this covers only the simple M (month) → m conversion and that full-name month tokens (MMMM) are not supported:

// Mendix uses M for month (Java style); Excel uses m. Full-name month tokens (MMMM) are not supported.
return cfg.pattern.replace(/M/g, "m");

⚠️ Low — countDecimalPlaces uses Big.toFixed() with no argument, which truncates trailing zeros

File: packages/pluggableWidgets/datagrid-web/src/features/data-export/cell-readers.ts line 117
Note: Big.toFixed() with no argument is equivalent to toFixed(0) — it rounds to zero decimal places and returns an integer string. For example, new Big("1234.56").toFixed() returns "1235", not "1234.56". The decimal count derived from that would always be 0. This would make getAttributeDefaultFormat return "#,##0" instead of "#,##0.00" for 1234.56.

Looking at how countSignificantDigits uses toFixed() (line 109) in the same file, and the tests for countDecimalPlaces pass (verified by the tasks.md claim of 221 passing tests), there may be a version of big.js where toFixed() without arguments returns the full decimal representation. However, the standard big.js docs specify toFixed(dp?) defaults to dp=0. It is worth verifying this is the intended behavior, or using value.toFixed(value.c?.length ?? 20) / value.toString() instead to reliably get the full decimal string.
Fix: Replace value.toFixed() with value.toString() to guarantee all decimal places are included:

function countDecimalPlaces(value: Big): number {
    const str = value.toString();
    const dot = str.indexOf(".");
    return dot === -1 ? 0 : str.length - dot - 1;
}

(Note: countSignificantDigits at line 109 has the same issue if its toFixed() is also intended to preserve decimals — worth reviewing together.)

⚠️ Low — Tests cast listAttribute(...) to any to attach .formatter — consider extending the builder

File: packages/pluggableWidgets/datagrid-web/src/features/data-export/__tests__/cell-readers.spec.ts lines 72, 87, 102, 116, 132, 147, 161
Note: Every new test uses const attr = listAttribute(() => ...) as any then sets attr.formatter = { ... } via mutation. This works but it bypasses TypeScript's type checks on the mock structure and makes the tests fragile to builder changes. The AGENTS.md guidelines call for using builders and avoiding manual mock objects. If the formatter property is a real part of ListAttributeValue (available since Mendix 10 runtime per proposal.md), consider extending EditableValueBuilder / listAttribute in @mendix/widget-plugin-test-utils to support it, or at minimum use a typed helper:

function attrWithFormatter<T>(value: () => T, formatter: object) {
    const attr = listAttribute(value) as ReturnType<typeof listAttribute<T>> & { formatter: typeof formatter };
    attr.formatter = formatter;
    return attr;
}

This is non-blocking but improves test maintainability.


Positives

  • The whole-number trailing-dot regression test ("1983""0" not "0.") is a concrete and well-documented guard against a specific Excel rendering bug — the inline comment explains why the static mask can't be used.
  • getAttributeDefaultFormat is correctly isolated from the main attribute reader — the branching at the call site is clean and doesn't pollute the existing getCellFormat path.
  • The decimalPrecision != null guard correctly uses != null (covers both null and undefined) rather than a loose falsy check, preserving the explicit decimalPrecision: 0 case.
  • CHANGELOG entries are user-facing and correctly avoid implementation details.
  • hideNestedPropertiesIn usage in editorConfig mirrors the existing pattern for customContent at line 30, keeping the file consistent.
  • Tests use readSingleCell factory helper and column/listAttribute from test-utils, consistent with existing patterns in the file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants