@lightdash/query-sdk 3.90.0 → 3.92.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.
- package/dist/apiTransport.js +8 -0
- package/dist/columnUrls.d.ts +22 -0
- package/dist/columnUrls.js +88 -0
- package/dist/features.js +7 -0
- package/dist/generated/sdkVersion.d.ts +1 -1
- package/dist/generated/sdkVersion.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/types.d.ts +19 -0
- package/package.json +2 -2
package/dist/apiTransport.js
CHANGED
|
@@ -489,10 +489,18 @@ function mapApiRowsToQueryResult({ apiRows, columns, fields, fieldIds, fieldName
|
|
|
489
489
|
const name = idToName.get(fieldId) ?? fieldId;
|
|
490
490
|
const fieldMeta = fields[fieldId];
|
|
491
491
|
const colMeta = columns[fieldId];
|
|
492
|
+
const urls = Array.isArray(fieldMeta?.urls)
|
|
493
|
+
? fieldMeta.urls.filter((u) => typeof u === 'object' &&
|
|
494
|
+
u !== null &&
|
|
495
|
+
typeof u.label === 'string' &&
|
|
496
|
+
typeof u.url === 'string')
|
|
497
|
+
: [];
|
|
492
498
|
return {
|
|
493
499
|
name,
|
|
494
500
|
label: fieldMeta?.label ?? fieldMeta?.displayName ?? name,
|
|
495
501
|
type: mapColumnType(colMeta?.type ?? fieldMeta?.type ?? 'string'),
|
|
502
|
+
fieldId,
|
|
503
|
+
...(urls.length > 0 ? { urls } : {}),
|
|
496
504
|
};
|
|
497
505
|
});
|
|
498
506
|
const formattedCache = new Map();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Column, FormatFunction, Row } from './types';
|
|
2
|
+
export type ResolvedColumnUrl = {
|
|
3
|
+
label: string;
|
|
4
|
+
href: string;
|
|
5
|
+
};
|
|
6
|
+
type ResolveArgs = {
|
|
7
|
+
/** The column whose cell is being rendered. */
|
|
8
|
+
column: Column;
|
|
9
|
+
/** The result row the cell belongs to (SDK row, keyed by column name). */
|
|
10
|
+
row: Row;
|
|
11
|
+
/** All result columns — used to resolve `${row.<table>.<field>}` references. */
|
|
12
|
+
columns: Column[];
|
|
13
|
+
/** The result's format function, for `.formatted` references. */
|
|
14
|
+
format?: FormatFunction;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Build the links a cell offers from its column's `urls` patterns. Patterns
|
|
18
|
+
* whose references cannot be resolved against this row (missing field, null
|
|
19
|
+
* value, unknown filter) are skipped, matching dashboard behavior.
|
|
20
|
+
*/
|
|
21
|
+
export declare const resolveColumnUrls: (args: ResolveArgs) => ResolvedColumnUrl[];
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const TEMPLATE_RE = /\$\{([^}]+)\}/g;
|
|
2
|
+
/**
|
|
3
|
+
* Find the row key a `${row.<table>.<field>}` reference points at. Column
|
|
4
|
+
* names differ per result path (plain names, dot notation, or qualified ids
|
|
5
|
+
* in underlying-data results), so resolve through the column's `fieldId`
|
|
6
|
+
* (`<table>_<field>`), which preserves table identity everywhere. A dotted
|
|
7
|
+
* name match remains as a fallback for hand-built columns without a fieldId;
|
|
8
|
+
* a bare field name is never matched — the same name on another table would
|
|
9
|
+
* silently link the wrong record.
|
|
10
|
+
*/
|
|
11
|
+
const rowKeyForReference = (columns, table, field) => {
|
|
12
|
+
const fieldId = `${table}_${field}`;
|
|
13
|
+
const byFieldId = columns.find((c) => c.fieldId === fieldId);
|
|
14
|
+
if (byFieldId)
|
|
15
|
+
return byFieldId.name;
|
|
16
|
+
const dotted = `${table}.${field}`;
|
|
17
|
+
const byDottedName = columns.find((c) => c.fieldId === undefined && c.name === dotted);
|
|
18
|
+
return byDottedName ? byDottedName.name : null;
|
|
19
|
+
};
|
|
20
|
+
const applyFilters = (value, filters) => {
|
|
21
|
+
let out = value;
|
|
22
|
+
for (const filter of filters) {
|
|
23
|
+
if (filter === 'url_encode') {
|
|
24
|
+
out = encodeURIComponent(out);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Unknown filter — mirror the dashboard renderer's strict mode
|
|
28
|
+
// and drop the link rather than emit a wrong URL.
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Resolve one `${...}` expression against the row. Returns null when the
|
|
36
|
+
* reference is invalid, the referenced value is missing, or a filter is
|
|
37
|
+
* unknown — the caller then skips the whole pattern.
|
|
38
|
+
*/
|
|
39
|
+
const resolveExpression = (expression, { column, row, columns, format }) => {
|
|
40
|
+
const [ref = '', ...filters] = expression
|
|
41
|
+
.split('|')
|
|
42
|
+
.map((part) => part.trim());
|
|
43
|
+
const parts = ref.split('.').map((part) => part.trim());
|
|
44
|
+
let key = null;
|
|
45
|
+
let mode = null;
|
|
46
|
+
if (parts.length === 2 && parts[0] === 'value') {
|
|
47
|
+
key = column.name;
|
|
48
|
+
mode = parts[1] === 'raw' || parts[1] === 'formatted' ? parts[1] : null;
|
|
49
|
+
}
|
|
50
|
+
else if (parts.length === 4 && parts[0] === 'row') {
|
|
51
|
+
key = rowKeyForReference(columns, parts[1], parts[2]);
|
|
52
|
+
mode = parts[3] === 'raw' || parts[3] === 'formatted' ? parts[3] : null;
|
|
53
|
+
}
|
|
54
|
+
if (key === null || mode === null)
|
|
55
|
+
return null;
|
|
56
|
+
const raw = row[key];
|
|
57
|
+
if (raw === null || raw === undefined)
|
|
58
|
+
return null;
|
|
59
|
+
const value = mode === 'formatted' && format ? format(row, key) : String(raw);
|
|
60
|
+
return applyFilters(value, filters);
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Build the links a cell offers from its column's `urls` patterns. Patterns
|
|
64
|
+
* whose references cannot be resolved against this row (missing field, null
|
|
65
|
+
* value, unknown filter) are skipped, matching dashboard behavior.
|
|
66
|
+
*/
|
|
67
|
+
export const resolveColumnUrls = (args) => {
|
|
68
|
+
const urls = args.column.urls ?? [];
|
|
69
|
+
if (urls.length === 0)
|
|
70
|
+
return [];
|
|
71
|
+
if (args.row[args.column.name] === null)
|
|
72
|
+
return [];
|
|
73
|
+
const resolved = [];
|
|
74
|
+
for (const { label, url } of urls) {
|
|
75
|
+
let failed = false;
|
|
76
|
+
const href = url.replace(TEMPLATE_RE, (match, expression) => {
|
|
77
|
+
const substituted = resolveExpression(expression, args);
|
|
78
|
+
if (substituted === null) {
|
|
79
|
+
failed = true;
|
|
80
|
+
return match;
|
|
81
|
+
}
|
|
82
|
+
return substituted;
|
|
83
|
+
});
|
|
84
|
+
if (!failed)
|
|
85
|
+
resolved.push({ label, href });
|
|
86
|
+
}
|
|
87
|
+
return resolved;
|
|
88
|
+
};
|
package/dist/features.js
CHANGED
|
@@ -211,6 +211,13 @@ export const SDK_FEATURES = [
|
|
|
211
211
|
description: 'Reflows the layout for narrow and short tiles, such as a dashboard on a phone, so values stay readable and nothing scrolls sideways.',
|
|
212
212
|
wiring: 'Rework the layout to the "Fitting the frame" section of the reusable-visualization skill. A chart type built on an older template first needs the frame runtime added to its own files, as described under viz-responsive-layout in the sdk-features skill: the VizFrame marker in src/main.jsx and the html[data-viz-frame] rules in src/index.css. Then size type, padding and gaps in rem or Tailwind classes instead of px, make rows of items wrap with a minimum item width that keeps values on one line (capped just under half the frame), remove any scroll regions of the chart\'s own so only the frame scrolls, and make a title or table header row sticky.',
|
|
213
213
|
},
|
|
214
|
+
{
|
|
215
|
+
key: 'field-links',
|
|
216
|
+
appliesTo: ['data_app'],
|
|
217
|
+
label: 'Field links',
|
|
218
|
+
description: "Result columns carry the semantic layer's url link patterns, so values with configured links render as links, matching dashboards.",
|
|
219
|
+
wiring: 'In cell renderers (tables, underlying-data dialogs), call resolveColumnUrls({ column, row, columns, format }) and render the value as a link when it returns entries, styled visibly as a link.',
|
|
220
|
+
},
|
|
214
221
|
];
|
|
215
222
|
export const SDK_FEATURE_KEYS = SDK_FEATURES.map((f) => f.key);
|
|
216
223
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "3.
|
|
1
|
+
export declare const SDK_VERSION = "3.92.0";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by scripts/generateSdkVersion.mjs (prebuild) — do not edit.
|
|
2
|
-
export const SDK_VERSION = '3.
|
|
2
|
+
export const SDK_VERSION = '3.92.0';
|
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,9 @@ export { useLightdash } from './useLightdash';
|
|
|
6
6
|
export { LightdashProvider, useLightdashClient } from './LightdashProvider';
|
|
7
7
|
export { createApiTransport, LightdashApiError, type FetchAdapter, } from './apiTransport';
|
|
8
8
|
export { createPostMessageTransport } from './postMessageTransport';
|
|
9
|
+
export { resolveColumnUrls, type ResolvedColumnUrl } from './columnUrls';
|
|
9
10
|
export { SDK_FEATURES, SDK_FEATURE_KEYS, SDK_FIXES, SDK_FIX_KEYS, SDK_FEATURE_TARGETS, SDK_MANIFEST_MESSAGE_TYPE, type SdkFeature, type SdkFeatureTarget, type SdkFix, type SdkManifestMessage, } from './features';
|
|
10
|
-
export type { AdditionalMetric, AiPromptRequest, AiPromptResult, Column, ColumnType, CustomDimension, DownloadResultsFileType, DownloadResultsLimit, DownloadResultsOptions, DownloadResultsResult, DownloadResultsValues, DownloadUnderlyingDataOptions, ExternalFetchMethod, ExternalFetchOptions, ExternalFetchResult, Filter, FilterOperator, FilterValue, FormatFunction, LightdashClientConfig, LightdashUser, MetricType, QueryDefinition, QueryResult, Row, Sort, TableCalculation, Transport, UnitOfTime, UnderlyingDataOptions, UnderlyingDataResult, } from './types';
|
|
11
|
+
export type { AdditionalMetric, AiPromptRequest, AiPromptResult, Column, ColumnType, ColumnUrl, CustomDimension, DownloadResultsFileType, DownloadResultsLimit, DownloadResultsOptions, DownloadResultsResult, DownloadResultsValues, DownloadUnderlyingDataOptions, ExternalFetchMethod, ExternalFetchOptions, ExternalFetchResult, Filter, FilterOperator, FilterValue, FormatFunction, LightdashClientConfig, LightdashUser, MetricType, QueryDefinition, QueryResult, Row, Sort, TableCalculation, Transport, UnitOfTime, UnderlyingDataOptions, UnderlyingDataResult, } from './types';
|
|
11
12
|
export type { SdkExternalFetchRequest, SdkExternalFetchResponse, SdkFetchRequest, SdkFetchResponse, SdkReadyMessage, SdkScreenshotAvailableMessage, SdkScreenshotRequest, SdkScreenshotResponse, SdkGsheetExportRequest, SdkGsheetExportResponse, SdkGsheetExportColumn, SdkGsheetExportColumnType, SdkGsheetExportRow, } from './postMessageTransport';
|
|
12
13
|
export type { InspectAvailableMessage, InspectSelectedMessage, } from './inspector';
|
|
13
14
|
export { useDelivery } from './delivery';
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export { LightdashProvider, useLightdashClient } from './LightdashProvider';
|
|
|
12
12
|
// Transports
|
|
13
13
|
export { createApiTransport, LightdashApiError, } from './apiTransport';
|
|
14
14
|
export { createPostMessageTransport } from './postMessageTransport';
|
|
15
|
+
export { resolveColumnUrls } from './columnUrls';
|
|
15
16
|
// Feature manifest (also exported via the "./features" subpath for hosts)
|
|
16
17
|
export { SDK_FEATURES, SDK_FEATURE_KEYS, SDK_FIXES, SDK_FIX_KEYS, SDK_FEATURE_TARGETS, SDK_MANIFEST_MESSAGE_TYPE, } from './features';
|
|
17
18
|
// Scheduled-delivery declarations (data apps)
|
package/dist/types.d.ts
CHANGED
|
@@ -94,10 +94,29 @@ export type QueryDefinition = {
|
|
|
94
94
|
label?: string;
|
|
95
95
|
};
|
|
96
96
|
export type ColumnType = 'string' | 'number' | 'date' | 'timestamp' | 'boolean';
|
|
97
|
+
/**
|
|
98
|
+
* A link pattern declared on the field in the semantic layer (`urls:` in the
|
|
99
|
+
* model YAML). `url` is a template: `${value.raw}` / `${value.formatted}` is
|
|
100
|
+
* the cell's own value, `${row.<table>.<field>.raw}` (or `.formatted`)
|
|
101
|
+
* references another field in the same result row, and a `| url_encode`
|
|
102
|
+
* filter URL-encodes the substituted value. Resolve with `resolveColumnUrls`.
|
|
103
|
+
*/
|
|
104
|
+
export type ColumnUrl = {
|
|
105
|
+
label: string;
|
|
106
|
+
url: string;
|
|
107
|
+
};
|
|
97
108
|
export type Column = {
|
|
98
109
|
name: string;
|
|
99
110
|
label: string;
|
|
100
111
|
type: ColumnType;
|
|
112
|
+
/**
|
|
113
|
+
* The API field id (`<table>_<field>`), preserved across result paths so
|
|
114
|
+
* `${row.<table>.<field>}` url references resolve to the right column
|
|
115
|
+
* even where names are qualified differently (underlying data, joins).
|
|
116
|
+
*/
|
|
117
|
+
fieldId?: string;
|
|
118
|
+
/** Link patterns for this field's values; render cells as links when set. */
|
|
119
|
+
urls?: ColumnUrl[];
|
|
101
120
|
};
|
|
102
121
|
export type Row = Record<string, string | number | boolean | null>;
|
|
103
122
|
export type FormatFunction = (row: Row, fieldId: string) => string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightdash/query-sdk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.92.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "SDK for building custom data apps against the Lightdash semantic layer",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@lightdash/common": "3.
|
|
29
|
+
"@lightdash/common": "3.92.0",
|
|
30
30
|
"@types/node": "22.13.1",
|
|
31
31
|
"@types/react": "19.3.0",
|
|
32
32
|
"@types/react-dom": "19.3.0",
|