@lightdash/cli 1.201.0 → 1.202.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,8 +27,15 @@ fetch anything yourself; the only host interaction is through the helpers the ho
27
27
  returns.
28
28
 
29
29
  ```tsx
30
- const { fieldMapping, rows, options, colorPalette, ready, underlyingData } =
31
- useVizContext();
30
+ const {
31
+ fieldMapping,
32
+ rows,
33
+ options,
34
+ colorPalette,
35
+ pivotDetails,
36
+ ready,
37
+ underlyingData,
38
+ } = useVizContext();
32
39
  ```
33
40
 
34
41
  - `fieldMapping` — `Record<string, string>`: the field name you declared → the query field
@@ -39,6 +46,8 @@ const { fieldMapping, rows, options, colorPalette, ready, underlyingData } =
39
46
  option you declared (the viewer's choice, else your declared `default`).
40
47
  - `colorPalette` — `string[]`: the Lightdash palette resolved for this chart. Always pushed,
41
48
  whether or not you declared `colorPalette`. Empty only when the host resolved none.
49
+ - `pivotDetails` — the complete backend-pivot layout, or `null` for ordinary rows. See
50
+ "Backend-pivoted results" below.
42
51
  - `ready` — false until the first context arrives.
43
52
  - `underlyingData` — host-mediated access to the raw rows behind a clicked data point.
44
53
  See "Data-point actions" below.
@@ -81,6 +90,69 @@ palette, delivered differently. An app imports `CHART_COLORS`; a viz reads the r
81
90
  colours off the hook, because the viewer picks the palette per chart. In a viz, use the
82
91
  hook, not `CHART_COLORS`.
83
92
 
93
+ ## Backend-pivoted results
94
+
95
+ A mapped `series` field makes Lightdash pivot the results before they reach the viz. In
96
+ that case the mapped metric id is no longer a row key: each series becomes a generated
97
+ column described by `pivotDetails.valuesColumns`.
98
+
99
+ Match `valuesColumns` whose `referenceField` equals the mapped metric id. For each match,
100
+ use `pivotValues` to identify and label the mapped series value. Generated
101
+ `pivotColumnName` keys contain the same `VizContextCell` objects as ordinary field keys:
102
+ read them with `getRaw(row, column.pivotColumnName)` or
103
+ `getFormatted(row, column.pivotColumnName)`. Never coerce `row[fieldId]` directly with
104
+ `String`, `Number`, or template interpolation; that coerces the cell object rather than
105
+ its value. Preserve the ordinary `fieldMapping` row path when `pivotDetails` is `null`, so
106
+ the same viz works without a mapped series and on older unpivoted charts.
107
+
108
+ The rest of `pivotDetails` describes the full layout rather than assuming the viz is a
109
+ Cartesian chart:
110
+
111
+ - `indexColumn` — row-grain fields and their `time`/`category` axis semantics.
112
+ - `groupByColumns` — pivot-header fields in backend layout order.
113
+ - `originalColumns` — original field ids and semantic types before pivoting.
114
+ - `sortBy` — the sort applied to the pivoted result, including anchored pivot values.
115
+ - `totalColumnCount` — the untruncated pivot column count; use it when the viz needs to
116
+ explain that the returned columns hit a limit.
117
+ - `passthroughDimensions` — hidden dimensions retained on rows for cross-field rendering.
118
+
119
+ Use these when the visualization's shape benefits from them: a table can build row and
120
+ column headers, while a chart can select a time axis from metadata instead of guessing
121
+ from values. Treat `fieldMapping` as the declared interface; metadata describes how those
122
+ fields were laid out, not permission to render unrelated query fields automatically.
123
+
124
+ ```tsx
125
+ const metricId = fieldMapping['value'];
126
+ const seriesId = fieldMapping['series'];
127
+ const pivotedMetrics =
128
+ pivotDetails?.valuesColumns.filter(
129
+ (column) => column.referenceField === metricId,
130
+ ) ?? [];
131
+
132
+ const series = pivotedMetrics.map((column) => ({
133
+ columnId: column.pivotColumnName,
134
+ label:
135
+ column.pivotValues.find((value) => value.referenceField === seriesId)
136
+ ?.formatted ?? 'Unknown',
137
+ }));
138
+
139
+ const categoryId = fieldMapping['category'];
140
+ const data = rows.map((row) => ({
141
+ label: getFormatted(row, categoryId),
142
+ ...Object.fromEntries(
143
+ series.map(({ columnId }) => [
144
+ columnId,
145
+ Number(getRaw(row, columnId) ?? 0),
146
+ ]),
147
+ ),
148
+ }));
149
+ ```
150
+
151
+ Use the order of `valuesColumns` for stable colour assignment. A chart with multiple
152
+ declared series fields builds its label from each matching `pivotValues` entry in declared
153
+ field order. Backend-pivoted rows do not have safe one-source-row provenance, so the host
154
+ sets `underlyingData.enabled` to false for them.
155
+
84
156
  ## Data-point actions: underlying data
85
157
 
86
158
  When `underlyingData.enabled` is true, viewers expect the standard Lightdash action on
@@ -25,6 +25,7 @@ Users describe features by what they see in the Lightdash editor. Translate:
25
25
  | "delivery has all tabs", full data in scheduled deliveries | `delivery-render` | app code opt-in |
26
26
  | external API data | `external-fetch` | app code opt-in |
27
27
  | runs inside a dashboard tile | `viz-context` | required — see below |
28
+ | reusable chart/table with pivoted results | `viz-pivoted-results` | required — see below |
28
29
  | "view underlying data", raw rows behind a point (viz only) | `viz-underlying-data` | app code opt-in |
29
30
  | light/dark mode, "matches my Lightdash theme" | `follow-host-theme` | CSS tokens — see below |
30
31
 
@@ -83,6 +84,20 @@ For colours CSS can't reach (a chart library's theme object, a logo swap), read
83
84
  the mode: `const colorScheme = useColorScheme();` — `'light' | 'dark'`,
84
85
  re-rendering on every host toggle.
85
86
 
87
+ ### `viz-pivoted-results` — reusable visualization pivots
88
+
89
+ Read `pivotDetails` from `useVizContext()`. When it is non-null, match
90
+ `pivotDetails.valuesColumns` to the mapped metric by `referenceField`, derive series
91
+ labels from `pivotValues`, and read each generated `pivotColumnName` with
92
+ `getRaw(row, pivotColumnName)` or `getFormatted(row, pivotColumnName)`. Generated and
93
+ ordinary row keys both contain `VizContextCell` objects; never coerce `row[fieldId]`
94
+ directly. Use the remaining metadata for the visualization's actual shape: `indexColumn` and
95
+ `originalColumns` provide row-grain/type semantics, `groupByColumns` provides header
96
+ order, `sortBy` describes result ordering, `totalColumnCount` exposes truncation, and
97
+ `passthroughDimensions` identifies hidden fields retained on rows. Preserve the ordinary
98
+ `fieldMapping` path when `pivotDetails` is null. The full contract is in the
99
+ `reusable-visualization` skill.
100
+
86
101
  ### App-code opt-ins (call the API where it fits the app)
87
102
 
88
103
  - `drill-down`: `drillDown(...)` derives a more detailed query from a clicked
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "1.201.0",
3
+ "version": "1.202.2",
4
4
  "description": "Lightdash CLI tool",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -45,8 +45,8 @@
45
45
  "unique-names-generator": "4.7.1",
46
46
  "uuid": "11.1.1",
47
47
  "yaml": "2.8.3",
48
- "@lightdash/common": "1.201.0",
49
- "@lightdash/warehouses": "1.201.0"
48
+ "@lightdash/common": "1.202.2",
49
+ "@lightdash/warehouses": "1.202.2"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/inquirer": "8.2.4",