@prismiq/react 0.1.1 → 0.2.1
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-CYlOtecq.d.ts → ChatBubble-3mFpV7yX.d.ts} +42 -3
- package/dist/{CustomSQLEditor-d84v_Cgp.d.cts → ChatBubble-CMkEupzn.d.cts} +42 -3
- package/dist/{DashboardDialog-DBNTVVSp.d.ts → DashboardDialog-DMmZ3bnf.d.cts} +5 -3
- package/dist/{DashboardDialog-CZD8I-6z.d.cts → DashboardDialog-RlcPkdMt.d.ts} +5 -3
- package/dist/charts/index.d.cts +2 -2
- package/dist/charts/index.d.ts +2 -2
- package/dist/{chunk-3LDRRDJ6.js → chunk-F6QYNQEW.js} +194 -28
- package/dist/chunk-F6QYNQEW.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-VQDFS6VS.cjs → chunk-N6I3QOHG.cjs} +376 -210
- package/dist/chunk-N6I3QOHG.cjs.map +1 -0
- package/dist/{chunk-URJH4H6G.cjs → chunk-NXXKG4GN.cjs} +520 -6
- package/dist/chunk-NXXKG4GN.cjs.map +1 -0
- package/dist/{chunk-ET7GCREP.js → chunk-VEFYFB5H.js} +517 -7
- package/dist/chunk-VEFYFB5H.js.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-BA2VUhgN.d.cts} +1 -1
- package/dist/{index-DXGLs1yY.d.ts → index-BPo89ZAj.d.ts} +1 -1
- package/dist/index.cjs +119 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -7
- package/dist/index.d.ts +77 -7
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/{types-j0kPJ9Hz.d.cts → types-BaI6sSAG.d.cts} +62 -1
- package/dist/{types-j0kPJ9Hz.d.ts → types-BaI6sSAG.d.ts} +62 -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,88 @@ 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
|
+
* @param widgetContext - Optional widget context for targeted SQL generation.
|
|
2865
|
+
* @yields StreamChunk objects as the response is generated.
|
|
2866
|
+
*/
|
|
2867
|
+
async *streamChat(message, history, currentSql, signal, widgetContext) {
|
|
2868
|
+
const url = `${this.endpoint}/llm/chat`;
|
|
2869
|
+
const headers = {
|
|
2870
|
+
"Content-Type": "application/json",
|
|
2871
|
+
"X-Tenant-ID": this.tenantId
|
|
2872
|
+
};
|
|
2873
|
+
if (this.userId) headers["X-User-ID"] = this.userId;
|
|
2874
|
+
if (this.schemaName) headers["X-Schema-Name"] = this.schemaName;
|
|
2875
|
+
if (this.customHeaders) Object.assign(headers, this.customHeaders);
|
|
2876
|
+
if (this.getToken) {
|
|
2877
|
+
const token = await this.getToken();
|
|
2878
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
2879
|
+
}
|
|
2880
|
+
const body = {
|
|
2881
|
+
message,
|
|
2882
|
+
history,
|
|
2883
|
+
current_sql: currentSql
|
|
2884
|
+
};
|
|
2885
|
+
if (widgetContext) {
|
|
2886
|
+
body.widget_context = widgetContext;
|
|
2887
|
+
}
|
|
2888
|
+
const response = await fetch(url, {
|
|
2889
|
+
method: "POST",
|
|
2890
|
+
headers,
|
|
2891
|
+
body: JSON.stringify(body),
|
|
2892
|
+
signal
|
|
2893
|
+
});
|
|
2894
|
+
if (!response.ok) {
|
|
2895
|
+
throw new PrismiqError(
|
|
2896
|
+
`LLM chat failed: ${response.status} ${response.statusText}`,
|
|
2897
|
+
response.status
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
const reader = response.body?.getReader();
|
|
2901
|
+
if (!reader) return;
|
|
2902
|
+
const decoder = new TextDecoder();
|
|
2903
|
+
let buffer = "";
|
|
2904
|
+
try {
|
|
2905
|
+
while (true) {
|
|
2906
|
+
const { done, value } = await reader.read();
|
|
2907
|
+
if (done) break;
|
|
2908
|
+
buffer += decoder.decode(value, { stream: true });
|
|
2909
|
+
const lines = buffer.split("\n");
|
|
2910
|
+
buffer = lines.pop() ?? "";
|
|
2911
|
+
for (const line of lines) {
|
|
2912
|
+
if (line.startsWith("data: ")) {
|
|
2913
|
+
const data = line.slice(6).trim();
|
|
2914
|
+
if (data) {
|
|
2915
|
+
try {
|
|
2916
|
+
const chunk = JSON.parse(data);
|
|
2917
|
+
yield chunk;
|
|
2918
|
+
} catch {
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
} finally {
|
|
2925
|
+
reader.releaseLock();
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2846
2928
|
};
|
|
2847
2929
|
var AnalyticsContext = react.createContext(null);
|
|
2848
2930
|
var CallbacksContext = react.createContext({});
|
|
@@ -3900,6 +3982,151 @@ function CrossFilterProvider({
|
|
|
3900
3982
|
function useCrossFilterOptional() {
|
|
3901
3983
|
return react.useContext(CrossFilterContext);
|
|
3902
3984
|
}
|
|
3985
|
+
|
|
3986
|
+
// src/hooks/useLLMStatus.ts
|
|
3987
|
+
function useLLMStatus() {
|
|
3988
|
+
const { client } = useAnalytics();
|
|
3989
|
+
const [status, setStatus] = react.useState({ enabled: false });
|
|
3990
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
3991
|
+
const [error, setError] = react.useState(null);
|
|
3992
|
+
react.useEffect(() => {
|
|
3993
|
+
if (!client) {
|
|
3994
|
+
setIsLoading(false);
|
|
3995
|
+
return;
|
|
3996
|
+
}
|
|
3997
|
+
let cancelled = false;
|
|
3998
|
+
client.getLLMStatus().then((result) => {
|
|
3999
|
+
if (!cancelled) {
|
|
4000
|
+
setStatus(result);
|
|
4001
|
+
setError(null);
|
|
4002
|
+
}
|
|
4003
|
+
}).catch((err) => {
|
|
4004
|
+
if (!cancelled) {
|
|
4005
|
+
setStatus({ enabled: false });
|
|
4006
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
4007
|
+
}
|
|
4008
|
+
}).finally(() => {
|
|
4009
|
+
if (!cancelled) setIsLoading(false);
|
|
4010
|
+
});
|
|
4011
|
+
return () => {
|
|
4012
|
+
cancelled = true;
|
|
4013
|
+
};
|
|
4014
|
+
}, [client]);
|
|
4015
|
+
return {
|
|
4016
|
+
enabled: status.enabled,
|
|
4017
|
+
provider: status.provider,
|
|
4018
|
+
model: status.model,
|
|
4019
|
+
isLoading,
|
|
4020
|
+
error
|
|
4021
|
+
};
|
|
4022
|
+
}
|
|
4023
|
+
function useLLMChat() {
|
|
4024
|
+
const { client } = useAnalytics();
|
|
4025
|
+
const [messages, setMessages] = react.useState([]);
|
|
4026
|
+
const [isStreaming, setIsStreaming] = react.useState(false);
|
|
4027
|
+
const [streamingContent, setStreamingContent] = react.useState("");
|
|
4028
|
+
const [suggestedSql, setSuggestedSql] = react.useState(null);
|
|
4029
|
+
const [error, setError] = react.useState(null);
|
|
4030
|
+
const [statusMessage, setStatusMessage] = react.useState(null);
|
|
4031
|
+
const abortRef = react.useRef(null);
|
|
4032
|
+
const isStreamingRef = react.useRef(false);
|
|
4033
|
+
const messagesRef = react.useRef([]);
|
|
4034
|
+
messagesRef.current = messages;
|
|
4035
|
+
const sendMessage = react.useCallback(
|
|
4036
|
+
async (message, currentSql, widgetContext) => {
|
|
4037
|
+
if (!client || isStreamingRef.current) return;
|
|
4038
|
+
abortRef.current?.abort();
|
|
4039
|
+
const controller = new AbortController();
|
|
4040
|
+
abortRef.current = controller;
|
|
4041
|
+
const userMsg = { role: "user", content: message };
|
|
4042
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
4043
|
+
isStreamingRef.current = true;
|
|
4044
|
+
setIsStreaming(true);
|
|
4045
|
+
setStreamingContent("");
|
|
4046
|
+
setSuggestedSql(null);
|
|
4047
|
+
setError(null);
|
|
4048
|
+
setStatusMessage(null);
|
|
4049
|
+
let accumulatedText = "";
|
|
4050
|
+
let lastSql = null;
|
|
4051
|
+
try {
|
|
4052
|
+
const history = messagesRef.current.map((m) => ({
|
|
4053
|
+
role: m.role,
|
|
4054
|
+
content: m.content
|
|
4055
|
+
}));
|
|
4056
|
+
for await (const chunk of client.streamChat(
|
|
4057
|
+
message,
|
|
4058
|
+
history,
|
|
4059
|
+
currentSql,
|
|
4060
|
+
controller.signal,
|
|
4061
|
+
widgetContext
|
|
4062
|
+
)) {
|
|
4063
|
+
if (controller.signal.aborted) break;
|
|
4064
|
+
switch (chunk.type) {
|
|
4065
|
+
case "text":
|
|
4066
|
+
accumulatedText += chunk.content ?? "";
|
|
4067
|
+
setStreamingContent(accumulatedText);
|
|
4068
|
+
setStatusMessage(null);
|
|
4069
|
+
break;
|
|
4070
|
+
case "sql":
|
|
4071
|
+
lastSql = chunk.content ?? null;
|
|
4072
|
+
setSuggestedSql(lastSql);
|
|
4073
|
+
break;
|
|
4074
|
+
case "status":
|
|
4075
|
+
setStatusMessage(chunk.content ?? null);
|
|
4076
|
+
break;
|
|
4077
|
+
case "error":
|
|
4078
|
+
setError(chunk.content ?? "Unknown error");
|
|
4079
|
+
break;
|
|
4080
|
+
case "done":
|
|
4081
|
+
setStatusMessage(null);
|
|
4082
|
+
break;
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
4085
|
+
} catch (err) {
|
|
4086
|
+
if (err instanceof Error && err.name !== "AbortError") {
|
|
4087
|
+
setError(err.message);
|
|
4088
|
+
}
|
|
4089
|
+
} finally {
|
|
4090
|
+
isStreamingRef.current = false;
|
|
4091
|
+
setIsStreaming(false);
|
|
4092
|
+
setStatusMessage(null);
|
|
4093
|
+
if (accumulatedText) {
|
|
4094
|
+
const assistantMsg = {
|
|
4095
|
+
role: "assistant",
|
|
4096
|
+
content: accumulatedText
|
|
4097
|
+
};
|
|
4098
|
+
setMessages((prev) => [...prev, assistantMsg]);
|
|
4099
|
+
}
|
|
4100
|
+
setStreamingContent("");
|
|
4101
|
+
}
|
|
4102
|
+
},
|
|
4103
|
+
[client]
|
|
4104
|
+
);
|
|
4105
|
+
react.useEffect(() => {
|
|
4106
|
+
return () => {
|
|
4107
|
+
abortRef.current?.abort();
|
|
4108
|
+
};
|
|
4109
|
+
}, []);
|
|
4110
|
+
const clearHistory = react.useCallback(() => {
|
|
4111
|
+
abortRef.current?.abort();
|
|
4112
|
+
setMessages([]);
|
|
4113
|
+
setStreamingContent("");
|
|
4114
|
+
setSuggestedSql(null);
|
|
4115
|
+
setError(null);
|
|
4116
|
+
setIsStreaming(false);
|
|
4117
|
+
setStatusMessage(null);
|
|
4118
|
+
}, []);
|
|
4119
|
+
return {
|
|
4120
|
+
messages,
|
|
4121
|
+
isStreaming,
|
|
4122
|
+
streamingContent,
|
|
4123
|
+
suggestedSql,
|
|
4124
|
+
sendMessage,
|
|
4125
|
+
clearHistory,
|
|
4126
|
+
error,
|
|
4127
|
+
statusMessage
|
|
4128
|
+
};
|
|
4129
|
+
}
|
|
3903
4130
|
var nodeStyles = {
|
|
3904
4131
|
display: "flex",
|
|
3905
4132
|
alignItems: "center",
|
|
@@ -4362,6 +4589,7 @@ function SchemaExplorer({
|
|
|
4362
4589
|
selectedColumns = [],
|
|
4363
4590
|
searchable = true,
|
|
4364
4591
|
collapsible = true,
|
|
4592
|
+
headerAction,
|
|
4365
4593
|
className,
|
|
4366
4594
|
style
|
|
4367
4595
|
}) {
|
|
@@ -4397,10 +4625,12 @@ function SchemaExplorer({
|
|
|
4397
4625
|
style: { ...containerStyles4, ...style },
|
|
4398
4626
|
role: "tree",
|
|
4399
4627
|
"aria-label": "Database schema",
|
|
4628
|
+
"data-testid": "schema-explorer-root",
|
|
4400
4629
|
children: [
|
|
4401
4630
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyles2, children: [
|
|
4402
4631
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "table", size: 16, style: { color: "var(--prismiq-color-primary)" } }),
|
|
4403
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: titleStyles2, children: "Schema Explorer" })
|
|
4632
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...titleStyles2, flex: 1 }, children: "Schema Explorer" }),
|
|
4633
|
+
headerAction
|
|
4404
4634
|
] }),
|
|
4405
4635
|
searchable && /* @__PURE__ */ jsxRuntime.jsx("div", { style: searchContainerStyles, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4406
4636
|
Input,
|
|
@@ -4409,7 +4639,8 @@ function SchemaExplorer({
|
|
|
4409
4639
|
placeholder: "Search tables and columns...",
|
|
4410
4640
|
value: searchQuery,
|
|
4411
4641
|
onChange: (e) => setSearchQuery(e.target.value),
|
|
4412
|
-
style: { width: "100%" }
|
|
4642
|
+
style: { width: "100%" },
|
|
4643
|
+
"data-testid": "schema-explorer-search"
|
|
4413
4644
|
}
|
|
4414
4645
|
) }),
|
|
4415
4646
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: treeContainerStyles, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(LoadingSkeleton, {}) : error ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: errorStyles2, children: [
|
|
@@ -8873,7 +9104,14 @@ function CustomSQLEditor({
|
|
|
8873
9104
|
style
|
|
8874
9105
|
}) {
|
|
8875
9106
|
const [sql, setSql] = react.useState(initialSql);
|
|
9107
|
+
const prevInitialSqlRef = react.useRef(initialSql);
|
|
8876
9108
|
const [isFocused, setIsFocused] = react.useState(false);
|
|
9109
|
+
react.useEffect(() => {
|
|
9110
|
+
if (initialSql !== prevInitialSqlRef.current) {
|
|
9111
|
+
prevInitialSqlRef.current = initialSql;
|
|
9112
|
+
setSql(initialSql);
|
|
9113
|
+
}
|
|
9114
|
+
}, [initialSql]);
|
|
8877
9115
|
const [executeEnabled, setExecuteEnabled] = react.useState(false);
|
|
8878
9116
|
const [lastExecutedSql, setLastExecutedSql] = react.useState(null);
|
|
8879
9117
|
const {
|
|
@@ -8919,7 +9157,7 @@ function CustomSQLEditor({
|
|
|
8919
9157
|
...buttonStyles,
|
|
8920
9158
|
...canExecute ? {} : buttonDisabledStyles
|
|
8921
9159
|
};
|
|
8922
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...containerStyles17, ...style }, children: [
|
|
9160
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...containerStyles17, ...style }, "data-testid": "custom-sql-editor", children: [
|
|
8923
9161
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: editorWrapperStyles, children: [
|
|
8924
9162
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8925
9163
|
"textarea",
|
|
@@ -8933,7 +9171,8 @@ function CustomSQLEditor({
|
|
|
8933
9171
|
style: mergedTextareaStyles,
|
|
8934
9172
|
spellCheck: false,
|
|
8935
9173
|
autoComplete: "off",
|
|
8936
|
-
autoCapitalize: "off"
|
|
9174
|
+
autoCapitalize: "off",
|
|
9175
|
+
"data-testid": "custom-sql-textarea"
|
|
8937
9176
|
}
|
|
8938
9177
|
),
|
|
8939
9178
|
validation && !validation.valid && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: validationErrorStyles, children: [
|
|
@@ -8957,6 +9196,7 @@ function CustomSQLEditor({
|
|
|
8957
9196
|
disabled: !canExecute,
|
|
8958
9197
|
style: mergedButtonStyles,
|
|
8959
9198
|
type: "button",
|
|
9199
|
+
"data-testid": "custom-sql-run-button",
|
|
8960
9200
|
children: [
|
|
8961
9201
|
isLoading ? "Executing..." : "Run Query",
|
|
8962
9202
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "11px", opacity: 0.7 }, children: "(Cmd+Enter)" })
|
|
@@ -9158,6 +9398,276 @@ function TableSelector({
|
|
|
9158
9398
|
] })
|
|
9159
9399
|
] });
|
|
9160
9400
|
}
|
|
9401
|
+
function parseContent(content) {
|
|
9402
|
+
const startToken = "```sql";
|
|
9403
|
+
const endToken = "```";
|
|
9404
|
+
const parts = [];
|
|
9405
|
+
let cursor = 0;
|
|
9406
|
+
while (cursor < content.length) {
|
|
9407
|
+
const start = content.indexOf(startToken, cursor);
|
|
9408
|
+
if (start === -1) break;
|
|
9409
|
+
if (start > cursor) {
|
|
9410
|
+
parts.push({ type: "text", value: content.slice(cursor, start) });
|
|
9411
|
+
}
|
|
9412
|
+
const sqlStart = content.indexOf("\n", start + startToken.length);
|
|
9413
|
+
if (sqlStart === -1) break;
|
|
9414
|
+
const end = content.indexOf(endToken, sqlStart + 1);
|
|
9415
|
+
if (end === -1) break;
|
|
9416
|
+
const sql = content.slice(sqlStart + 1, end).trim();
|
|
9417
|
+
if (sql) {
|
|
9418
|
+
parts.push({ type: "sql", value: sql });
|
|
9419
|
+
}
|
|
9420
|
+
cursor = end + endToken.length;
|
|
9421
|
+
}
|
|
9422
|
+
if (cursor < content.length) {
|
|
9423
|
+
parts.push({ type: "text", value: content.slice(cursor) });
|
|
9424
|
+
}
|
|
9425
|
+
return parts;
|
|
9426
|
+
}
|
|
9427
|
+
function ChatBubble({ message, onApplySql }) {
|
|
9428
|
+
const { theme } = chunkLMTG3LRC_cjs.useTheme();
|
|
9429
|
+
const isUser = message.role === "user";
|
|
9430
|
+
const parts = react.useMemo(() => parseContent(message.content), [message.content]);
|
|
9431
|
+
const bubbleStyle = {
|
|
9432
|
+
maxWidth: "85%",
|
|
9433
|
+
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
|
|
9434
|
+
borderRadius: theme.radius.md,
|
|
9435
|
+
fontSize: theme.fontSizes.sm,
|
|
9436
|
+
lineHeight: 1.5,
|
|
9437
|
+
whiteSpace: "pre-wrap",
|
|
9438
|
+
wordBreak: "break-word",
|
|
9439
|
+
alignSelf: isUser ? "flex-end" : "flex-start",
|
|
9440
|
+
backgroundColor: isUser ? theme.colors.primary : theme.colors.surface,
|
|
9441
|
+
color: isUser ? "#fff" : theme.colors.text,
|
|
9442
|
+
border: isUser ? "none" : `1px solid ${theme.colors.border}`
|
|
9443
|
+
};
|
|
9444
|
+
const sqlBlockStyle = {
|
|
9445
|
+
backgroundColor: isUser ? "rgba(0,0,0,0.2)" : theme.colors.background,
|
|
9446
|
+
borderRadius: theme.radius.sm,
|
|
9447
|
+
padding: theme.spacing.sm,
|
|
9448
|
+
margin: `${theme.spacing.xs} 0`,
|
|
9449
|
+
fontFamily: theme.fonts.mono,
|
|
9450
|
+
fontSize: theme.fontSizes.xs,
|
|
9451
|
+
overflow: "auto",
|
|
9452
|
+
position: "relative"
|
|
9453
|
+
};
|
|
9454
|
+
const applyBtnContainerStyle = {
|
|
9455
|
+
display: "flex",
|
|
9456
|
+
justifyContent: "flex-end",
|
|
9457
|
+
marginTop: theme.spacing.xs
|
|
9458
|
+
};
|
|
9459
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: bubbleStyle, children: parts.map((part, i) => {
|
|
9460
|
+
if (part.type === "sql") {
|
|
9461
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-testid": `chat-sql-${i}`, children: [
|
|
9462
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { style: sqlBlockStyle, children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: part.value }) }),
|
|
9463
|
+
onApplySql && /* @__PURE__ */ jsxRuntime.jsx("div", { style: applyBtnContainerStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9464
|
+
Button,
|
|
9465
|
+
{
|
|
9466
|
+
variant: "ghost",
|
|
9467
|
+
size: "sm",
|
|
9468
|
+
onClick: () => onApplySql(part.value),
|
|
9469
|
+
"data-testid": `apply-sql-btn-${i}`,
|
|
9470
|
+
children: "Apply to Editor"
|
|
9471
|
+
}
|
|
9472
|
+
) })
|
|
9473
|
+
] }, i);
|
|
9474
|
+
}
|
|
9475
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { children: part.value }, i);
|
|
9476
|
+
}) });
|
|
9477
|
+
}
|
|
9478
|
+
function ChatPanel({ currentSql, onApplySql, widgetContext }) {
|
|
9479
|
+
const { theme } = chunkLMTG3LRC_cjs.useTheme();
|
|
9480
|
+
const {
|
|
9481
|
+
messages,
|
|
9482
|
+
isStreaming,
|
|
9483
|
+
streamingContent,
|
|
9484
|
+
suggestedSql,
|
|
9485
|
+
sendMessage,
|
|
9486
|
+
clearHistory,
|
|
9487
|
+
error,
|
|
9488
|
+
statusMessage
|
|
9489
|
+
} = useLLMChat();
|
|
9490
|
+
const [input, setInput] = react.useState("");
|
|
9491
|
+
const messagesEndRef = react.useRef(null);
|
|
9492
|
+
react.useEffect(() => {
|
|
9493
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
9494
|
+
}, [messages, streamingContent]);
|
|
9495
|
+
const handleSend = react.useCallback(() => {
|
|
9496
|
+
const trimmed = input.trim();
|
|
9497
|
+
if (!trimmed) return;
|
|
9498
|
+
setInput("");
|
|
9499
|
+
void sendMessage(trimmed, currentSql, widgetContext);
|
|
9500
|
+
}, [input, currentSql, widgetContext, sendMessage]);
|
|
9501
|
+
const handleKeyDown = react.useCallback(
|
|
9502
|
+
(e) => {
|
|
9503
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
9504
|
+
e.preventDefault();
|
|
9505
|
+
handleSend();
|
|
9506
|
+
}
|
|
9507
|
+
},
|
|
9508
|
+
[handleSend]
|
|
9509
|
+
);
|
|
9510
|
+
const containerStyle = {
|
|
9511
|
+
display: "flex",
|
|
9512
|
+
flexDirection: "column",
|
|
9513
|
+
height: "100%",
|
|
9514
|
+
borderLeft: `1px solid ${theme.colors.border}`,
|
|
9515
|
+
backgroundColor: theme.colors.background
|
|
9516
|
+
};
|
|
9517
|
+
const headerStyle = {
|
|
9518
|
+
display: "flex",
|
|
9519
|
+
alignItems: "center",
|
|
9520
|
+
justifyContent: "space-between",
|
|
9521
|
+
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
|
|
9522
|
+
borderBottom: `1px solid ${theme.colors.border}`,
|
|
9523
|
+
flexShrink: 0
|
|
9524
|
+
};
|
|
9525
|
+
const headerTitleStyle = {
|
|
9526
|
+
display: "flex",
|
|
9527
|
+
alignItems: "center",
|
|
9528
|
+
gap: theme.spacing.xs,
|
|
9529
|
+
fontSize: theme.fontSizes.sm,
|
|
9530
|
+
fontWeight: 600,
|
|
9531
|
+
color: theme.colors.text
|
|
9532
|
+
};
|
|
9533
|
+
const messagesStyle = {
|
|
9534
|
+
flex: 1,
|
|
9535
|
+
overflow: "auto",
|
|
9536
|
+
padding: theme.spacing.md,
|
|
9537
|
+
display: "flex",
|
|
9538
|
+
flexDirection: "column",
|
|
9539
|
+
gap: theme.spacing.md
|
|
9540
|
+
};
|
|
9541
|
+
const streamingStyle = {
|
|
9542
|
+
alignSelf: "flex-start",
|
|
9543
|
+
maxWidth: "85%",
|
|
9544
|
+
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
|
|
9545
|
+
borderRadius: theme.radius.md,
|
|
9546
|
+
fontSize: theme.fontSizes.sm,
|
|
9547
|
+
lineHeight: 1.5,
|
|
9548
|
+
whiteSpace: "pre-wrap",
|
|
9549
|
+
wordBreak: "break-word",
|
|
9550
|
+
backgroundColor: theme.colors.surface,
|
|
9551
|
+
color: theme.colors.text,
|
|
9552
|
+
border: `1px solid ${theme.colors.border}`
|
|
9553
|
+
};
|
|
9554
|
+
const suggestedSqlStyle = {
|
|
9555
|
+
padding: theme.spacing.sm,
|
|
9556
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
9557
|
+
display: "flex",
|
|
9558
|
+
alignItems: "center",
|
|
9559
|
+
justifyContent: "center",
|
|
9560
|
+
flexShrink: 0
|
|
9561
|
+
};
|
|
9562
|
+
const inputAreaStyle = {
|
|
9563
|
+
display: "flex",
|
|
9564
|
+
gap: theme.spacing.sm,
|
|
9565
|
+
padding: theme.spacing.sm,
|
|
9566
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
9567
|
+
flexShrink: 0
|
|
9568
|
+
};
|
|
9569
|
+
const textareaStyle = {
|
|
9570
|
+
flex: 1,
|
|
9571
|
+
resize: "none",
|
|
9572
|
+
border: `1px solid ${theme.colors.border}`,
|
|
9573
|
+
borderRadius: theme.radius.sm,
|
|
9574
|
+
padding: theme.spacing.sm,
|
|
9575
|
+
fontSize: theme.fontSizes.sm,
|
|
9576
|
+
fontFamily: theme.fonts.sans,
|
|
9577
|
+
backgroundColor: theme.colors.surface,
|
|
9578
|
+
color: theme.colors.text,
|
|
9579
|
+
outline: "none",
|
|
9580
|
+
minHeight: "36px",
|
|
9581
|
+
maxHeight: "120px"
|
|
9582
|
+
};
|
|
9583
|
+
const emptyStyle = {
|
|
9584
|
+
flex: 1,
|
|
9585
|
+
display: "flex",
|
|
9586
|
+
alignItems: "center",
|
|
9587
|
+
justifyContent: "center",
|
|
9588
|
+
textAlign: "center",
|
|
9589
|
+
padding: theme.spacing.lg,
|
|
9590
|
+
color: theme.colors.textMuted,
|
|
9591
|
+
fontSize: theme.fontSizes.sm
|
|
9592
|
+
};
|
|
9593
|
+
const errorStyle = {
|
|
9594
|
+
padding: theme.spacing.sm,
|
|
9595
|
+
margin: `0 ${theme.spacing.md}`,
|
|
9596
|
+
borderRadius: theme.radius.sm,
|
|
9597
|
+
backgroundColor: "rgba(239, 68, 68, 0.1)",
|
|
9598
|
+
color: "#ef4444",
|
|
9599
|
+
fontSize: theme.fontSizes.xs,
|
|
9600
|
+
flexShrink: 0
|
|
9601
|
+
};
|
|
9602
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyle, className: "prismiq-chat-panel", "data-testid": "chat-panel-root", children: [
|
|
9603
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
|
|
9604
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerTitleStyle, children: [
|
|
9605
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "edit", size: 16 }),
|
|
9606
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "SQL Assistant" })
|
|
9607
|
+
] }),
|
|
9608
|
+
messages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: clearHistory, "data-testid": "chat-clear", children: "Clear" })
|
|
9609
|
+
] }),
|
|
9610
|
+
messages.length === 0 && !isStreaming ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: emptyStyle, "data-testid": "chat-empty", children: [
|
|
9611
|
+
"Ask me to help write SQL queries.",
|
|
9612
|
+
"\n",
|
|
9613
|
+
"I can see your database schema and validate queries."
|
|
9614
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: messagesStyle, "data-testid": "chat-messages", children: [
|
|
9615
|
+
messages.map((msg, i) => /* @__PURE__ */ jsxRuntime.jsx(ChatBubble, { message: msg, onApplySql }, i)),
|
|
9616
|
+
isStreaming && streamingContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: streamingStyle, "data-testid": "chat-streaming", children: [
|
|
9617
|
+
streamingContent,
|
|
9618
|
+
"\u258D"
|
|
9619
|
+
] }),
|
|
9620
|
+
isStreaming && !streamingContent && /* @__PURE__ */ jsxRuntime.jsx("div", { style: streamingStyle, "data-testid": "chat-streaming", children: "Thinking..." }),
|
|
9621
|
+
isStreaming && statusMessage && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9622
|
+
"div",
|
|
9623
|
+
{
|
|
9624
|
+
style: {
|
|
9625
|
+
display: "flex",
|
|
9626
|
+
alignItems: "center",
|
|
9627
|
+
gap: theme.spacing.xs,
|
|
9628
|
+
fontSize: theme.fontSizes.xs,
|
|
9629
|
+
color: theme.colors.textMuted,
|
|
9630
|
+
padding: `${theme.spacing.xs} 0`
|
|
9631
|
+
},
|
|
9632
|
+
"data-testid": "chat-status",
|
|
9633
|
+
children: [
|
|
9634
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "sync", size: 12 }),
|
|
9635
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: statusMessage })
|
|
9636
|
+
]
|
|
9637
|
+
}
|
|
9638
|
+
),
|
|
9639
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
|
|
9640
|
+
] }),
|
|
9641
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorStyle, "data-testid": "chat-error", children: error }),
|
|
9642
|
+
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" }) }),
|
|
9643
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: inputAreaStyle, children: [
|
|
9644
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9645
|
+
"textarea",
|
|
9646
|
+
{
|
|
9647
|
+
style: textareaStyle,
|
|
9648
|
+
value: input,
|
|
9649
|
+
onChange: (e) => setInput(e.target.value),
|
|
9650
|
+
onKeyDown: handleKeyDown,
|
|
9651
|
+
placeholder: "Ask about your data...",
|
|
9652
|
+
rows: 1,
|
|
9653
|
+
disabled: isStreaming,
|
|
9654
|
+
"data-testid": "chat-input"
|
|
9655
|
+
}
|
|
9656
|
+
),
|
|
9657
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9658
|
+
Button,
|
|
9659
|
+
{
|
|
9660
|
+
variant: "primary",
|
|
9661
|
+
size: "sm",
|
|
9662
|
+
onClick: handleSend,
|
|
9663
|
+
disabled: isStreaming || !input.trim(),
|
|
9664
|
+
"data-testid": "chat-send",
|
|
9665
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "play", size: 16 })
|
|
9666
|
+
}
|
|
9667
|
+
)
|
|
9668
|
+
] })
|
|
9669
|
+
] });
|
|
9670
|
+
}
|
|
9161
9671
|
|
|
9162
9672
|
exports.AggregationPicker = AggregationPicker;
|
|
9163
9673
|
exports.AnalyticsProvider = AnalyticsProvider;
|
|
@@ -9165,6 +9675,8 @@ exports.AutoSaveIndicator = AutoSaveIndicator;
|
|
|
9165
9675
|
exports.Badge = Badge;
|
|
9166
9676
|
exports.Button = Button;
|
|
9167
9677
|
exports.CalculatedFieldBuilder = CalculatedFieldBuilder;
|
|
9678
|
+
exports.ChatBubble = ChatBubble;
|
|
9679
|
+
exports.ChatPanel = ChatPanel;
|
|
9168
9680
|
exports.Checkbox = Checkbox;
|
|
9169
9681
|
exports.CollapsibleSection = CollapsibleSection;
|
|
9170
9682
|
exports.ColorPaletteSelector = ColorPaletteSelector;
|
|
@@ -9228,10 +9740,12 @@ exports.useDashboardMutations = useDashboardMutations;
|
|
|
9228
9740
|
exports.useDashboardPinStatus = useDashboardPinStatus;
|
|
9229
9741
|
exports.useDashboards = useDashboards;
|
|
9230
9742
|
exports.useDebouncedLayoutSave = useDebouncedLayoutSave;
|
|
9743
|
+
exports.useLLMChat = useLLMChat;
|
|
9744
|
+
exports.useLLMStatus = useLLMStatus;
|
|
9231
9745
|
exports.usePinMutations = usePinMutations;
|
|
9232
9746
|
exports.usePinnedDashboards = usePinnedDashboards;
|
|
9233
9747
|
exports.useQuery = useQuery;
|
|
9234
9748
|
exports.useSavedQueries = useSavedQueries;
|
|
9235
9749
|
exports.useSchema = useSchema;
|
|
9236
|
-
//# sourceMappingURL=chunk-
|
|
9237
|
-
//# sourceMappingURL=chunk-
|
|
9750
|
+
//# sourceMappingURL=chunk-NXXKG4GN.cjs.map
|
|
9751
|
+
//# sourceMappingURL=chunk-NXXKG4GN.cjs.map
|