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 @@
+
+
+
+
+
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(