Compare commits

...

2 Commits

Author SHA1 Message Date
rusackas
0bde9a7f28 test(table): move all_records totals test to avoid perturbing shared memoized state
The added test called transformProps before the pre-existing 'render basic
data' test in the same file, evicting the module-level memoizeOne cache that
test relies on and flipping its timestamp column formatting. Relocating the
test to the end of the suite keeps it from disturbing earlier tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 18:45:16 -07:00
rusackas
5cb1752e65 fix(table): pick totals query positionally so all_records percent metrics don't shift it
`buildQuery` inserts an extra query ahead of the totals query in `queriesData`
when `percent_metric_calculation` is set to "all_records", so the fixed-index
destructuring in `transformProps` grabbed that query instead of the actual
totals query, leaving the summary row with the wrong (and unformatted) values.

Fixes #39587
2026-07-25 17:26:37 -07:00
2 changed files with 72 additions and 2 deletions

View File

@@ -712,12 +712,27 @@ const transformProps = (
let totalQuery;
let rowCount;
if (serverPagination) {
[baseQuery, countQuery, totalQuery] = queriesData;
[baseQuery, countQuery] = queriesData;
rowCount = (countQuery?.data?.[0]?.rowcount as number) ?? 0;
} else {
[baseQuery, totalQuery] = queriesData;
[baseQuery] = queriesData;
rowCount = baseQuery?.rowcount ?? 0;
}
// `buildQuery` may prepend an extra query (used to compute percent metrics
// against the entire result set when `percent_metric_calculation` is set to
// `all_records`) before the totals query. Since the totals query, when
// present, is always the last entry in `queriesData`, look it up positionally
// from the end rather than assuming a fixed index. The minimum number of
// queries expected without a totals query is 1 (base query), or 2 when
// server pagination is enabled (base query + row count query).
const minQueriesWithoutTotals = serverPagination ? 2 : 1;
if (
showTotals &&
queryMode === QueryMode.Aggregate &&
queriesData.length > minQueriesWithoutTotals
) {
totalQuery = queriesData[queriesData.length - 1];
}
const data = processDataRecords(baseQuery?.data, columns);
const comparisonData = processComparisonDataRecords(
baseQuery?.data,

View File

@@ -2575,6 +2575,61 @@ describe('plugin-chart-table', () => {
);
expect(screen.queryByText('Search by')).toBeInTheDocument();
});
test(
'should read the totals row from the correct query when percent metrics ' +
'use the "all records" calculation mode',
() => {
// When `percent_metric_calculation` is `all_records`, buildQuery adds an
// extra query (used to compute percentages against the entire result set)
// *before* the totals query in `queriesData`. Verify totals are still
// sourced from the actual totals query and not this preceding query.
const props = {
...testData.basic,
rawFormData: {
...testData.basic.rawFormData,
query_mode: QueryMode.Aggregate,
metrics: ['sum__num'],
percent_metrics: ['count'],
percent_metric_calculation: 'all_records',
show_totals: true,
column_config: {
sum__num: { d3NumberFormat: '.0%' },
},
},
queriesData: [
{
...testData.basic.queriesData[0],
colnames: ['name', 'sum__num', '%count'],
coltypes: [
GenericDataType.String,
GenericDataType.Numeric,
GenericDataType.Numeric,
],
data: [{ name: 'Michael', sum__num: 0.1, '%count': 0.05 }],
},
// extra "all records" query used only to compute percent metrics
{
...testData.basic.queriesData[0],
colnames: ['count'],
coltypes: [GenericDataType.Numeric],
data: [{ count: 999 }],
},
// actual totals query
{
...testData.basic.queriesData[0],
colnames: ['sum__num'],
coltypes: [GenericDataType.Numeric],
data: [{ sum__num: 0.27 }],
},
],
};
const transformedProps = transformProps(props);
expect(transformedProps.totals).toEqual({ sum__num: 0.27 });
},
);
});
/**