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