You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/07/30 01:54:48 UTC
(superset) 01/01: fix(pivot-table): keep D3_FORMAT-styled numbers intact in pivoted Excel export
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch fix/issue-38555-followup
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 3ea77a92dd3c8bdc0de8339f9c4b287c7f7ed843
Author: rusackas <ev...@rusackas.com>
AuthorDate: Wed Jul 29 18:50:24 2026 -0700
fix(pivot-table): keep D3_FORMAT-styled numbers intact in pivoted Excel export
The "Export to Pivoted Excel" download runs entirely client-side via
SheetJS's utils.table_to_book(), reading the rendered pivot table DOM.
By default SheetJS tries to infer numbers/dates from each cell's
displayed text, which mis-parses non-US D3_FORMAT strings: "1.234,56"
(Spanish decimal formatting) silently became the number 1.23456,
"3.500" became 3.5, and "12,50%" became 12.5.
Pass raw: true so every cell is kept as the literal text already
formatted by D3_FORMAT, instead of being reinterpreted by SheetJS.
Fixes #38555
---
.../src/utils/downloadAsPivotExcel.test.ts | 59 ++++++++++++++++++++++
.../src/utils/downloadAsPivotExcel.ts | 6 ++-
2 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/superset-frontend/src/utils/downloadAsPivotExcel.test.ts b/superset-frontend/src/utils/downloadAsPivotExcel.test.ts
new file mode 100644
index 00000000000..5b6bb74d10f
--- /dev/null
+++ b/superset-frontend/src/utils/downloadAsPivotExcel.test.ts
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import type { WorkBook } from 'xlsx';
+import exportPivotExcel from './downloadAsPivotExcel';
+
+const mockWriteFile = jest.fn();
+
+jest.mock('xlsx', () => {
+ const actual = jest.requireActual('xlsx');
+ return {
+ ...actual,
+ writeFile: (...args: unknown[]) => mockWriteFile(...args),
+ };
+});
+
+test('preserves locale-formatted numbers exactly as rendered, without SheetJS reinterpreting them', () => {
+ document.body.innerHTML = `
+ <table id="pivot-table">
+ <tbody>
+ <tr>
+ <td>1.234,56</td>
+ <td>12,50%</td>
+ <td>3.500</td>
+ </tr>
+ </tbody>
+ </table>
+ `;
+
+ exportPivotExcel('#pivot-table', 'export');
+
+ expect(mockWriteFile).toHaveBeenCalledTimes(1);
+ const workbook = mockWriteFile.mock.calls[0][0] as WorkBook;
+ const sheet = workbook.Sheets[workbook.SheetNames[0]];
+
+ // These are Spanish-locale D3_FORMAT strings ("." as thousands separator,
+ // "," as decimal separator). Each must survive the export untouched, as a
+ // text cell, rather than being silently reparsed as a different number
+ // (SheetJS's default HTML table parsing would otherwise turn "1.234,56"
+ // into the number 1.23456, "3.500" into 3.5, and "12,50%" into 12.5).
+ expect(sheet.A1).toMatchObject({ t: 's', v: '1.234,56' });
+ expect(sheet.B1).toMatchObject({ t: 's', v: '12,50%' });
+ expect(sheet.C1).toMatchObject({ t: 's', v: '3.500' });
+});
diff --git a/superset-frontend/src/utils/downloadAsPivotExcel.ts b/superset-frontend/src/utils/downloadAsPivotExcel.ts
index 40d10fe3492..6603ad30ea9 100644
--- a/superset-frontend/src/utils/downloadAsPivotExcel.ts
+++ b/superset-frontend/src/utils/downloadAsPivotExcel.ts
@@ -23,6 +23,10 @@ export default function exportPivotExcel(
fileName: string,
) {
const table = document.querySelector(tableSelector);
- const workbook = utils.table_to_book(table);
+ // `raw: true` keeps every cell as the literal text rendered in the DOM.
+ // Without it, SheetJS tries to infer numbers/dates from the displayed
+ // string, which mangles values that were formatted using a non-US
+ // D3_FORMAT (e.g. "1.234,56" gets misread as a date or truncated number).
+ const workbook = utils.table_to_book(table, { raw: true });
writeFile(workbook, `${fileName}.xlsx`);
}