@inkindcards/semantic-layer 2.2.6 → 2.3.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/components.cjs +269 -133
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +35 -4
- package/dist/components.d.ts +35 -4
- package/dist/components.js +268 -134
- package/dist/components.js.map +1 -1
- package/package.json +1 -1
package/dist/components.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { S as SemanticField, d as FieldType, Q as QueryResult } from './types-c5qj4BKB.cjs';
|
|
2
|
+
import { S as SemanticField, d as FieldType, Q as QueryResult, T as TimeGrain } from './types-c5qj4BKB.cjs';
|
|
3
3
|
import React__default from 'react';
|
|
4
4
|
|
|
5
5
|
interface MetricPickerProps {
|
|
@@ -84,20 +84,51 @@ interface FieldMatch {
|
|
|
84
84
|
suggestedField: SemanticField | null;
|
|
85
85
|
confidence: MatchConfidence;
|
|
86
86
|
}
|
|
87
|
+
interface ChartAnalysis {
|
|
88
|
+
dimensionColumns: string[];
|
|
89
|
+
metricColumns: string[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Best-effort match of a single column name against the catalog.
|
|
93
|
+
*/
|
|
94
|
+
declare function matchField(column: string, catalog: SemanticField[]): {
|
|
95
|
+
field: SemanticField | null;
|
|
96
|
+
confidence: MatchConfidence;
|
|
97
|
+
};
|
|
87
98
|
/**
|
|
88
99
|
* Match an array of column names against the semantic layer field catalog.
|
|
89
100
|
* Uses three layers: exact name match, normalized match, then display name match.
|
|
90
101
|
*/
|
|
91
102
|
declare function matchFields(columns: string[], catalog: SemanticField[]): FieldMatch[];
|
|
103
|
+
/**
|
|
104
|
+
* Analyze chart data to classify columns as dimensions (string/date values)
|
|
105
|
+
* or metrics (numeric values). Used by the inspector modal to build the
|
|
106
|
+
* query builder UI instead of a flat column-to-field mapping.
|
|
107
|
+
*/
|
|
108
|
+
declare function analyzeChartData(columns: string[], sampleValues: Record<string, unknown>[]): ChartAnalysis;
|
|
92
109
|
|
|
93
110
|
interface FieldMapping {
|
|
94
111
|
column: string;
|
|
95
112
|
field: SemanticField | null;
|
|
96
113
|
}
|
|
114
|
+
interface DimensionMapping {
|
|
115
|
+
column: string;
|
|
116
|
+
field: SemanticField;
|
|
117
|
+
}
|
|
118
|
+
interface MigrationConfig {
|
|
119
|
+
componentLabel: string;
|
|
120
|
+
dimensions: DimensionMapping[];
|
|
121
|
+
metrics: SemanticField[];
|
|
122
|
+
grain: TimeGrain | null;
|
|
123
|
+
originalMetricColumns: string[];
|
|
124
|
+
}
|
|
97
125
|
/**
|
|
98
126
|
* Generate a ready-to-paste Lovable prompt that tells the AI how to migrate
|
|
99
|
-
* a component from
|
|
127
|
+
* a component from hardcoded data to a useSemanticQuery() call.
|
|
128
|
+
*
|
|
129
|
+
* Understands the distinction between dimensions (groupBy) and metrics (values),
|
|
130
|
+
* and produces correct query config with data reshaping instructions.
|
|
100
131
|
*/
|
|
101
|
-
declare function generateMigrationPrompt(
|
|
132
|
+
declare function generateMigrationPrompt(config: MigrationConfig): string;
|
|
102
133
|
|
|
103
|
-
export { AdminDashboard, type AdminDashboardProps, DataCatalog, type DataCatalogProps, DataInspector, type DataInspectorProps, type FieldMapping, type FieldMatch, Inspectable, type InspectableProps, type MatchConfidence, MetricPicker, type MetricPickerProps, ResultsTable, type ResultsTableProps, generateMigrationPrompt, matchFields };
|
|
134
|
+
export { AdminDashboard, type AdminDashboardProps, type ChartAnalysis, DataCatalog, type DataCatalogProps, DataInspector, type DataInspectorProps, type DimensionMapping, type FieldMapping, type FieldMatch, Inspectable, type InspectableProps, type MatchConfidence, MetricPicker, type MetricPickerProps, type MigrationConfig, ResultsTable, type ResultsTableProps, analyzeChartData, generateMigrationPrompt, matchField, matchFields };
|
package/dist/components.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { S as SemanticField, d as FieldType, Q as QueryResult } from './types-c5qj4BKB.js';
|
|
2
|
+
import { S as SemanticField, d as FieldType, Q as QueryResult, T as TimeGrain } from './types-c5qj4BKB.js';
|
|
3
3
|
import React__default from 'react';
|
|
4
4
|
|
|
5
5
|
interface MetricPickerProps {
|
|
@@ -84,20 +84,51 @@ interface FieldMatch {
|
|
|
84
84
|
suggestedField: SemanticField | null;
|
|
85
85
|
confidence: MatchConfidence;
|
|
86
86
|
}
|
|
87
|
+
interface ChartAnalysis {
|
|
88
|
+
dimensionColumns: string[];
|
|
89
|
+
metricColumns: string[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Best-effort match of a single column name against the catalog.
|
|
93
|
+
*/
|
|
94
|
+
declare function matchField(column: string, catalog: SemanticField[]): {
|
|
95
|
+
field: SemanticField | null;
|
|
96
|
+
confidence: MatchConfidence;
|
|
97
|
+
};
|
|
87
98
|
/**
|
|
88
99
|
* Match an array of column names against the semantic layer field catalog.
|
|
89
100
|
* Uses three layers: exact name match, normalized match, then display name match.
|
|
90
101
|
*/
|
|
91
102
|
declare function matchFields(columns: string[], catalog: SemanticField[]): FieldMatch[];
|
|
103
|
+
/**
|
|
104
|
+
* Analyze chart data to classify columns as dimensions (string/date values)
|
|
105
|
+
* or metrics (numeric values). Used by the inspector modal to build the
|
|
106
|
+
* query builder UI instead of a flat column-to-field mapping.
|
|
107
|
+
*/
|
|
108
|
+
declare function analyzeChartData(columns: string[], sampleValues: Record<string, unknown>[]): ChartAnalysis;
|
|
92
109
|
|
|
93
110
|
interface FieldMapping {
|
|
94
111
|
column: string;
|
|
95
112
|
field: SemanticField | null;
|
|
96
113
|
}
|
|
114
|
+
interface DimensionMapping {
|
|
115
|
+
column: string;
|
|
116
|
+
field: SemanticField;
|
|
117
|
+
}
|
|
118
|
+
interface MigrationConfig {
|
|
119
|
+
componentLabel: string;
|
|
120
|
+
dimensions: DimensionMapping[];
|
|
121
|
+
metrics: SemanticField[];
|
|
122
|
+
grain: TimeGrain | null;
|
|
123
|
+
originalMetricColumns: string[];
|
|
124
|
+
}
|
|
97
125
|
/**
|
|
98
126
|
* Generate a ready-to-paste Lovable prompt that tells the AI how to migrate
|
|
99
|
-
* a component from
|
|
127
|
+
* a component from hardcoded data to a useSemanticQuery() call.
|
|
128
|
+
*
|
|
129
|
+
* Understands the distinction between dimensions (groupBy) and metrics (values),
|
|
130
|
+
* and produces correct query config with data reshaping instructions.
|
|
100
131
|
*/
|
|
101
|
-
declare function generateMigrationPrompt(
|
|
132
|
+
declare function generateMigrationPrompt(config: MigrationConfig): string;
|
|
102
133
|
|
|
103
|
-
export { AdminDashboard, type AdminDashboardProps, DataCatalog, type DataCatalogProps, DataInspector, type DataInspectorProps, type FieldMapping, type FieldMatch, Inspectable, type InspectableProps, type MatchConfidence, MetricPicker, type MetricPickerProps, ResultsTable, type ResultsTableProps, generateMigrationPrompt, matchFields };
|
|
134
|
+
export { AdminDashboard, type AdminDashboardProps, type ChartAnalysis, DataCatalog, type DataCatalogProps, DataInspector, type DataInspectorProps, type DimensionMapping, type FieldMapping, type FieldMatch, Inspectable, type InspectableProps, type MatchConfidence, MetricPicker, type MetricPickerProps, type MigrationConfig, ResultsTable, type ResultsTableProps, analyzeChartData, generateMigrationPrompt, matchField, matchFields };
|
package/dist/components.js
CHANGED
|
@@ -996,48 +996,83 @@ function matchDisplayName(column, catalog) {
|
|
|
996
996
|
if (lower.length < 3) return null;
|
|
997
997
|
return catalog.find((f) => f.displayName.toLowerCase().includes(lower)) ?? catalog.find((f) => f.description.toLowerCase().includes(lower)) ?? null;
|
|
998
998
|
}
|
|
999
|
+
function matchField(column, catalog) {
|
|
1000
|
+
const exact = matchExact(column, catalog);
|
|
1001
|
+
if (exact) return { field: exact, confidence: "exact" };
|
|
1002
|
+
const normalized = matchNormalized(column, catalog);
|
|
1003
|
+
if (normalized) return { field: normalized, confidence: "fuzzy" };
|
|
1004
|
+
const display = matchDisplayName(column, catalog);
|
|
1005
|
+
if (display) return { field: display, confidence: "fuzzy" };
|
|
1006
|
+
return { field: null, confidence: "manual" };
|
|
1007
|
+
}
|
|
999
1008
|
function matchFields(columns, catalog) {
|
|
1000
1009
|
return columns.map((column) => {
|
|
1001
|
-
const
|
|
1002
|
-
|
|
1003
|
-
const normalized = matchNormalized(column, catalog);
|
|
1004
|
-
if (normalized) return { column, suggestedField: normalized, confidence: "fuzzy" };
|
|
1005
|
-
const display = matchDisplayName(column, catalog);
|
|
1006
|
-
if (display) return { column, suggestedField: display, confidence: "fuzzy" };
|
|
1007
|
-
return { column, suggestedField: null, confidence: "manual" };
|
|
1010
|
+
const { field, confidence } = matchField(column, catalog);
|
|
1011
|
+
return { column, suggestedField: field, confidence };
|
|
1008
1012
|
});
|
|
1009
1013
|
}
|
|
1014
|
+
function analyzeChartData(columns, sampleValues) {
|
|
1015
|
+
const dimensionColumns = [];
|
|
1016
|
+
const metricColumns = [];
|
|
1017
|
+
for (const col of columns) {
|
|
1018
|
+
const values = sampleValues.map((row) => row[col]).filter((v) => v !== null && v !== void 0);
|
|
1019
|
+
if (values.length === 0) {
|
|
1020
|
+
dimensionColumns.push(col);
|
|
1021
|
+
continue;
|
|
1022
|
+
}
|
|
1023
|
+
const numericCount = values.filter((v) => typeof v === "number" || typeof v === "string" && !isNaN(Number(v)) && v.trim() !== "").length;
|
|
1024
|
+
const isNumeric = numericCount / values.length > 0.5;
|
|
1025
|
+
if (isNumeric) {
|
|
1026
|
+
metricColumns.push(col);
|
|
1027
|
+
} else {
|
|
1028
|
+
dimensionColumns.push(col);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return { dimensionColumns, metricColumns };
|
|
1032
|
+
}
|
|
1010
1033
|
|
|
1011
1034
|
// src/components/prompt-generator.ts
|
|
1012
|
-
function generateMigrationPrompt(
|
|
1013
|
-
const
|
|
1014
|
-
if (
|
|
1035
|
+
function generateMigrationPrompt(config) {
|
|
1036
|
+
const { componentLabel, dimensions, metrics, grain, originalMetricColumns } = config;
|
|
1037
|
+
if (dimensions.length === 0 && metrics.length === 0) {
|
|
1015
1038
|
return `Replace the sample/hardcoded data in the "${componentLabel}" component with live data from the semantic layer using useSemanticQuery. Use the DataCatalog to find the right field names.`;
|
|
1016
1039
|
}
|
|
1017
|
-
const metrics = resolved.filter((m) => m.field.type === "metric").map((m) => m.field.name);
|
|
1018
|
-
const timeDims = resolved.filter((m) => m.field.type === "time_dimension").map((m) => m.field.name);
|
|
1019
|
-
const dims = resolved.filter((m) => m.field.type === "dimension").map((m) => m.field.name);
|
|
1020
|
-
const groupBy = [...timeDims, ...dims];
|
|
1021
1040
|
const parts = [
|
|
1022
|
-
`Replace the sample/hardcoded data in the "${componentLabel}" component with a useSemanticQuery call using
|
|
1041
|
+
`Replace the sample/hardcoded data in the "${componentLabel}" component with a useSemanticQuery call using:`,
|
|
1042
|
+
""
|
|
1023
1043
|
];
|
|
1024
1044
|
if (metrics.length > 0) {
|
|
1025
|
-
parts.push(` metrics: [${metrics.map((
|
|
1045
|
+
parts.push(` metrics: [${metrics.map((m) => `'${m.name}'`).join(", ")}]`);
|
|
1026
1046
|
}
|
|
1027
|
-
if (
|
|
1047
|
+
if (dimensions.length > 0) {
|
|
1048
|
+
const groupBy = dimensions.map((d) => d.field.name);
|
|
1028
1049
|
parts.push(` groupBy: [${groupBy.map((n) => `'${n}'`).join(", ")}]`);
|
|
1029
1050
|
}
|
|
1030
|
-
if (
|
|
1031
|
-
parts.push(` grain: '
|
|
1051
|
+
if (grain) {
|
|
1052
|
+
parts.push(` grain: '${grain}'`);
|
|
1032
1053
|
}
|
|
1033
1054
|
parts.push("");
|
|
1034
|
-
|
|
1035
|
-
for (const
|
|
1036
|
-
|
|
1055
|
+
const sampleRow = [];
|
|
1056
|
+
for (const d of dimensions) {
|
|
1057
|
+
sampleRow.push(`${d.field.name}: "..."`);
|
|
1058
|
+
}
|
|
1059
|
+
for (const m of metrics) {
|
|
1060
|
+
sampleRow.push(`${m.name}: 1234`);
|
|
1061
|
+
}
|
|
1062
|
+
parts.push("The query returns rows like:");
|
|
1063
|
+
parts.push(` { ${sampleRow.join(", ")} }`);
|
|
1064
|
+
parts.push("");
|
|
1065
|
+
parts.push("Map to the chart's expected format:");
|
|
1066
|
+
for (const d of dimensions) {
|
|
1067
|
+
parts.push(` X-axis / category: "${d.field.name}" (was "${d.column}" in the hardcoded data)`);
|
|
1068
|
+
}
|
|
1069
|
+
if (metrics.length > 0 && originalMetricColumns.length > 0) {
|
|
1070
|
+
parts.push(` Series / values: each metric (${metrics.map((m) => `"${m.name}"`).join(", ")}) becomes a line/area/bar in the chart`);
|
|
1071
|
+
parts.push(` (replaces the old columns: ${originalMetricColumns.map((c) => `"${c}"`).join(", ")})`);
|
|
1037
1072
|
}
|
|
1038
1073
|
parts.push("");
|
|
1039
1074
|
parts.push(
|
|
1040
|
-
"Remove the old hardcoded/sample data and any fetch logic it used. Use the data, isLoading, and error values from useSemanticQuery to render the component."
|
|
1075
|
+
"Remove the old hardcoded/sample data and any fetch logic it used. Use the data, isLoading, and error values from useSemanticQuery to render the component. Show a loading spinner while isLoading is true. Show an error message if error is not null."
|
|
1041
1076
|
);
|
|
1042
1077
|
return parts.join("\n");
|
|
1043
1078
|
}
|
|
@@ -1147,30 +1182,53 @@ function InspectorModal({
|
|
|
1147
1182
|
onClose
|
|
1148
1183
|
}) {
|
|
1149
1184
|
const { fields: catalog, error: catalogError, isLoading: catalogLoading } = useMetrics();
|
|
1150
|
-
const
|
|
1151
|
-
() =>
|
|
1152
|
-
[entry.columns,
|
|
1153
|
-
);
|
|
1154
|
-
const [mappings, setMappings] = useState(
|
|
1155
|
-
() => new Map(initialMatches.map((m) => [m.column, m.suggestedField]))
|
|
1185
|
+
const analysis = useMemo(
|
|
1186
|
+
() => analyzeChartData(entry.columns, entry.sampleValues),
|
|
1187
|
+
[entry.columns, entry.sampleValues]
|
|
1156
1188
|
);
|
|
1189
|
+
const dimensions = catalog.filter((f) => f.type === "dimension" || f.type === "time_dimension");
|
|
1190
|
+
const metrics = catalog.filter((f) => f.type === "metric");
|
|
1191
|
+
const initialDimMappings = useMemo(() => {
|
|
1192
|
+
const map = /* @__PURE__ */ new Map();
|
|
1193
|
+
for (const col of analysis.dimensionColumns) {
|
|
1194
|
+
const { field } = matchField(col, dimensions);
|
|
1195
|
+
map.set(col, field);
|
|
1196
|
+
}
|
|
1197
|
+
return map;
|
|
1198
|
+
}, [analysis.dimensionColumns, dimensions]);
|
|
1199
|
+
const [dimMappings, setDimMappings] = useState(initialDimMappings);
|
|
1157
1200
|
useEffect(() => {
|
|
1158
|
-
|
|
1159
|
-
}, [
|
|
1201
|
+
setDimMappings(initialDimMappings);
|
|
1202
|
+
}, [initialDimMappings]);
|
|
1203
|
+
const [selectedMetrics, setSelectedMetrics] = useState([]);
|
|
1204
|
+
const hasTimeDim = Array.from(dimMappings.values()).some((f) => f?.type === "time_dimension");
|
|
1205
|
+
const [grain, setGrain] = useState("month");
|
|
1160
1206
|
const [copied, setCopied] = useState(false);
|
|
1161
|
-
const
|
|
1162
|
-
|
|
1207
|
+
const handleDimChange = useCallback((col, field) => {
|
|
1208
|
+
setDimMappings((prev) => {
|
|
1163
1209
|
const next = new Map(prev);
|
|
1164
|
-
next.set(
|
|
1210
|
+
next.set(col, field);
|
|
1165
1211
|
return next;
|
|
1166
1212
|
});
|
|
1167
1213
|
}, []);
|
|
1214
|
+
const handleToggleMetric = useCallback((field) => {
|
|
1215
|
+
setSelectedMetrics(
|
|
1216
|
+
(prev) => prev.some((m) => m.name === field.name) ? prev.filter((m) => m.name !== field.name) : [...prev, field]
|
|
1217
|
+
);
|
|
1218
|
+
}, []);
|
|
1168
1219
|
const handleGenerate = useCallback(async () => {
|
|
1169
|
-
const
|
|
1170
|
-
|
|
1171
|
-
field
|
|
1172
|
-
}
|
|
1173
|
-
const
|
|
1220
|
+
const resolvedDims = [];
|
|
1221
|
+
for (const [col, field] of dimMappings) {
|
|
1222
|
+
if (field) resolvedDims.push({ column: col, field });
|
|
1223
|
+
}
|
|
1224
|
+
const migrationConfig = {
|
|
1225
|
+
componentLabel: entry.label,
|
|
1226
|
+
dimensions: resolvedDims,
|
|
1227
|
+
metrics: selectedMetrics,
|
|
1228
|
+
grain: hasTimeDim && grain ? grain : null,
|
|
1229
|
+
originalMetricColumns: analysis.metricColumns
|
|
1230
|
+
};
|
|
1231
|
+
const prompt = generateMigrationPrompt(migrationConfig);
|
|
1174
1232
|
try {
|
|
1175
1233
|
await navigator.clipboard.writeText(prompt);
|
|
1176
1234
|
setCopied(true);
|
|
@@ -1185,12 +1243,8 @@ function InspectorModal({
|
|
|
1185
1243
|
setCopied(true);
|
|
1186
1244
|
setTimeout(() => setCopied(false), 2e3);
|
|
1187
1245
|
}
|
|
1188
|
-
}, [entry,
|
|
1189
|
-
const
|
|
1190
|
-
const map = /* @__PURE__ */ new Map();
|
|
1191
|
-
for (const m of initialMatches) map.set(m.column, m.confidence);
|
|
1192
|
-
return map;
|
|
1193
|
-
}, [initialMatches]);
|
|
1246
|
+
}, [entry, dimMappings, selectedMetrics, grain, hasTimeDim, analysis.metricColumns]);
|
|
1247
|
+
const canGenerate = selectedMetrics.length > 0 || Array.from(dimMappings.values()).some(Boolean);
|
|
1194
1248
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1195
1249
|
/* @__PURE__ */ jsx("div", { onClick: onClose, style: backdropStyle }),
|
|
1196
1250
|
/* @__PURE__ */ jsxs("div", { style: modalStyle, children: [
|
|
@@ -1204,92 +1258,175 @@ function InspectorModal({
|
|
|
1204
1258
|
] }),
|
|
1205
1259
|
/* @__PURE__ */ jsx("button", { onClick: onClose, style: closeBtnStyle, children: "\xD7" })
|
|
1206
1260
|
] }),
|
|
1207
|
-
|
|
1208
|
-
/* @__PURE__ */
|
|
1209
|
-
|
|
1210
|
-
/* @__PURE__ */ jsx("
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
] }),
|
|
1214
|
-
/* @__PURE__ */ jsxs("div", { style: sectionStyle, children: [
|
|
1215
|
-
/* @__PURE__ */ jsx("div", { style: sectionTitleStyle, children: "Field Mapping" }),
|
|
1216
|
-
/* @__PURE__ */ jsxs("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: 13 }, children: [
|
|
1217
|
-
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
1218
|
-
/* @__PURE__ */ jsx("th", { style: mappingThStyle, children: "Current Column" }),
|
|
1219
|
-
/* @__PURE__ */ jsx("th", { style: mappingThStyle, children: "Confidence" }),
|
|
1220
|
-
/* @__PURE__ */ jsx("th", { style: mappingThStyle, children: "Semantic Layer Field" })
|
|
1261
|
+
/* @__PURE__ */ jsxs("div", { style: { overflow: "auto", flex: 1 }, children: [
|
|
1262
|
+
entry.sampleValues.length > 0 && /* @__PURE__ */ jsxs("div", { style: sectionStyle, children: [
|
|
1263
|
+
/* @__PURE__ */ jsx("div", { style: sectionTitleStyle, children: "Current Data Preview" }),
|
|
1264
|
+
/* @__PURE__ */ jsx("div", { style: { overflow: "auto" }, children: /* @__PURE__ */ jsxs("table", { style: previewTableStyle, children: [
|
|
1265
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: entry.columns.map((col) => /* @__PURE__ */ jsx("th", { style: previewThStyle, children: col }, col)) }) }),
|
|
1266
|
+
/* @__PURE__ */ jsx("tbody", { children: entry.sampleValues.map((row, i) => /* @__PURE__ */ jsx("tr", { children: entry.columns.map((col) => /* @__PURE__ */ jsx("td", { style: previewTdStyle, children: row[col] === null || row[col] === void 0 ? "\u2014" : String(row[col]) }, col)) }, i)) })
|
|
1221
1267
|
] }) }),
|
|
1222
|
-
/* @__PURE__ */
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1268
|
+
/* @__PURE__ */ jsxs("div", { style: { marginTop: 8, fontSize: 11, color: "#9ca3af" }, children: [
|
|
1269
|
+
"Detected: ",
|
|
1270
|
+
analysis.dimensionColumns.length,
|
|
1271
|
+
" dimension column",
|
|
1272
|
+
analysis.dimensionColumns.length !== 1 ? "s" : "",
|
|
1273
|
+
" (",
|
|
1274
|
+
analysis.dimensionColumns.join(", ") || "none",
|
|
1275
|
+
")",
|
|
1276
|
+
" \xB7 ",
|
|
1277
|
+
analysis.metricColumns.length,
|
|
1278
|
+
" value column",
|
|
1279
|
+
analysis.metricColumns.length !== 1 ? "s" : "",
|
|
1280
|
+
" (",
|
|
1281
|
+
analysis.metricColumns.join(", ") || "none",
|
|
1282
|
+
")"
|
|
1283
|
+
] })
|
|
1284
|
+
] }),
|
|
1285
|
+
catalog.length === 0 && /* @__PURE__ */ jsx("div", { style: { ...sectionStyle, textAlign: "center" }, children: /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#9ca3af" }, children: catalogLoading ? "Loading catalog..." : catalogError ? `Error loading catalog: ${catalogError}` : "No semantic layer catalog available. Connect to the gateway to enable smart matching." }) }),
|
|
1286
|
+
catalog.length > 0 && /* @__PURE__ */ jsxs("div", { style: sectionStyle, children: [
|
|
1287
|
+
/* @__PURE__ */ jsx("div", { style: sectionTitleStyle, children: "Dimensions (Group By)" }),
|
|
1288
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: "#9ca3af", marginBottom: 8 }, children: "What categories define the rows? (X-axis, grouping)" }),
|
|
1289
|
+
analysis.dimensionColumns.length === 0 ? /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#9ca3af", fontStyle: "italic" }, children: "No dimension columns detected in the data." }) : /* @__PURE__ */ jsxs("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: 13 }, children: [
|
|
1290
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
1291
|
+
/* @__PURE__ */ jsx("th", { style: mappingThStyle, children: "Current Column" }),
|
|
1292
|
+
/* @__PURE__ */ jsx("th", { style: mappingThStyle, children: "Sample Values" }),
|
|
1293
|
+
/* @__PURE__ */ jsx("th", { style: mappingThStyle, children: "Semantic Layer Dimension" })
|
|
1294
|
+
] }) }),
|
|
1295
|
+
/* @__PURE__ */ jsx("tbody", { children: analysis.dimensionColumns.map((col) => {
|
|
1296
|
+
const sampleVals = entry.sampleValues.map((row) => row[col]).filter((v) => v !== null && v !== void 0).slice(0, 4).map(String);
|
|
1297
|
+
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
1298
|
+
/* @__PURE__ */ jsx("td", { style: mappingTdStyle, children: /* @__PURE__ */ jsx("code", { style: { fontSize: 12, color: "#6366f1", fontFamily: "monospace" }, children: col }) }),
|
|
1299
|
+
/* @__PURE__ */ jsxs("td", { style: { ...mappingTdStyle, fontSize: 11, color: "#9ca3af" }, children: [
|
|
1300
|
+
sampleVals.join(", "),
|
|
1301
|
+
sampleVals.length >= 4 ? ", ..." : ""
|
|
1302
|
+
] }),
|
|
1303
|
+
/* @__PURE__ */ jsx("td", { style: mappingTdStyle, children: /* @__PURE__ */ jsxs(
|
|
1304
|
+
"select",
|
|
1305
|
+
{
|
|
1306
|
+
value: dimMappings.get(col)?.name ?? "",
|
|
1307
|
+
onChange: (e) => {
|
|
1308
|
+
const field = dimensions.find((f) => f.name === e.target.value) ?? null;
|
|
1309
|
+
handleDimChange(col, field);
|
|
1310
|
+
},
|
|
1311
|
+
style: selectStyle2,
|
|
1312
|
+
children: [
|
|
1313
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "-- select dimension --" }),
|
|
1314
|
+
dimensions.map((f) => /* @__PURE__ */ jsxs("option", { value: f.name, children: [
|
|
1315
|
+
f.displayName,
|
|
1316
|
+
" (",
|
|
1317
|
+
f.type,
|
|
1318
|
+
") \u2014 ",
|
|
1319
|
+
f.name
|
|
1320
|
+
] }, f.name))
|
|
1321
|
+
]
|
|
1322
|
+
}
|
|
1323
|
+
) })
|
|
1324
|
+
] }, col);
|
|
1325
|
+
}) })
|
|
1326
|
+
] }),
|
|
1327
|
+
hasTimeDim && /* @__PURE__ */ jsxs("div", { style: { marginTop: 10, display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
1328
|
+
/* @__PURE__ */ jsx("label", { style: { fontSize: 12, fontWeight: 600, color: "#374151" }, children: "Time Grain:" }),
|
|
1329
|
+
/* @__PURE__ */ jsxs(
|
|
1330
|
+
"select",
|
|
1331
|
+
{
|
|
1332
|
+
value: grain,
|
|
1333
|
+
onChange: (e) => setGrain(e.target.value),
|
|
1334
|
+
style: { ...selectStyle2, width: "auto" },
|
|
1335
|
+
children: [
|
|
1336
|
+
/* @__PURE__ */ jsx("option", { value: "day", children: "Day" }),
|
|
1337
|
+
/* @__PURE__ */ jsx("option", { value: "week", children: "Week" }),
|
|
1338
|
+
/* @__PURE__ */ jsx("option", { value: "month", children: "Month" }),
|
|
1339
|
+
/* @__PURE__ */ jsx("option", { value: "quarter", children: "Quarter" }),
|
|
1340
|
+
/* @__PURE__ */ jsx("option", { value: "year", children: "Year" })
|
|
1341
|
+
]
|
|
1342
|
+
}
|
|
1343
|
+
)
|
|
1344
|
+
] })
|
|
1233
1345
|
] }),
|
|
1234
|
-
catalog.length
|
|
1346
|
+
catalog.length > 0 && /* @__PURE__ */ jsxs("div", { style: sectionStyle, children: [
|
|
1347
|
+
/* @__PURE__ */ jsx("div", { style: sectionTitleStyle, children: "Metrics (Values)" }),
|
|
1348
|
+
/* @__PURE__ */ jsxs("div", { style: { fontSize: 11, color: "#9ca3af", marginBottom: 8 }, children: [
|
|
1349
|
+
"Which metrics should be queried? These become the series/values in the chart.",
|
|
1350
|
+
analysis.metricColumns.length > 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
1351
|
+
" (replaces: ",
|
|
1352
|
+
analysis.metricColumns.join(", "),
|
|
1353
|
+
")"
|
|
1354
|
+
] })
|
|
1355
|
+
] }),
|
|
1356
|
+
metrics.length === 0 ? /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#9ca3af", fontStyle: "italic" }, children: "No metrics available in the catalog." }) : /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 4, maxHeight: 200, overflow: "auto" }, children: metrics.map((m) => {
|
|
1357
|
+
const isSelected = selectedMetrics.some((s) => s.name === m.name);
|
|
1358
|
+
return /* @__PURE__ */ jsxs(
|
|
1359
|
+
"label",
|
|
1360
|
+
{
|
|
1361
|
+
style: {
|
|
1362
|
+
display: "flex",
|
|
1363
|
+
alignItems: "center",
|
|
1364
|
+
gap: 8,
|
|
1365
|
+
padding: "4px 8px",
|
|
1366
|
+
borderRadius: 4,
|
|
1367
|
+
cursor: "pointer",
|
|
1368
|
+
backgroundColor: isSelected ? "#eff6ff" : "transparent",
|
|
1369
|
+
border: isSelected ? "1px solid #bfdbfe" : "1px solid transparent",
|
|
1370
|
+
fontSize: 12
|
|
1371
|
+
},
|
|
1372
|
+
children: [
|
|
1373
|
+
/* @__PURE__ */ jsx(
|
|
1374
|
+
"input",
|
|
1375
|
+
{
|
|
1376
|
+
type: "checkbox",
|
|
1377
|
+
checked: isSelected,
|
|
1378
|
+
onChange: () => handleToggleMetric(m),
|
|
1379
|
+
style: { margin: 0 }
|
|
1380
|
+
}
|
|
1381
|
+
),
|
|
1382
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 500, color: "#111827" }, children: m.displayName }),
|
|
1383
|
+
/* @__PURE__ */ jsx("code", { style: { fontSize: 10, color: "#6366f1", fontFamily: "monospace" }, children: m.name }),
|
|
1384
|
+
m.category && /* @__PURE__ */ jsx("span", { style: { marginLeft: "auto", fontSize: 10, color: "#9ca3af" }, children: m.category })
|
|
1385
|
+
]
|
|
1386
|
+
},
|
|
1387
|
+
m.name
|
|
1388
|
+
);
|
|
1389
|
+
}) }),
|
|
1390
|
+
selectedMetrics.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: 8, fontSize: 11, color: "#6b7280" }, children: [
|
|
1391
|
+
"Selected: ",
|
|
1392
|
+
selectedMetrics.map((m) => m.displayName).join(", ")
|
|
1393
|
+
] })
|
|
1394
|
+
] }),
|
|
1395
|
+
canGenerate && /* @__PURE__ */ jsxs("div", { style: sectionStyle, children: [
|
|
1396
|
+
/* @__PURE__ */ jsx("div", { style: sectionTitleStyle, children: "Query Preview" }),
|
|
1397
|
+
/* @__PURE__ */ jsx("pre", { style: {
|
|
1398
|
+
fontSize: 11,
|
|
1399
|
+
fontFamily: "monospace",
|
|
1400
|
+
backgroundColor: "#f9fafb",
|
|
1401
|
+
border: "1px solid #e5e7eb",
|
|
1402
|
+
borderRadius: 6,
|
|
1403
|
+
padding: "8px 12px",
|
|
1404
|
+
whiteSpace: "pre-wrap",
|
|
1405
|
+
color: "#374151",
|
|
1406
|
+
margin: 0
|
|
1407
|
+
}, children: `useSemanticQuery({${selectedMetrics.length > 0 ? `
|
|
1408
|
+
metrics: [${selectedMetrics.map((m) => `'${m.name}'`).join(", ")}],` : ""}${Array.from(dimMappings.values()).some(Boolean) ? `
|
|
1409
|
+
groupBy: [${Array.from(dimMappings.values()).filter(Boolean).map((f) => `'${f.name}'`).join(", ")}],` : ""}${hasTimeDim && grain ? `
|
|
1410
|
+
grain: '${grain}',` : ""}
|
|
1411
|
+
})` })
|
|
1412
|
+
] })
|
|
1235
1413
|
] }),
|
|
1236
|
-
/* @__PURE__ */ jsx("div", { style: { padding: "12px 20px", borderTop: "1px solid #e5e7eb" }, children: /* @__PURE__ */ jsx(
|
|
1414
|
+
/* @__PURE__ */ jsx("div", { style: { padding: "12px 20px", borderTop: "1px solid #e5e7eb" }, children: /* @__PURE__ */ jsx(
|
|
1415
|
+
"button",
|
|
1416
|
+
{
|
|
1417
|
+
onClick: handleGenerate,
|
|
1418
|
+
disabled: !canGenerate,
|
|
1419
|
+
style: {
|
|
1420
|
+
...generateBtnStyle,
|
|
1421
|
+
opacity: canGenerate ? 1 : 0.5,
|
|
1422
|
+
cursor: canGenerate ? "pointer" : "not-allowed"
|
|
1423
|
+
},
|
|
1424
|
+
children: copied ? "Copied to clipboard!" : "Generate Migration Prompt"
|
|
1425
|
+
}
|
|
1426
|
+
) })
|
|
1237
1427
|
] })
|
|
1238
1428
|
] });
|
|
1239
1429
|
}
|
|
1240
|
-
function MappingRow({
|
|
1241
|
-
column,
|
|
1242
|
-
confidence,
|
|
1243
|
-
selectedField,
|
|
1244
|
-
catalog,
|
|
1245
|
-
onChange
|
|
1246
|
-
}) {
|
|
1247
|
-
const badgeColors = {
|
|
1248
|
-
exact: { bg: "#dcfce7", color: "#15803d" },
|
|
1249
|
-
fuzzy: { bg: "#fef9c3", color: "#a16207" },
|
|
1250
|
-
manual: { bg: "#fee2e2", color: "#dc2626" }
|
|
1251
|
-
};
|
|
1252
|
-
const badge = badgeColors[confidence] ?? badgeColors.manual;
|
|
1253
|
-
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
1254
|
-
/* @__PURE__ */ jsx("td", { style: mappingTdStyle, children: /* @__PURE__ */ jsx("code", { style: { fontSize: 12, color: "#6366f1", fontFamily: "monospace" }, children: column }) }),
|
|
1255
|
-
/* @__PURE__ */ jsx("td", { style: { ...mappingTdStyle, textAlign: "center" }, children: /* @__PURE__ */ jsx(
|
|
1256
|
-
"span",
|
|
1257
|
-
{
|
|
1258
|
-
style: {
|
|
1259
|
-
display: "inline-block",
|
|
1260
|
-
padding: "1px 6px",
|
|
1261
|
-
fontSize: 10,
|
|
1262
|
-
fontWeight: 600,
|
|
1263
|
-
borderRadius: 4,
|
|
1264
|
-
backgroundColor: badge.bg,
|
|
1265
|
-
color: badge.color
|
|
1266
|
-
},
|
|
1267
|
-
children: confidence
|
|
1268
|
-
}
|
|
1269
|
-
) }),
|
|
1270
|
-
/* @__PURE__ */ jsx("td", { style: mappingTdStyle, children: catalog.length > 0 ? /* @__PURE__ */ jsxs(
|
|
1271
|
-
"select",
|
|
1272
|
-
{
|
|
1273
|
-
value: selectedField?.name ?? "",
|
|
1274
|
-
onChange: (e) => {
|
|
1275
|
-
const field = catalog.find((f) => f.name === e.target.value) ?? null;
|
|
1276
|
-
onChange(field);
|
|
1277
|
-
},
|
|
1278
|
-
style: selectStyle2,
|
|
1279
|
-
children: [
|
|
1280
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "-- none --" }),
|
|
1281
|
-
catalog.map((f) => /* @__PURE__ */ jsxs("option", { value: f.name, children: [
|
|
1282
|
-
f.displayName,
|
|
1283
|
-
" (",
|
|
1284
|
-
f.type,
|
|
1285
|
-
") \u2014 ",
|
|
1286
|
-
f.name
|
|
1287
|
-
] }, f.name))
|
|
1288
|
-
]
|
|
1289
|
-
}
|
|
1290
|
-
) : /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "#9ca3af" }, children: selectedField ? selectedField.name : "No catalog" }) })
|
|
1291
|
-
] });
|
|
1292
|
-
}
|
|
1293
1430
|
var backdropStyle = {
|
|
1294
1431
|
position: "fixed",
|
|
1295
1432
|
inset: 0,
|
|
@@ -1302,8 +1439,8 @@ var modalStyle = {
|
|
|
1302
1439
|
left: "50%",
|
|
1303
1440
|
transform: "translate(-50%, -50%)",
|
|
1304
1441
|
zIndex: 100001,
|
|
1305
|
-
width: "min(
|
|
1306
|
-
maxHeight: "
|
|
1442
|
+
width: "min(700px, 90vw)",
|
|
1443
|
+
maxHeight: "85vh",
|
|
1307
1444
|
backgroundColor: "#fff",
|
|
1308
1445
|
borderRadius: 12,
|
|
1309
1446
|
boxShadow: "0 8px 30px rgba(0,0,0,0.2)",
|
|
@@ -1329,9 +1466,7 @@ var closeBtnStyle = {
|
|
|
1329
1466
|
lineHeight: 1
|
|
1330
1467
|
};
|
|
1331
1468
|
var sectionStyle = {
|
|
1332
|
-
padding: "12px 20px"
|
|
1333
|
-
overflow: "auto",
|
|
1334
|
-
flex: 1
|
|
1469
|
+
padding: "12px 20px"
|
|
1335
1470
|
};
|
|
1336
1471
|
var sectionTitleStyle = {
|
|
1337
1472
|
fontSize: 11,
|
|
@@ -1339,7 +1474,7 @@ var sectionTitleStyle = {
|
|
|
1339
1474
|
textTransform: "uppercase",
|
|
1340
1475
|
letterSpacing: "0.05em",
|
|
1341
1476
|
color: "#6b7280",
|
|
1342
|
-
marginBottom:
|
|
1477
|
+
marginBottom: 4
|
|
1343
1478
|
};
|
|
1344
1479
|
var previewTableStyle = {
|
|
1345
1480
|
width: "100%",
|
|
@@ -1394,10 +1529,9 @@ var generateBtnStyle = {
|
|
|
1394
1529
|
color: "#fff",
|
|
1395
1530
|
backgroundColor: "#3b82f6",
|
|
1396
1531
|
border: "none",
|
|
1397
|
-
borderRadius: 8
|
|
1398
|
-
cursor: "pointer"
|
|
1532
|
+
borderRadius: 8
|
|
1399
1533
|
};
|
|
1400
1534
|
|
|
1401
|
-
export { AdminDashboard, DataCatalog, DataInspector, Inspectable, MetricPicker, ResultsTable, generateMigrationPrompt, matchFields };
|
|
1535
|
+
export { AdminDashboard, DataCatalog, DataInspector, Inspectable, MetricPicker, ResultsTable, analyzeChartData, generateMigrationPrompt, matchField, matchFields };
|
|
1402
1536
|
//# sourceMappingURL=components.js.map
|
|
1403
1537
|
//# sourceMappingURL=components.js.map
|