Skip to content

Commit 903d443

Browse files
authored
feat: add show more for outermost dimension in pivot (#8570)
* feat: add show more for outermost pivot dimension * alignment and state fix * slice axis total based on actual limit
1 parent 207ff2e commit 903d443

File tree

11 files changed

+255
-19
lines changed

11 files changed

+255
-19
lines changed

web-common/src/features/dashboards/pivot/PivotDisplay.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@
150150
rowId,
151151
columnId,
152152
)}
153+
setPivotOutermostRowLimit={(limit) =>
154+
metricsExplorerStore.setPivotOutermostRowLimit($exploreName, limit)}
153155
setPivotRowLimitForExpanded={(expandIndex, limit) =>
154156
metricsExplorerStore.setPivotRowLimitForExpandedRow(
155157
$exploreName,

web-common/src/features/dashboards/pivot/PivotExpandableCell.svelte

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
export let row: Row<PivotDataRow>;
99
export let value: string;
1010
export let assembled = true;
11+
export let hasNestedDimensions = false;
1112
1213
$: canExpand = row.getCanExpand();
1314
$: expanded = row.getIsExpanded();
1415
$: assembledAndCanExpand = assembled && canExpand;
16+
17+
$: needsSpacer = row.depth >= 1 || (hasNestedDimensions && !canExpand);
1518
</script>
1619

1720
<div
@@ -26,7 +29,7 @@
2629
<div class="caret opacity-100 shrink-0" class:expanded>
2730
<ChevronRight size="16px" color="#9CA3AF" />
2831
</div>
29-
{:else if row.depth >= 1}
32+
{:else if needsSpacer}
3033
<span class="shrink-0"><Spacer size="16px" /></span>
3134
{/if}
3235

web-common/src/features/dashboards/pivot/PivotShowMoreCell.svelte

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@
88
export let row: Row<PivotDataRow>;
99
export let value: string;
1010
export let assembled = true;
11+
export let hasNestedDimensions = false;
12+
13+
$: needsSpacer = row.depth >= 1 || hasNestedDimensions;
1114
</script>
1215

1316
<div class="show-more-cell" style:padding-left="{row?.depth * 14}px">
14-
<Spacer size="16px" />
17+
{#if needsSpacer}
18+
<Spacer size="16px" />
19+
{/if}
1520
<Tooltip distance={8} location="right">
1621
<span class={assembled ? "ui-copy" : "ui-copy-inactive"}>
1722
Show more ...

web-common/src/features/dashboards/pivot/PivotTable.svelte

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
export let setPivotActiveCell:
5757
| ((rowId: string, columnId: string) => void)
5858
| undefined = undefined;
59+
export let setPivotOutermostRowLimit: ((limit: number) => void) | undefined =
60+
undefined;
5961
export let setPivotRowLimitForExpanded:
6062
| ((expandIndex: string, limit: number) => void)
6163
| undefined = undefined;
@@ -209,13 +211,27 @@
209211
// Handle "Show More" button clicks
210212
if (value === SHOW_MORE_BUTTON && rowHeader) {
211213
const rowData = row.original;
212-
213-
const expandIndex = rowId.split(".").slice(0, -1).join(".");
214214
const currentLimit = rowData.__currentLimit as number;
215215
const nextLimit = getNextRowLimit(currentLimit);
216216
217-
if (expandIndex && nextLimit && setPivotRowLimitForExpanded) {
218-
setPivotRowLimitForExpanded(expandIndex, nextLimit);
217+
if (!nextLimit) return;
218+
219+
// Check if this is the outermost dimension or a nested dimension
220+
// Outermost dimension has rowId like "0", "1", etc. (no dots)
221+
// Nested dimensions have rowId like "0.1", "0.1.2", etc.
222+
const isOutermostDimension = !rowId.includes(".");
223+
224+
if (isOutermostDimension) {
225+
// Handle outermost dimension "Show more" click
226+
if (setPivotOutermostRowLimit) {
227+
setPivotOutermostRowLimit(nextLimit);
228+
}
229+
} else {
230+
// Handle nested dimension "Show more" click
231+
const expandIndex = rowId.split(".").slice(0, -1).join(".");
232+
if (expandIndex && setPivotRowLimitForExpanded) {
233+
setPivotRowLimitForExpanded(expandIndex, nextLimit);
234+
}
219235
}
220236
return;
221237
}

web-common/src/features/dashboards/pivot/pivot-column-definition.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,9 @@ function getNestedColumnDef(
422422
const rowDimensionsForColumnDef = rowDimensions.slice(0, 1);
423423
const nestedLabel = getRowNestedLabel(rowDimensions);
424424

425+
// Check if there are nested dimensions (more than one row dimension)
426+
const hasNestedDimensions = rowDimensions.length > 1;
427+
425428
// Create row dimension columns
426429
const rowDefinitions: ColumnDef<PivotDataRow>[] =
427430
rowDimensionsForColumnDef.map((d) => {
@@ -443,6 +446,7 @@ function getNestedColumnDef(
443446
return cellComponent(PivotShowMoreCell, {
444447
value: label,
445448
row,
449+
hasNestedDimensions,
446450
});
447451
}
448452

@@ -456,6 +460,7 @@ function getNestedColumnDef(
456460
return cellComponent(PivotExpandableCell, {
457461
value: formattedDimensionValue,
458462
row,
463+
hasNestedDimensions,
459464
});
460465
},
461466
};

web-common/src/features/dashboards/pivot/pivot-constants.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ export const PIVOT_ROW_LIMIT_OPTIONS = [5, 10, 25, 50, 100] as const;
1717
* @param rowLimit - The maximum number of rows to fetch (undefined = unlimited)
1818
* @param rowOffset - The current row offset (for pagination)
1919
* @param pageSize - The number of rows per page
20+
* @param respectPageSize - Whether to constrain by page size (default: true). Set to false for explicit user-requested limits.
2021
* @returns The limit to apply as a string for the query
2122
*/
2223
export function calculateEffectiveRowLimit(
2324
rowLimit: number | undefined,
2425
rowOffset: number,
2526
pageSize: number,
27+
respectPageSize: boolean = true,
2628
): string {
2729
if (rowLimit === undefined) {
2830
return pageSize.toString();
@@ -31,6 +33,11 @@ export function calculateEffectiveRowLimit(
3133
if (remainingRows <= 0) {
3234
return "0";
3335
}
36+
// When respectPageSize is false (e.g., for explicit user-requested limits like "Show more" button),
37+
// don't constrain by page size to allow fetching the full requested amount
38+
if (!respectPageSize) {
39+
return remainingRows.toString();
40+
}
3441
return Math.min(remainingRows, pageSize).toString();
3542
}
3643

web-common/src/features/dashboards/pivot/pivot-data-store.ts

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { getDimensionFilterWithSearch } from "@rilldata/web-common/features/dashboards/dimension-table/dimension-table-utils";
2-
import { calculateEffectiveRowLimit } from "@rilldata/web-common/features/dashboards/pivot/pivot-constants";
2+
import {
3+
calculateEffectiveRowLimit,
4+
MAX_ROW_EXPANSION_LIMIT,
5+
SHOW_MORE_BUTTON,
6+
} from "@rilldata/web-common/features/dashboards/pivot/pivot-constants";
37
import { mergeFilters } from "@rilldata/web-common/features/dashboards/pivot/pivot-merge-filters";
48
import { memoizeMetricsStore } from "@rilldata/web-common/features/dashboards/state-managers/memoize-metrics-store";
59
import type { StateManagers } from "@rilldata/web-common/features/dashboards/state-managers/state-managers";
@@ -299,13 +303,27 @@ export function createPivotDataStore(
299303
readable(null);
300304

301305
if (!isFlat) {
302-
// Calculate the effective limit based on rowLimit, offset, and page size
306+
// Use outermostRowLimit if set, otherwise fall back to rowLimit
307+
const effectiveOutermostLimit =
308+
config.pivot.outermostRowLimit ?? config.pivot.rowLimit;
309+
310+
// Calculate the effective limit based on outermostRowLimit, offset, and page size
311+
// When outermostRowLimit is explicitly set, don't constrain by page size
312+
const isExplicitOutermostLimit =
313+
config.pivot.outermostRowLimit !== undefined;
303314
const limitToApply = calculateEffectiveRowLimit(
304-
config.pivot.rowLimit,
315+
effectiveOutermostLimit,
305316
rowOffset,
306317
NUM_ROWS_PER_PAGE,
318+
!isExplicitOutermostLimit, // Don't respect page size for explicit outermost limit
307319
);
308320

321+
// Query for limit + 1 to detect if there's more data
322+
const limitToQuery =
323+
effectiveOutermostLimit !== undefined
324+
? (parseInt(limitToApply) + 1).toString()
325+
: limitToApply;
326+
309327
// Get sort order for the anchor dimension
310328
rowDimensionAxisQuery = getAxisForDimensions(
311329
ctx,
@@ -315,7 +333,7 @@ export function createPivotDataStore(
315333
whereFilter,
316334
sortPivotBy,
317335
timeRange,
318-
limitToApply,
336+
limitToQuery,
319337
rowOffset.toString(),
320338
);
321339
}
@@ -424,14 +442,36 @@ export function createPivotDataStore(
424442
globalTotalsResponse?.data?.data,
425443
);
426444

427-
const rowDimensionValues =
445+
let rowDimensionValues =
428446
rowDimensionAxes?.data?.[anchorDimension] || [];
429447

430-
const totalColumns = getTotalColumnCount(totalsRowData);
431-
432-
const axesRowTotals =
448+
let axesRowTotals =
433449
rowDimensionAxes?.totals?.[anchorDimension] || [];
434450

451+
// Detect if there's more data for the outermost dimension
452+
// and trim to the actual limit
453+
let hasMoreRows = false;
454+
const effectiveOutermostLimit =
455+
config.pivot.outermostRowLimit ?? config.pivot.rowLimit;
456+
if (!isFlat && effectiveOutermostLimit !== undefined) {
457+
const isExplicitOutermostLimit =
458+
config.pivot.outermostRowLimit !== undefined;
459+
const limitToApply = calculateEffectiveRowLimit(
460+
effectiveOutermostLimit,
461+
rowOffset,
462+
NUM_ROWS_PER_PAGE,
463+
!isExplicitOutermostLimit, // Don't respect page size for explicit outermost limit
464+
);
465+
const actualLimit = parseInt(limitToApply);
466+
if (rowDimensionValues.length > actualLimit) {
467+
hasMoreRows = true;
468+
rowDimensionValues = rowDimensionValues.slice(0, actualLimit);
469+
axesRowTotals = axesRowTotals.slice(0, actualLimit);
470+
}
471+
}
472+
473+
const totalColumns = getTotalColumnCount(totalsRowData);
474+
435475
const rowAxesQueryForMeasureTotals = getAxisQueryForMeasureTotals(
436476
ctx,
437477
config,
@@ -605,6 +645,22 @@ export function createPivotDataStore(
605645
expandedTableMap[key] = tableDataExpanded;
606646
}
607647

648+
// Add "Show more" row for outermost dimension if needed
649+
const effectiveOutermostLimit =
650+
config.pivot.outermostRowLimit ?? config.pivot.rowLimit;
651+
652+
if (
653+
hasMoreRows &&
654+
effectiveOutermostLimit &&
655+
effectiveOutermostLimit < MAX_ROW_EXPANSION_LIMIT
656+
) {
657+
const showMoreRow: PivotDataRow = {
658+
[anchorDimension]: SHOW_MORE_BUTTON,
659+
__currentLimit: effectiveOutermostLimit,
660+
} as PivotDataRow;
661+
tableDataExpanded = [...tableDataExpanded, showMoreRow];
662+
}
663+
608664
const activeCell = config.pivot.activeCell;
609665
let activeCellFilters: PivotFilter | undefined = undefined;
610666
if (activeCell) {

web-common/src/features/dashboards/pivot/pivot-utils.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ export function getPivotConfigKey(config: PivotDataStoreConfig) {
5454
pivot,
5555
} = config;
5656

57-
const { sorting, tableMode: tableModeKey, rowLimit } = pivot;
57+
const {
58+
sorting,
59+
tableMode: tableModeKey,
60+
rowLimit,
61+
outermostRowLimit,
62+
} = pivot;
5863
const timeKey = JSON.stringify(time);
5964
const sortingKey = JSON.stringify(sorting);
6065
const filterKey = JSON.stringify(whereFilter);
@@ -63,7 +68,7 @@ export function getPivotConfigKey(config: PivotDataStoreConfig) {
6368
.concat(measureNames, colDimensionNames)
6469
.join("_");
6570

66-
return `${dimsAndMeasures}_${timeKey}_${sortingKey}_${tableModeKey}_${filterKey}_${enableComparison}_${comparisonTimeKey}_${rowLimit ?? "all"}`;
71+
return `${dimsAndMeasures}_${timeKey}_${sortingKey}_${tableModeKey}_${filterKey}_${enableComparison}_${comparisonTimeKey}_${rowLimit ?? "all"}_${outermostRowLimit ?? "none"}`;
6772
}
6873

6974
/**

0 commit comments

Comments
 (0)