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