diff --git a/web-common/src/features/dashboards/pivot/PivotDimensionCell.svelte b/web-common/src/features/dashboards/pivot/PivotDimensionCell.svelte new file mode 100644 index 00000000000..0457612e71e --- /dev/null +++ b/web-common/src/features/dashboards/pivot/PivotDimensionCell.svelte @@ -0,0 +1,34 @@ + + +
+ {value ?? "null"} + e.stopPropagation()} + > + + +
+ + diff --git a/web-common/src/features/dashboards/pivot/pivot-column-definition.ts b/web-common/src/features/dashboards/pivot/pivot-column-definition.ts index 05cbe02559b..623143556c5 100644 --- a/web-common/src/features/dashboards/pivot/pivot-column-definition.ts +++ b/web-common/src/features/dashboards/pivot/pivot-column-definition.ts @@ -1,6 +1,10 @@ import PercentageChange from "@rilldata/web-common/components/data-types/PercentageChange.svelte"; import DeltaChange from "@rilldata/web-common/features/dashboards/dimension-table/DeltaChange.svelte"; import DeltaChangePercentage from "@rilldata/web-common/features/dashboards/dimension-table/DeltaChangePercentage.svelte"; +import { + URI_DIMENSION_SUFFIX, + makeHref, +} from "@rilldata/web-common/features/dashboards/leaderboard/leaderboard-utils"; import { getNextLimitLabel, LOADING_CELL, @@ -15,6 +19,7 @@ import type { ColumnDef } from "tanstack-table-8-svelte-5"; import { timeFormat } from "d3-time-format"; import type { ComponentType, SvelteComponent } from "svelte"; import PivotDeltaCell from "./PivotDeltaCell.svelte"; +import PivotDimensionCell from "./PivotDimensionCell.svelte"; import PivotExpandableCell from "./PivotExpandableCell.svelte"; import PivotMeasureCell from "./PivotMeasureCell.svelte"; import PivotShowMoreCell from "./PivotShowMoreCell.svelte"; @@ -317,17 +322,32 @@ function getFlatColumnDef( ): ColumnDef[] { const rowDefinitions: ColumnDef[] = rowDimensions.map( (d, i) => { + const dimSpec = config.allDimensions.find( + (dim) => dim.name === d.name || dim.column === d.name, + ); + const uriField = + dimSpec?.uri && dimSpec.name + ? dimSpec.name + URI_DIMENSION_SUFFIX + : undefined; + return { id: d.name, accessorFn: (row) => row[d.name], header: d.label || d.name, - cell: ({ getValue }) => { + cell: ({ row, getValue }) => { const value = formatDimensionValue( getValue() as string, i, config.time, rowDimensionNames, ); + if (uriField) { + const uri = row.original[uriField] as string | null | undefined; + const href = makeHref(uri ?? null, (value as string) ?? ""); + if (href) { + return cellComponent(PivotDimensionCell, { value, href }); + } + } if (value === null) return "null"; return value; }, diff --git a/web-common/src/features/dashboards/pivot/pivot-data-store.ts b/web-common/src/features/dashboards/pivot/pivot-data-store.ts index 0bf8ecbf437..34c6c624eb6 100644 --- a/web-common/src/features/dashboards/pivot/pivot-data-store.ts +++ b/web-common/src/features/dashboards/pivot/pivot-data-store.ts @@ -1,4 +1,5 @@ import type { ConnectError } from "@connectrpc/connect"; +import { getURIRequestMeasure } from "@rilldata/web-common/features/dashboards/dashboard-utils"; import { getDimensionFilterWithSearch } from "@rilldata/web-common/features/dashboards/dimension-table/dimension-table-utils"; import { calculateEffectiveRowLimit, @@ -12,6 +13,7 @@ import { createAndExpression } from "@rilldata/web-common/features/dashboards/st import type { TimeRangeString } from "@rilldata/web-common/lib/time/types"; import type { V1Expression, + V1MetricsViewAggregationMeasure, V1MetricsViewAggregationResponse, V1MetricsViewAggregationSort, } from "@rilldata/web-common/runtime-client"; @@ -113,7 +115,22 @@ export function createTableCellQuery( }; } else return { name: dimension }; }); - const measureBody = measureNames.map((m) => ({ name: m })); + const measureBody: V1MetricsViewAggregationMeasure[] = measureNames.map( + (m) => ({ name: m }), + ); + + // Request computed URI measures for flat-mode row dimensions that define a + // uri template, so dimension cells can render as links (matching leaderboard). + if (isFlat) { + for (const dimensionName of rowDimensionNames) { + const dimSpec = config.allDimensions.find( + (d) => d.name === dimensionName || d.column === dimensionName, + ); + if (dimSpec?.uri && dimSpec.name) { + measureBody.push(getURIRequestMeasure(dimSpec.name)); + } + } + } const { filters: filterForInitialTable, timeFilters } = getFilterForPivotTable(