@lightdash/cli 3.89.0 → 3.91.0
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.
|
@@ -165,6 +165,13 @@ order, `sortBy` describes result ordering, `totalColumnCount` exposes truncation
|
|
|
165
165
|
`drillDown.open({ row, metric })` on selection. Either way Lightdash opens
|
|
166
166
|
its drill dialog. Distinct from `drill-down`, which is the full-app query
|
|
167
167
|
helper.
|
|
168
|
+
- `field-links`: result columns carry the semantic layer's `urls` link
|
|
169
|
+
patterns (`column.urls`), and `resolveColumnUrls({ column, row, columns,
|
|
170
|
+
format })` resolves them per cell. In every cell renderer — hand-written
|
|
171
|
+
tables and generic column loops such as underlying-data dialogs — render
|
|
172
|
+
the value as a link when it returns entries, styled visibly as a link
|
|
173
|
+
(underline and/or link color). Full rules in the data-app skill's
|
|
174
|
+
"Field links — `urls`" section.
|
|
168
175
|
- `url-state`: `useUrlState(...)` syncs a piece of app state into the page URL
|
|
169
176
|
so views can be shared and restored.
|
|
170
177
|
- `app-state`: `useAppState(key, default)` remembers a value per person;
|
|
@@ -130,6 +130,44 @@ A field's position in the YAML determines whether it goes in `.dimensions()` or
|
|
|
130
130
|
|
|
131
131
|
Use the **metric key name**, not the label. YAML `label: "Order Count"` → SDK field name is `order_count`.
|
|
132
132
|
|
|
133
|
+
### Field links — `urls`
|
|
134
|
+
|
|
135
|
+
A dimension or metric may declare `urls:` — link patterns for its values:
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
columns:
|
|
139
|
+
- name: account_number
|
|
140
|
+
meta:
|
|
141
|
+
dimension:
|
|
142
|
+
type: string
|
|
143
|
+
urls:
|
|
144
|
+
- label: Open account
|
|
145
|
+
url: "https://portal.example.com/accounts/${value.raw | url_encode }"
|
|
146
|
+
- label: Open owner
|
|
147
|
+
url: "https://portal.example.com/users/${row.accounts.owner_id.raw }"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**When a field you display declares `urls`, render its values as links built from those patterns** — in tables, underlying-data views, and anywhere the raw value is shown. Dashboards already do this; the app must match.
|
|
151
|
+
|
|
152
|
+
Every query result's `columns` carry the patterns too (`column.urls`), and the SDK resolves them per cell — prefer this over hand-rolling, especially in generic column loops:
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import { resolveColumnUrls } from '@lightdash/query-sdk';
|
|
156
|
+
|
|
157
|
+
const links = resolveColumnUrls({ column, row, columns, format });
|
|
158
|
+
// → [{ label, href }] with unresolvable patterns already skipped
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
When you hand-roll instead (e.g. a hard-coded table where you know the field), resolve placeholders with simple substitution:
|
|
162
|
+
|
|
163
|
+
- `${value.raw}` / `${value.formatted}` — the cell's own raw/formatted value.
|
|
164
|
+
- `${row.<model>.<field>.raw}` (or `.formatted`) — another field in the same result row. **Add that field to the query** so it's present in the row.
|
|
165
|
+
- A `| url_encode` filter means URL-encode the substituted value (`encodeURIComponent`).
|
|
166
|
+
|
|
167
|
+
One pattern → the cell is a plain link (open in a new tab). Several → a primary link plus a menu, or a small dropdown. Skip the link for null/empty values. Never invent patterns for fields without `urls`.
|
|
168
|
+
|
|
169
|
+
**Links must look like links at rest, not only on hover**: underline them (e.g. `underline underline-offset-4`) and/or use a distinct link color that fits the app's theme, plus a hover state. A viewer should spot the clickable cells without mousing over the table.
|
|
170
|
+
|
|
133
171
|
### Joined table fields — dot notation
|
|
134
172
|
|
|
135
173
|
When a model has `joins`, the joined table's dimensions and metrics are available in your query. **Use dot notation** (`table.field`) to reference fields from joined tables:
|
|
@@ -499,6 +537,27 @@ Rules:
|
|
|
499
537
|
- Whenever you show an underlying-data table/dialog, include a Download button in that table/dialog header. It should call `downloadUnderlyingData({ row, metric, fileType, values, limit, filename })`, track export state, and show a spinner or "Exporting..." label until the promise settles.
|
|
500
538
|
- For underlying-data downloads, `limit: 'table'` uses the backend default underlying-data row limit, `limit: 'all'` exports all matching rows allowed by backend export caps, and a number requests that many rows.
|
|
501
539
|
- This works for grouped SDK query rows. If you have heavily transformed or pivoted data client-side, keep the original source row around and pass that original row.
|
|
540
|
+
- **Render field links in the dialog's generic column loop.** Underlying-data columns carry `urls` (the field's link patterns), and `resolveColumnUrls` resolves them per cell — a cell with resolved links renders as a link (see [Field links — `urls`](#field-links--urls)):
|
|
541
|
+
|
|
542
|
+
```tsx
|
|
543
|
+
import { resolveColumnUrls } from '@lightdash/query-sdk';
|
|
544
|
+
|
|
545
|
+
{result.columns.map((c) => {
|
|
546
|
+
const links = resolveColumnUrls({ column: c, row: r, columns: result.columns, format: result.format });
|
|
547
|
+
return (
|
|
548
|
+
<TableCell key={c.name}>
|
|
549
|
+
{links.length > 0 ? (
|
|
550
|
+
<a href={links[0].href} target="_blank" rel="noreferrer"
|
|
551
|
+
className="text-primary underline underline-offset-4">
|
|
552
|
+
{result.format(r, c.name)}
|
|
553
|
+
</a>
|
|
554
|
+
) : (
|
|
555
|
+
result.format(r, c.name)
|
|
556
|
+
)}
|
|
557
|
+
</TableCell>
|
|
558
|
+
);
|
|
559
|
+
})}
|
|
560
|
+
```
|
|
502
561
|
|
|
503
562
|
```tsx
|
|
504
563
|
const revenueQuery = query('orders')
|
|
@@ -638,6 +697,8 @@ Use `formatField` for cells so dates render `Jun 16, 2025` instead of `2025-06-1
|
|
|
638
697
|
|
|
639
698
|
For the action-menu label and clipboard copy on a cell, the same helper applies — pass `format` so the per-field server format wins for currency/percent.
|
|
640
699
|
|
|
700
|
+
**Before writing any table or value display, check each displayed field's model YAML for a `urls:` block.** A field with `urls` MUST render its values as links, not plain text — see [Field links — `urls`](#field-links--urls). This applies to joined-table fields too: `customers.first_name` queried through `orders` is defined in `customers.yml`, so check the joined model's file (the index marks models whose fields carry links with `urls=…`). This is not optional polish: dashboards render these links, and an app that drops them loses functionality the user already relies on.
|
|
701
|
+
|
|
641
702
|
### Filters
|
|
642
703
|
|
|
643
704
|
Use `.filters([...])` for dimension/WHERE filters and `.metricFilters([...])`
|
|
@@ -1283,6 +1344,7 @@ The action-menu example above shows typical `drillDown()` usage. For the full AP
|
|
|
1283
1344
|
| Mistake | Why it breaks | Fix |
|
|
1284
1345
|
|---|---|---|
|
|
1285
1346
|
| Guessing field names | API returns opaque errors | Read the dbt YAML first — always |
|
|
1347
|
+
| Rendering a `urls` field's values as plain text | Dashboards render those values as links; the app silently drops functionality the user relies on | Check every displayed field's model YAML — including joined models (`customers.first_name` lives in `customers.yml`) — for `urls:` and render links per [Field links — `urls`](#field-links--urls) |
|
|
1286
1348
|
| `.metrics()` on a pre-aggregated model | Re-aggregates already-aggregated values → wrong numbers | If `wins` is a dimension in the YAML, use `.dimensions(['wins'])` |
|
|
1287
1349
|
| `.metrics(['max_cumulative_points'])` instead of `.dimensions(['cumulative_points'])` | Aggregates per-row data into a single value — collapses line charts | Check YAML: is it under `columns[].name` (dimension) or `meta.metrics` (metric)? |
|
|
1288
1350
|
| Unused dimensions in `.dimensions()` | Changes GROUP BY → wrong numbers | Only include dimensions you render or require for sorting; hidden sort fields stay selected but can be omitted from the UI |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightdash/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.91.0",
|
|
4
4
|
"description": "Lightdash CLI tool",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"@actions/core": "1.11.1",
|
|
23
23
|
"@aws-sdk/credential-providers": "3.995.0",
|
|
24
24
|
"@casl/ability": "6.8.0",
|
|
25
|
-
"@lightdash/common": "3.
|
|
26
|
-
"@lightdash/warehouses": "3.
|
|
25
|
+
"@lightdash/common": "3.91.0",
|
|
26
|
+
"@lightdash/warehouses": "3.91.0",
|
|
27
27
|
"@sidvind/better-ajv-errors": "7.0.0",
|
|
28
28
|
"@types/columnify": "1.5.1",
|
|
29
29
|
"ajv": "8.18.0",
|