@lightdash/cli 1.143.0 → 1.144.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.
@@ -21,11 +21,14 @@ instead stays frozen until somebody regenerates the whole viz.
21
21
 
22
22
  ## The hook
23
23
 
24
- `useVizContext()` from `@lightdash/query-sdk` is the only source of data and settings. Do
25
- not add a message listener and do not fetch anything.
24
+ `useVizContext()` from `@lightdash/query-sdk` is the only channel to the host — data,
25
+ settings, and host actions all come from it. Do not add a message listener and do not
26
+ fetch anything yourself; the only host interaction is through the helpers the hook
27
+ returns.
26
28
 
27
29
  ```tsx
28
- const { fieldMapping, rows, options, colorPalette, ready } = useVizContext();
30
+ const { fieldMapping, rows, options, colorPalette, ready, underlyingData } =
31
+ useVizContext();
29
32
  ```
30
33
 
31
34
  - `fieldMapping` — `Record<string, string>`: the field name you declared → the query field
@@ -37,9 +40,11 @@ const { fieldMapping, rows, options, colorPalette, ready } = useVizContext();
37
40
  - `colorPalette` — `string[]`: the Lightdash palette resolved for this chart. Always pushed,
38
41
  whether or not you declared `colorPalette`. Empty only when the host resolved none.
39
42
  - `ready` — false until the first context arrives.
43
+ - `underlyingData` — host-mediated access to the raw rows behind a clicked data point.
44
+ See "Data-point actions" below.
40
45
 
41
- Read all five. Ignoring `options` and `colorPalette` is the most common way to build a viz
42
- nobody can configure.
46
+ Read all of them. Ignoring `options` and `colorPalette` is the most common way to build a
47
+ viz nobody can configure.
43
48
 
44
49
  ### These app-level APIs do not apply to a viz
45
50
 
@@ -76,6 +81,48 @@ palette, delivered differently. An app imports `CHART_COLORS`; a viz reads the r
76
81
  colours off the hook, because the viewer picks the palette per chart. In a viz, use the
77
82
  hook, not `CHART_COLORS`.
78
83
 
84
+ ## Data-point actions: underlying data
85
+
86
+ When `underlyingData.enabled` is true, viewers expect the standard Lightdash action on
87
+ chart marks: click a data point → small action menu → "View underlying data" → a dialog
88
+ listing the raw rows behind that point, with a Download button. When it is false (host
89
+ too old, viewer lacks permission, embed), render no menu item — never a disabled one.
90
+
91
+ Provenance is the contract: **every interactive datum keeps a reference to its
92
+ untransformed source row.** When mapping `rows` into chart data, carry the row:
93
+
94
+ ```tsx
95
+ const data = rows.map((row) => ({
96
+ label: getFormatted(row, catField),
97
+ value: Number(getRaw(row, valField) ?? 0),
98
+ sourceRow: row, // ← required for underlying data
99
+ }));
100
+ ```
101
+
102
+ Only attach the action where one mark maps to exactly ONE source row and ONE metric-slot
103
+ field. A mark that aggregates several rows (a binned bucket, a "top N + other" slice)
104
+ gets no underlying-data item.
105
+
106
+ On click, fetch and render in a dialog themed like the rest of the viz:
107
+
108
+ ```tsx
109
+ const result = await underlyingData.get({ row: datum.sourceRow, metric: 'value' });
110
+ // result.rows / result.columns / result.format — render as a table
111
+ // Download button:
112
+ // await underlyingData.download({ row: datum.sourceRow, metric: 'value', fileType: 'csv' });
113
+ ```
114
+
115
+ `metric` is the declared field NAME from your `fields` (the same key you read from
116
+ `fieldMapping`), not a query field id. Show `get()`/`download()` rejection messages in
117
+ the dialog — they are written for viewers.
118
+
119
+ Keep the dialog table dense — underlying data is often wide and long. Compact cell
120
+ padding (the table is for scanning, not presenting). If the header is sticky: pin it
121
+ flush at `top: 0` with an opaque background, and put NO padding on the scroll
122
+ container itself — pad the cells, not the scroller. A sticky header pins to the
123
+ container's content edge, so any container padding becomes a strip that rows
124
+ visibly scroll through above the header.
125
+
79
126
  ## The declaration
80
127
 
81
128
  Alongside the component you emit one structured declaration — as **structured output, not a
@@ -206,3 +253,6 @@ chart.
206
253
  Then check both directions: every key you read from `options` is declared, and every option
207
254
  you declared is read somewhere. `colorPalette` is declared when you colour from
208
255
  `colorPalette` — it is never read from `options`.
256
+
257
+ Finally, if the chart has clickable marks: each interactive datum carries `sourceRow`,
258
+ and the data-point action menu is gated on `underlyingData.enabled`.
@@ -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
+ | "view underlying data", raw rows behind a point (viz only) | `viz-underlying-data` | app code opt-in |
28
29
  | light/dark mode, "matches my Lightdash theme" | `follow-host-theme` | CSS tokens — see below |
29
30
 
30
31
  ## Automatic (zero wiring — active on any current-SDK bundle)
@@ -98,6 +99,12 @@ re-rendering on every host toggle.
98
99
  every tab's queries execute during capture while only the active tab stays
99
100
  visible — never mount all tabs unconditionally (interactive loads must stay
100
101
  lazy).
102
+ - `viz-underlying-data` (vizs only): keep the untransformed `sourceRow` on each
103
+ interactive datum, gate a data-point action menu on
104
+ `useVizContext().underlyingData.enabled`, render
105
+ `underlyingData.get({ row, metric })` in a themed dialog, and wire its
106
+ Download button to `underlyingData.download`. Full contract in the
107
+ `reusable-visualization` skill.
101
108
 
102
109
  ## After a template upgrade
103
110
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "1.143.0",
3
+ "version": "1.144.2",
4
4
  "description": "Lightdash CLI tool",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,8 +42,8 @@
42
42
  "unique-names-generator": "4.7.1",
43
43
  "uuid": "11.1.1",
44
44
  "yaml": "2.8.3",
45
- "@lightdash/common": "1.143.0",
46
- "@lightdash/warehouses": "1.143.0"
45
+ "@lightdash/common": "1.144.2",
46
+ "@lightdash/warehouses": "1.144.2"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/inquirer": "8.2.4",