@prismiq/react 0.1.1 → 0.2.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/{CustomSQLEditor-d84v_Cgp.d.cts → ChatBubble-ARocmvZD.d.cts} +40 -3
- package/dist/{CustomSQLEditor-CYlOtecq.d.ts → ChatBubble-BN_CjIpk.d.ts} +40 -3
- package/dist/{DashboardDialog-CZD8I-6z.d.cts → DashboardDialog-UhUGXx2h.d.ts} +5 -3
- package/dist/{DashboardDialog-DBNTVVSp.d.ts → DashboardDialog-Z-HypxmG.d.cts} +5 -3
- package/dist/charts/index.d.cts +2 -2
- package/dist/charts/index.d.ts +2 -2
- package/dist/{chunk-VQDFS6VS.cjs → chunk-FKXCINUF.cjs} +368 -210
- package/dist/chunk-FKXCINUF.cjs.map +1 -0
- package/dist/{chunk-ET7GCREP.js → chunk-GELI7MDZ.js} +482 -7
- package/dist/chunk-GELI7MDZ.js.map +1 -0
- package/dist/{chunk-WWTT2OJ5.js → chunk-HKZFEXT6.js} +27 -9
- package/dist/chunk-HKZFEXT6.js.map +1 -0
- package/dist/{chunk-3LDRRDJ6.js → chunk-JBJ5LEAG.js} +186 -28
- package/dist/chunk-JBJ5LEAG.js.map +1 -0
- package/dist/{chunk-URJH4H6G.cjs → chunk-PG7QBH3G.cjs} +485 -6
- package/dist/chunk-PG7QBH3G.cjs.map +1 -0
- package/dist/{chunk-MDXGGZSW.cjs → chunk-ZYVN6XAZ.cjs} +35 -37
- package/dist/chunk-ZYVN6XAZ.cjs.map +1 -0
- package/dist/components/index.cjs +62 -54
- package/dist/components/index.d.cts +2 -2
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.js +1 -1
- package/dist/dashboard/index.cjs +34 -34
- package/dist/dashboard/index.d.cts +7 -5
- package/dist/dashboard/index.d.ts +7 -5
- package/dist/dashboard/index.js +2 -2
- package/dist/export/index.cjs +7 -7
- package/dist/export/index.d.cts +6 -4
- package/dist/export/index.d.ts +6 -4
- package/dist/export/index.js +1 -1
- package/dist/{index-CvKj3SWO.d.cts → index-B8DelfpL.d.cts} +1 -1
- package/dist/{index-DXGLs1yY.d.ts → index-RbfYPQD_.d.ts} +1 -1
- package/dist/index.cjs +119 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -7
- package/dist/index.d.ts +74 -7
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/{types-j0kPJ9Hz.d.cts → types-ccB9Ps3k.d.cts} +44 -1
- package/dist/{types-j0kPJ9Hz.d.ts → types-ccB9Ps3k.d.ts} +44 -1
- package/dist/utils/index.d.cts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/package.json +2 -6
- package/dist/chunk-3LDRRDJ6.js.map +0 -1
- package/dist/chunk-ET7GCREP.js.map +0 -1
- package/dist/chunk-MDXGGZSW.cjs.map +0 -1
- package/dist/chunk-URJH4H6G.cjs.map +0 -1
- package/dist/chunk-VQDFS6VS.cjs.map +0 -1
- package/dist/chunk-WWTT2OJ5.js.map +0 -1
|
@@ -2843,6 +2843,83 @@ var PrismiqClient = class {
|
|
|
2843
2843
|
})
|
|
2844
2844
|
});
|
|
2845
2845
|
}
|
|
2846
|
+
// ============================================================================
|
|
2847
|
+
// LLM Methods
|
|
2848
|
+
// ============================================================================
|
|
2849
|
+
/**
|
|
2850
|
+
* Get the LLM agent status.
|
|
2851
|
+
*
|
|
2852
|
+
* @returns LLM status including enabled state, provider, and model.
|
|
2853
|
+
*/
|
|
2854
|
+
async getLLMStatus() {
|
|
2855
|
+
return this.request("/llm/status");
|
|
2856
|
+
}
|
|
2857
|
+
/**
|
|
2858
|
+
* Stream a chat response from the LLM agent via SSE.
|
|
2859
|
+
*
|
|
2860
|
+
* @param message - User's message.
|
|
2861
|
+
* @param history - Previous conversation messages.
|
|
2862
|
+
* @param currentSql - Current SQL in the editor (for context).
|
|
2863
|
+
* @param signal - Optional AbortSignal for cancellation.
|
|
2864
|
+
* @yields StreamChunk objects as the response is generated.
|
|
2865
|
+
*/
|
|
2866
|
+
async *streamChat(message, history, currentSql, signal) {
|
|
2867
|
+
const url = `${this.endpoint}/llm/chat`;
|
|
2868
|
+
const headers = {
|
|
2869
|
+
"Content-Type": "application/json",
|
|
2870
|
+
"X-Tenant-ID": this.tenantId
|
|
2871
|
+
};
|
|
2872
|
+
if (this.userId) headers["X-User-ID"] = this.userId;
|
|
2873
|
+
if (this.schemaName) headers["X-Schema-Name"] = this.schemaName;
|
|
2874
|
+
if (this.customHeaders) Object.assign(headers, this.customHeaders);
|
|
2875
|
+
if (this.getToken) {
|
|
2876
|
+
const token = await this.getToken();
|
|
2877
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
2878
|
+
}
|
|
2879
|
+
const response = await fetch(url, {
|
|
2880
|
+
method: "POST",
|
|
2881
|
+
headers,
|
|
2882
|
+
body: JSON.stringify({
|
|
2883
|
+
message,
|
|
2884
|
+
history,
|
|
2885
|
+
current_sql: currentSql
|
|
2886
|
+
}),
|
|
2887
|
+
signal
|
|
2888
|
+
});
|
|
2889
|
+
if (!response.ok) {
|
|
2890
|
+
throw new PrismiqError(
|
|
2891
|
+
`LLM chat failed: ${response.status} ${response.statusText}`,
|
|
2892
|
+
response.status
|
|
2893
|
+
);
|
|
2894
|
+
}
|
|
2895
|
+
const reader = response.body?.getReader();
|
|
2896
|
+
if (!reader) return;
|
|
2897
|
+
const decoder = new TextDecoder();
|
|
2898
|
+
let buffer = "";
|
|
2899
|
+
try {
|
|
2900
|
+
while (true) {
|
|
2901
|
+
const { done, value } = await reader.read();
|
|
2902
|
+
if (done) break;
|
|
2903
|
+
buffer += decoder.decode(value, { stream: true });
|
|
2904
|
+
const lines = buffer.split("\n");
|
|
2905
|
+
buffer = lines.pop() ?? "";
|
|
2906
|
+
for (const line of lines) {
|
|
2907
|
+
if (line.startsWith("data: ")) {
|
|
2908
|
+
const data = line.slice(6).trim();
|
|
2909
|
+
if (data) {
|
|
2910
|
+
try {
|
|
2911
|
+
const chunk = JSON.parse(data);
|
|
2912
|
+
yield chunk;
|
|
2913
|
+
} catch {
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
} finally {
|
|
2920
|
+
reader.releaseLock();
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2846
2923
|
};
|
|
2847
2924
|
var AnalyticsContext = react.createContext(null);
|
|
2848
2925
|
var CallbacksContext = react.createContext({});
|
|
@@ -3900,6 +3977,140 @@ function CrossFilterProvider({
|
|
|
3900
3977
|
function useCrossFilterOptional() {
|
|
3901
3978
|
return react.useContext(CrossFilterContext);
|
|
3902
3979
|
}
|
|
3980
|
+
|
|
3981
|
+
// src/hooks/useLLMStatus.ts
|
|
3982
|
+
function useLLMStatus() {
|
|
3983
|
+
const { client } = useAnalytics();
|
|
3984
|
+
const [status, setStatus] = react.useState({ enabled: false });
|
|
3985
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
3986
|
+
const [error, setError] = react.useState(null);
|
|
3987
|
+
react.useEffect(() => {
|
|
3988
|
+
if (!client) {
|
|
3989
|
+
setIsLoading(false);
|
|
3990
|
+
return;
|
|
3991
|
+
}
|
|
3992
|
+
let cancelled = false;
|
|
3993
|
+
client.getLLMStatus().then((result) => {
|
|
3994
|
+
if (!cancelled) {
|
|
3995
|
+
setStatus(result);
|
|
3996
|
+
setError(null);
|
|
3997
|
+
}
|
|
3998
|
+
}).catch((err) => {
|
|
3999
|
+
if (!cancelled) {
|
|
4000
|
+
setStatus({ enabled: false });
|
|
4001
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
4002
|
+
}
|
|
4003
|
+
}).finally(() => {
|
|
4004
|
+
if (!cancelled) setIsLoading(false);
|
|
4005
|
+
});
|
|
4006
|
+
return () => {
|
|
4007
|
+
cancelled = true;
|
|
4008
|
+
};
|
|
4009
|
+
}, [client]);
|
|
4010
|
+
return {
|
|
4011
|
+
enabled: status.enabled,
|
|
4012
|
+
provider: status.provider,
|
|
4013
|
+
model: status.model,
|
|
4014
|
+
isLoading,
|
|
4015
|
+
error
|
|
4016
|
+
};
|
|
4017
|
+
}
|
|
4018
|
+
function useLLMChat() {
|
|
4019
|
+
const { client } = useAnalytics();
|
|
4020
|
+
const [messages, setMessages] = react.useState([]);
|
|
4021
|
+
const [isStreaming, setIsStreaming] = react.useState(false);
|
|
4022
|
+
const [streamingContent, setStreamingContent] = react.useState("");
|
|
4023
|
+
const [suggestedSql, setSuggestedSql] = react.useState(null);
|
|
4024
|
+
const [error, setError] = react.useState(null);
|
|
4025
|
+
const abortRef = react.useRef(null);
|
|
4026
|
+
const isStreamingRef = react.useRef(false);
|
|
4027
|
+
const messagesRef = react.useRef([]);
|
|
4028
|
+
messagesRef.current = messages;
|
|
4029
|
+
const sendMessage = react.useCallback(
|
|
4030
|
+
async (message, currentSql) => {
|
|
4031
|
+
if (!client || isStreamingRef.current) return;
|
|
4032
|
+
abortRef.current?.abort();
|
|
4033
|
+
const controller = new AbortController();
|
|
4034
|
+
abortRef.current = controller;
|
|
4035
|
+
const userMsg = { role: "user", content: message };
|
|
4036
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
4037
|
+
isStreamingRef.current = true;
|
|
4038
|
+
setIsStreaming(true);
|
|
4039
|
+
setStreamingContent("");
|
|
4040
|
+
setSuggestedSql(null);
|
|
4041
|
+
setError(null);
|
|
4042
|
+
let accumulatedText = "";
|
|
4043
|
+
let lastSql = null;
|
|
4044
|
+
try {
|
|
4045
|
+
const history = messagesRef.current.map((m) => ({
|
|
4046
|
+
role: m.role,
|
|
4047
|
+
content: m.content
|
|
4048
|
+
}));
|
|
4049
|
+
for await (const chunk of client.streamChat(
|
|
4050
|
+
message,
|
|
4051
|
+
history,
|
|
4052
|
+
currentSql,
|
|
4053
|
+
controller.signal
|
|
4054
|
+
)) {
|
|
4055
|
+
if (controller.signal.aborted) break;
|
|
4056
|
+
switch (chunk.type) {
|
|
4057
|
+
case "text":
|
|
4058
|
+
accumulatedText += chunk.content ?? "";
|
|
4059
|
+
setStreamingContent(accumulatedText);
|
|
4060
|
+
break;
|
|
4061
|
+
case "sql":
|
|
4062
|
+
lastSql = chunk.content ?? null;
|
|
4063
|
+
setSuggestedSql(lastSql);
|
|
4064
|
+
break;
|
|
4065
|
+
case "error":
|
|
4066
|
+
setError(chunk.content ?? "Unknown error");
|
|
4067
|
+
break;
|
|
4068
|
+
case "done":
|
|
4069
|
+
break;
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
} catch (err) {
|
|
4073
|
+
if (err instanceof Error && err.name !== "AbortError") {
|
|
4074
|
+
setError(err.message);
|
|
4075
|
+
}
|
|
4076
|
+
} finally {
|
|
4077
|
+
isStreamingRef.current = false;
|
|
4078
|
+
setIsStreaming(false);
|
|
4079
|
+
if (accumulatedText) {
|
|
4080
|
+
const assistantMsg = {
|
|
4081
|
+
role: "assistant",
|
|
4082
|
+
content: accumulatedText
|
|
4083
|
+
};
|
|
4084
|
+
setMessages((prev) => [...prev, assistantMsg]);
|
|
4085
|
+
}
|
|
4086
|
+
setStreamingContent("");
|
|
4087
|
+
}
|
|
4088
|
+
},
|
|
4089
|
+
[client]
|
|
4090
|
+
);
|
|
4091
|
+
react.useEffect(() => {
|
|
4092
|
+
return () => {
|
|
4093
|
+
abortRef.current?.abort();
|
|
4094
|
+
};
|
|
4095
|
+
}, []);
|
|
4096
|
+
const clearHistory = react.useCallback(() => {
|
|
4097
|
+
abortRef.current?.abort();
|
|
4098
|
+
setMessages([]);
|
|
4099
|
+
setStreamingContent("");
|
|
4100
|
+
setSuggestedSql(null);
|
|
4101
|
+
setError(null);
|
|
4102
|
+
setIsStreaming(false);
|
|
4103
|
+
}, []);
|
|
4104
|
+
return {
|
|
4105
|
+
messages,
|
|
4106
|
+
isStreaming,
|
|
4107
|
+
streamingContent,
|
|
4108
|
+
suggestedSql,
|
|
4109
|
+
sendMessage,
|
|
4110
|
+
clearHistory,
|
|
4111
|
+
error
|
|
4112
|
+
};
|
|
4113
|
+
}
|
|
3903
4114
|
var nodeStyles = {
|
|
3904
4115
|
display: "flex",
|
|
3905
4116
|
alignItems: "center",
|
|
@@ -4362,6 +4573,7 @@ function SchemaExplorer({
|
|
|
4362
4573
|
selectedColumns = [],
|
|
4363
4574
|
searchable = true,
|
|
4364
4575
|
collapsible = true,
|
|
4576
|
+
headerAction,
|
|
4365
4577
|
className,
|
|
4366
4578
|
style
|
|
4367
4579
|
}) {
|
|
@@ -4397,10 +4609,12 @@ function SchemaExplorer({
|
|
|
4397
4609
|
style: { ...containerStyles4, ...style },
|
|
4398
4610
|
role: "tree",
|
|
4399
4611
|
"aria-label": "Database schema",
|
|
4612
|
+
"data-testid": "schema-explorer-root",
|
|
4400
4613
|
children: [
|
|
4401
4614
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyles2, children: [
|
|
4402
4615
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "table", size: 16, style: { color: "var(--prismiq-color-primary)" } }),
|
|
4403
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: titleStyles2, children: "Schema Explorer" })
|
|
4616
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...titleStyles2, flex: 1 }, children: "Schema Explorer" }),
|
|
4617
|
+
headerAction
|
|
4404
4618
|
] }),
|
|
4405
4619
|
searchable && /* @__PURE__ */ jsxRuntime.jsx("div", { style: searchContainerStyles, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4406
4620
|
Input,
|
|
@@ -4409,7 +4623,8 @@ function SchemaExplorer({
|
|
|
4409
4623
|
placeholder: "Search tables and columns...",
|
|
4410
4624
|
value: searchQuery,
|
|
4411
4625
|
onChange: (e) => setSearchQuery(e.target.value),
|
|
4412
|
-
style: { width: "100%" }
|
|
4626
|
+
style: { width: "100%" },
|
|
4627
|
+
"data-testid": "schema-explorer-search"
|
|
4413
4628
|
}
|
|
4414
4629
|
) }),
|
|
4415
4630
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: treeContainerStyles, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(LoadingSkeleton, {}) : error ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: errorStyles2, children: [
|
|
@@ -8873,7 +9088,14 @@ function CustomSQLEditor({
|
|
|
8873
9088
|
style
|
|
8874
9089
|
}) {
|
|
8875
9090
|
const [sql, setSql] = react.useState(initialSql);
|
|
9091
|
+
const prevInitialSqlRef = react.useRef(initialSql);
|
|
8876
9092
|
const [isFocused, setIsFocused] = react.useState(false);
|
|
9093
|
+
react.useEffect(() => {
|
|
9094
|
+
if (initialSql !== prevInitialSqlRef.current) {
|
|
9095
|
+
prevInitialSqlRef.current = initialSql;
|
|
9096
|
+
setSql(initialSql);
|
|
9097
|
+
}
|
|
9098
|
+
}, [initialSql]);
|
|
8877
9099
|
const [executeEnabled, setExecuteEnabled] = react.useState(false);
|
|
8878
9100
|
const [lastExecutedSql, setLastExecutedSql] = react.useState(null);
|
|
8879
9101
|
const {
|
|
@@ -8919,7 +9141,7 @@ function CustomSQLEditor({
|
|
|
8919
9141
|
...buttonStyles,
|
|
8920
9142
|
...canExecute ? {} : buttonDisabledStyles
|
|
8921
9143
|
};
|
|
8922
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...containerStyles17, ...style }, children: [
|
|
9144
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...containerStyles17, ...style }, "data-testid": "custom-sql-editor", children: [
|
|
8923
9145
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: editorWrapperStyles, children: [
|
|
8924
9146
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8925
9147
|
"textarea",
|
|
@@ -8933,7 +9155,8 @@ function CustomSQLEditor({
|
|
|
8933
9155
|
style: mergedTextareaStyles,
|
|
8934
9156
|
spellCheck: false,
|
|
8935
9157
|
autoComplete: "off",
|
|
8936
|
-
autoCapitalize: "off"
|
|
9158
|
+
autoCapitalize: "off",
|
|
9159
|
+
"data-testid": "custom-sql-textarea"
|
|
8937
9160
|
}
|
|
8938
9161
|
),
|
|
8939
9162
|
validation && !validation.valid && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: validationErrorStyles, children: [
|
|
@@ -8957,6 +9180,7 @@ function CustomSQLEditor({
|
|
|
8957
9180
|
disabled: !canExecute,
|
|
8958
9181
|
style: mergedButtonStyles,
|
|
8959
9182
|
type: "button",
|
|
9183
|
+
"data-testid": "custom-sql-run-button",
|
|
8960
9184
|
children: [
|
|
8961
9185
|
isLoading ? "Executing..." : "Run Query",
|
|
8962
9186
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "11px", opacity: 0.7 }, children: "(Cmd+Enter)" })
|
|
@@ -9158,6 +9382,257 @@ function TableSelector({
|
|
|
9158
9382
|
] })
|
|
9159
9383
|
] });
|
|
9160
9384
|
}
|
|
9385
|
+
function parseContent(content) {
|
|
9386
|
+
const startToken = "```sql";
|
|
9387
|
+
const endToken = "```";
|
|
9388
|
+
const parts = [];
|
|
9389
|
+
let cursor = 0;
|
|
9390
|
+
while (cursor < content.length) {
|
|
9391
|
+
const start = content.indexOf(startToken, cursor);
|
|
9392
|
+
if (start === -1) break;
|
|
9393
|
+
if (start > cursor) {
|
|
9394
|
+
parts.push({ type: "text", value: content.slice(cursor, start) });
|
|
9395
|
+
}
|
|
9396
|
+
const sqlStart = content.indexOf("\n", start + startToken.length);
|
|
9397
|
+
if (sqlStart === -1) break;
|
|
9398
|
+
const end = content.indexOf(endToken, sqlStart + 1);
|
|
9399
|
+
if (end === -1) break;
|
|
9400
|
+
const sql = content.slice(sqlStart + 1, end).trim();
|
|
9401
|
+
if (sql) {
|
|
9402
|
+
parts.push({ type: "sql", value: sql });
|
|
9403
|
+
}
|
|
9404
|
+
cursor = end + endToken.length;
|
|
9405
|
+
}
|
|
9406
|
+
if (cursor < content.length) {
|
|
9407
|
+
parts.push({ type: "text", value: content.slice(cursor) });
|
|
9408
|
+
}
|
|
9409
|
+
return parts;
|
|
9410
|
+
}
|
|
9411
|
+
function ChatBubble({ message, onApplySql }) {
|
|
9412
|
+
const { theme } = chunkLMTG3LRC_cjs.useTheme();
|
|
9413
|
+
const isUser = message.role === "user";
|
|
9414
|
+
const parts = react.useMemo(() => parseContent(message.content), [message.content]);
|
|
9415
|
+
const bubbleStyle = {
|
|
9416
|
+
maxWidth: "85%",
|
|
9417
|
+
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
|
|
9418
|
+
borderRadius: theme.radius.md,
|
|
9419
|
+
fontSize: theme.fontSizes.sm,
|
|
9420
|
+
lineHeight: 1.5,
|
|
9421
|
+
whiteSpace: "pre-wrap",
|
|
9422
|
+
wordBreak: "break-word",
|
|
9423
|
+
alignSelf: isUser ? "flex-end" : "flex-start",
|
|
9424
|
+
backgroundColor: isUser ? theme.colors.primary : theme.colors.surface,
|
|
9425
|
+
color: isUser ? "#fff" : theme.colors.text,
|
|
9426
|
+
border: isUser ? "none" : `1px solid ${theme.colors.border}`
|
|
9427
|
+
};
|
|
9428
|
+
const sqlBlockStyle = {
|
|
9429
|
+
backgroundColor: isUser ? "rgba(0,0,0,0.2)" : theme.colors.background,
|
|
9430
|
+
borderRadius: theme.radius.sm,
|
|
9431
|
+
padding: theme.spacing.sm,
|
|
9432
|
+
margin: `${theme.spacing.xs} 0`,
|
|
9433
|
+
fontFamily: theme.fonts.mono,
|
|
9434
|
+
fontSize: theme.fontSizes.xs,
|
|
9435
|
+
overflow: "auto",
|
|
9436
|
+
position: "relative"
|
|
9437
|
+
};
|
|
9438
|
+
const applyBtnContainerStyle = {
|
|
9439
|
+
display: "flex",
|
|
9440
|
+
justifyContent: "flex-end",
|
|
9441
|
+
marginTop: theme.spacing.xs
|
|
9442
|
+
};
|
|
9443
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: bubbleStyle, children: parts.map((part, i) => {
|
|
9444
|
+
if (part.type === "sql") {
|
|
9445
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-testid": `chat-sql-${i}`, children: [
|
|
9446
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { style: sqlBlockStyle, children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: part.value }) }),
|
|
9447
|
+
onApplySql && /* @__PURE__ */ jsxRuntime.jsx("div", { style: applyBtnContainerStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9448
|
+
Button,
|
|
9449
|
+
{
|
|
9450
|
+
variant: "ghost",
|
|
9451
|
+
size: "sm",
|
|
9452
|
+
onClick: () => onApplySql(part.value),
|
|
9453
|
+
"data-testid": `apply-sql-btn-${i}`,
|
|
9454
|
+
children: "Apply to Editor"
|
|
9455
|
+
}
|
|
9456
|
+
) })
|
|
9457
|
+
] }, i);
|
|
9458
|
+
}
|
|
9459
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { children: part.value }, i);
|
|
9460
|
+
}) });
|
|
9461
|
+
}
|
|
9462
|
+
function ChatPanel({ currentSql, onApplySql }) {
|
|
9463
|
+
const { theme } = chunkLMTG3LRC_cjs.useTheme();
|
|
9464
|
+
const {
|
|
9465
|
+
messages,
|
|
9466
|
+
isStreaming,
|
|
9467
|
+
streamingContent,
|
|
9468
|
+
suggestedSql,
|
|
9469
|
+
sendMessage,
|
|
9470
|
+
clearHistory,
|
|
9471
|
+
error
|
|
9472
|
+
} = useLLMChat();
|
|
9473
|
+
const [input, setInput] = react.useState("");
|
|
9474
|
+
const messagesEndRef = react.useRef(null);
|
|
9475
|
+
react.useEffect(() => {
|
|
9476
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
9477
|
+
}, [messages, streamingContent]);
|
|
9478
|
+
const handleSend = react.useCallback(() => {
|
|
9479
|
+
const trimmed = input.trim();
|
|
9480
|
+
if (!trimmed) return;
|
|
9481
|
+
setInput("");
|
|
9482
|
+
void sendMessage(trimmed, currentSql);
|
|
9483
|
+
}, [input, currentSql, sendMessage]);
|
|
9484
|
+
const handleKeyDown = react.useCallback(
|
|
9485
|
+
(e) => {
|
|
9486
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
9487
|
+
e.preventDefault();
|
|
9488
|
+
handleSend();
|
|
9489
|
+
}
|
|
9490
|
+
},
|
|
9491
|
+
[handleSend]
|
|
9492
|
+
);
|
|
9493
|
+
const containerStyle = {
|
|
9494
|
+
display: "flex",
|
|
9495
|
+
flexDirection: "column",
|
|
9496
|
+
height: "100%",
|
|
9497
|
+
borderLeft: `1px solid ${theme.colors.border}`,
|
|
9498
|
+
backgroundColor: theme.colors.background
|
|
9499
|
+
};
|
|
9500
|
+
const headerStyle = {
|
|
9501
|
+
display: "flex",
|
|
9502
|
+
alignItems: "center",
|
|
9503
|
+
justifyContent: "space-between",
|
|
9504
|
+
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
|
|
9505
|
+
borderBottom: `1px solid ${theme.colors.border}`,
|
|
9506
|
+
flexShrink: 0
|
|
9507
|
+
};
|
|
9508
|
+
const headerTitleStyle = {
|
|
9509
|
+
display: "flex",
|
|
9510
|
+
alignItems: "center",
|
|
9511
|
+
gap: theme.spacing.xs,
|
|
9512
|
+
fontSize: theme.fontSizes.sm,
|
|
9513
|
+
fontWeight: 600,
|
|
9514
|
+
color: theme.colors.text
|
|
9515
|
+
};
|
|
9516
|
+
const messagesStyle = {
|
|
9517
|
+
flex: 1,
|
|
9518
|
+
overflow: "auto",
|
|
9519
|
+
padding: theme.spacing.md,
|
|
9520
|
+
display: "flex",
|
|
9521
|
+
flexDirection: "column",
|
|
9522
|
+
gap: theme.spacing.md
|
|
9523
|
+
};
|
|
9524
|
+
const streamingStyle = {
|
|
9525
|
+
alignSelf: "flex-start",
|
|
9526
|
+
maxWidth: "85%",
|
|
9527
|
+
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
|
|
9528
|
+
borderRadius: theme.radius.md,
|
|
9529
|
+
fontSize: theme.fontSizes.sm,
|
|
9530
|
+
lineHeight: 1.5,
|
|
9531
|
+
whiteSpace: "pre-wrap",
|
|
9532
|
+
wordBreak: "break-word",
|
|
9533
|
+
backgroundColor: theme.colors.surface,
|
|
9534
|
+
color: theme.colors.text,
|
|
9535
|
+
border: `1px solid ${theme.colors.border}`
|
|
9536
|
+
};
|
|
9537
|
+
const suggestedSqlStyle = {
|
|
9538
|
+
padding: theme.spacing.sm,
|
|
9539
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
9540
|
+
display: "flex",
|
|
9541
|
+
alignItems: "center",
|
|
9542
|
+
justifyContent: "center",
|
|
9543
|
+
flexShrink: 0
|
|
9544
|
+
};
|
|
9545
|
+
const inputAreaStyle = {
|
|
9546
|
+
display: "flex",
|
|
9547
|
+
gap: theme.spacing.sm,
|
|
9548
|
+
padding: theme.spacing.sm,
|
|
9549
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
9550
|
+
flexShrink: 0
|
|
9551
|
+
};
|
|
9552
|
+
const textareaStyle = {
|
|
9553
|
+
flex: 1,
|
|
9554
|
+
resize: "none",
|
|
9555
|
+
border: `1px solid ${theme.colors.border}`,
|
|
9556
|
+
borderRadius: theme.radius.sm,
|
|
9557
|
+
padding: theme.spacing.sm,
|
|
9558
|
+
fontSize: theme.fontSizes.sm,
|
|
9559
|
+
fontFamily: theme.fonts.sans,
|
|
9560
|
+
backgroundColor: theme.colors.surface,
|
|
9561
|
+
color: theme.colors.text,
|
|
9562
|
+
outline: "none",
|
|
9563
|
+
minHeight: "36px",
|
|
9564
|
+
maxHeight: "120px"
|
|
9565
|
+
};
|
|
9566
|
+
const emptyStyle = {
|
|
9567
|
+
flex: 1,
|
|
9568
|
+
display: "flex",
|
|
9569
|
+
alignItems: "center",
|
|
9570
|
+
justifyContent: "center",
|
|
9571
|
+
textAlign: "center",
|
|
9572
|
+
padding: theme.spacing.lg,
|
|
9573
|
+
color: theme.colors.textMuted,
|
|
9574
|
+
fontSize: theme.fontSizes.sm
|
|
9575
|
+
};
|
|
9576
|
+
const errorStyle = {
|
|
9577
|
+
padding: theme.spacing.sm,
|
|
9578
|
+
margin: `0 ${theme.spacing.md}`,
|
|
9579
|
+
borderRadius: theme.radius.sm,
|
|
9580
|
+
backgroundColor: "rgba(239, 68, 68, 0.1)",
|
|
9581
|
+
color: "#ef4444",
|
|
9582
|
+
fontSize: theme.fontSizes.xs,
|
|
9583
|
+
flexShrink: 0
|
|
9584
|
+
};
|
|
9585
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyle, className: "prismiq-chat-panel", "data-testid": "chat-panel-root", children: [
|
|
9586
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
|
|
9587
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerTitleStyle, children: [
|
|
9588
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "edit", size: 16 }),
|
|
9589
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "SQL Assistant" })
|
|
9590
|
+
] }),
|
|
9591
|
+
messages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: clearHistory, "data-testid": "chat-clear", children: "Clear" })
|
|
9592
|
+
] }),
|
|
9593
|
+
messages.length === 0 && !isStreaming ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: emptyStyle, "data-testid": "chat-empty", children: [
|
|
9594
|
+
"Ask me to help write SQL queries.",
|
|
9595
|
+
"\n",
|
|
9596
|
+
"I can see your database schema and validate queries."
|
|
9597
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: messagesStyle, "data-testid": "chat-messages", children: [
|
|
9598
|
+
messages.map((msg, i) => /* @__PURE__ */ jsxRuntime.jsx(ChatBubble, { message: msg, onApplySql }, i)),
|
|
9599
|
+
isStreaming && streamingContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: streamingStyle, "data-testid": "chat-streaming", children: [
|
|
9600
|
+
streamingContent,
|
|
9601
|
+
"\u258D"
|
|
9602
|
+
] }),
|
|
9603
|
+
isStreaming && !streamingContent && /* @__PURE__ */ jsxRuntime.jsx("div", { style: streamingStyle, "data-testid": "chat-streaming", children: "Thinking..." }),
|
|
9604
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
|
|
9605
|
+
] }),
|
|
9606
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorStyle, "data-testid": "chat-error", children: error }),
|
|
9607
|
+
suggestedSql && !isStreaming && /* @__PURE__ */ jsxRuntime.jsx("div", { style: suggestedSqlStyle, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", size: "sm", onClick: () => onApplySql(suggestedSql), "data-testid": "chat-apply-sql", children: "Apply SQL to Editor" }) }),
|
|
9608
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: inputAreaStyle, children: [
|
|
9609
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9610
|
+
"textarea",
|
|
9611
|
+
{
|
|
9612
|
+
style: textareaStyle,
|
|
9613
|
+
value: input,
|
|
9614
|
+
onChange: (e) => setInput(e.target.value),
|
|
9615
|
+
onKeyDown: handleKeyDown,
|
|
9616
|
+
placeholder: "Ask about your data...",
|
|
9617
|
+
rows: 1,
|
|
9618
|
+
disabled: isStreaming,
|
|
9619
|
+
"data-testid": "chat-input"
|
|
9620
|
+
}
|
|
9621
|
+
),
|
|
9622
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9623
|
+
Button,
|
|
9624
|
+
{
|
|
9625
|
+
variant: "primary",
|
|
9626
|
+
size: "sm",
|
|
9627
|
+
onClick: handleSend,
|
|
9628
|
+
disabled: isStreaming || !input.trim(),
|
|
9629
|
+
"data-testid": "chat-send",
|
|
9630
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "play", size: 16 })
|
|
9631
|
+
}
|
|
9632
|
+
)
|
|
9633
|
+
] })
|
|
9634
|
+
] });
|
|
9635
|
+
}
|
|
9161
9636
|
|
|
9162
9637
|
exports.AggregationPicker = AggregationPicker;
|
|
9163
9638
|
exports.AnalyticsProvider = AnalyticsProvider;
|
|
@@ -9165,6 +9640,8 @@ exports.AutoSaveIndicator = AutoSaveIndicator;
|
|
|
9165
9640
|
exports.Badge = Badge;
|
|
9166
9641
|
exports.Button = Button;
|
|
9167
9642
|
exports.CalculatedFieldBuilder = CalculatedFieldBuilder;
|
|
9643
|
+
exports.ChatBubble = ChatBubble;
|
|
9644
|
+
exports.ChatPanel = ChatPanel;
|
|
9168
9645
|
exports.Checkbox = Checkbox;
|
|
9169
9646
|
exports.CollapsibleSection = CollapsibleSection;
|
|
9170
9647
|
exports.ColorPaletteSelector = ColorPaletteSelector;
|
|
@@ -9228,10 +9705,12 @@ exports.useDashboardMutations = useDashboardMutations;
|
|
|
9228
9705
|
exports.useDashboardPinStatus = useDashboardPinStatus;
|
|
9229
9706
|
exports.useDashboards = useDashboards;
|
|
9230
9707
|
exports.useDebouncedLayoutSave = useDebouncedLayoutSave;
|
|
9708
|
+
exports.useLLMChat = useLLMChat;
|
|
9709
|
+
exports.useLLMStatus = useLLMStatus;
|
|
9231
9710
|
exports.usePinMutations = usePinMutations;
|
|
9232
9711
|
exports.usePinnedDashboards = usePinnedDashboards;
|
|
9233
9712
|
exports.useQuery = useQuery;
|
|
9234
9713
|
exports.useSavedQueries = useSavedQueries;
|
|
9235
9714
|
exports.useSchema = useSchema;
|
|
9236
|
-
//# sourceMappingURL=chunk-
|
|
9237
|
-
//# sourceMappingURL=chunk-
|
|
9715
|
+
//# sourceMappingURL=chunk-PG7QBH3G.cjs.map
|
|
9716
|
+
//# sourceMappingURL=chunk-PG7QBH3G.cjs.map
|