@useatlas/react 0.0.1 → 0.0.3
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/LICENSE +21 -0
- package/README.md +79 -2
- package/dist/{chunk-5SEVKHS5.cjs → chunk-35SCTKSW.js} +100 -7
- package/dist/chunk-35SCTKSW.js.map +1 -0
- package/dist/{chunk-UIRB6L36.cjs → chunk-DZFSZSQB.cjs} +46 -54
- package/dist/chunk-DZFSZSQB.cjs.map +1 -0
- package/dist/{chunk-2WFDP7G5.js → chunk-FMSGREKS.js} +46 -54
- package/dist/chunk-FMSGREKS.js.map +1 -0
- package/dist/{chunk-44HBZYKP.js → chunk-IDXGFWFS.cjs} +109 -3
- package/dist/chunk-IDXGFWFS.cjs.map +1 -0
- package/dist/global.d.ts +36 -0
- package/dist/hooks.cjs +10 -10
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +2 -2
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js +3 -3
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +385 -265
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +224 -4
- package/dist/index.d.ts +224 -4
- package/dist/index.js +328 -208
- package/dist/index.js.map +1 -1
- package/dist/lib/widget-types.d.ts +232 -0
- package/dist/{result-chart-YLCKBNV4.cjs → result-chart-ANZOT6FL.cjs} +24 -34
- package/dist/result-chart-ANZOT6FL.cjs.map +1 -0
- package/dist/{result-chart-NFAJ4IQ5.js → result-chart-C3EJTN5G.js} +22 -32
- package/dist/result-chart-C3EJTN5G.js.map +1 -0
- package/dist/widget.css +2 -2
- package/dist/widget.js +215 -246
- package/package.json +27 -17
- package/src/components/__tests__/data-table.test.tsx +125 -0
- package/src/components/actions/action-approval-card.tsx +26 -19
- package/src/components/actions/action-status-badge.tsx +3 -3
- package/src/components/atlas-chat.tsx +97 -37
- package/src/components/chart/result-chart.tsx +13 -37
- package/src/components/chat/api-key-bar.tsx +4 -4
- package/src/components/chat/data-table.tsx +42 -3
- package/src/components/chat/error-banner.tsx +108 -5
- package/src/components/chat/follow-up-chips.tsx +1 -1
- package/src/components/chat/managed-auth-card.tsx +6 -6
- package/src/components/conversations/conversation-item.tsx +19 -14
- package/src/components/conversations/conversation-list.tsx +3 -3
- package/src/components/conversations/conversation-sidebar.tsx +15 -4
- package/src/components/conversations/delete-confirmation.tsx +2 -2
- package/src/components/error-boundary.tsx +66 -0
- package/src/components/schema-explorer/schema-explorer.tsx +4 -0
- package/src/env.d.ts +9 -7
- package/src/global.d.ts +36 -0
- package/src/hooks/__tests__/use-atlas-conversations.test.tsx +4 -6
- package/src/hooks/use-atlas-chat.ts +1 -1
- package/src/hooks/use-atlas-conversations.ts +2 -2
- package/src/hooks/use-conversations.ts +60 -68
- package/src/index.ts +8 -0
- package/src/lib/action-types.ts +2 -2
- package/src/lib/helpers.ts +16 -16
- package/src/lib/types.ts +3 -2
- package/src/lib/widget-types.ts +232 -0
- package/src/test-setup.ts +2 -2
- package/dist/chunk-2WFDP7G5.js.map +0 -1
- package/dist/chunk-44HBZYKP.js.map +0 -1
- package/dist/chunk-5SEVKHS5.cjs.map +0 -1
- package/dist/chunk-UIRB6L36.cjs.map +0 -1
- package/dist/result-chart-NFAJ4IQ5.js.map +0 -1
- package/dist/result-chart-YLCKBNV4.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
import { DarkModeContext, setTheme, useDarkMode, useConversations, AUTH_MODES, OKLCH_RE, applyBrandColor, useThemeMode, parseChatError } from './chunk-
|
|
2
|
-
export { AUTH_MODES, THEME_STORAGE_KEY, buildThemeInitScript, parseChatError, setTheme, useConversations } from './chunk-
|
|
3
|
-
import { detectCharts } from './chunk-
|
|
1
|
+
import { DarkModeContext, setTheme, useDarkMode, useConversations, AUTH_MODES, OKLCH_RE, applyBrandColor, useThemeMode, parseChatError } from './chunk-FMSGREKS.js';
|
|
2
|
+
export { AUTH_MODES, THEME_STORAGE_KEY, buildThemeInitScript, parseChatError, setTheme, useConversations } from './chunk-FMSGREKS.js';
|
|
3
|
+
import { detectCharts, ErrorBoundary, Button, cn } from './chunk-35SCTKSW.js';
|
|
4
4
|
import { useChat } from '@ai-sdk/react';
|
|
5
5
|
import { getToolName, DefaultChatTransport, isToolUIPart } from 'ai';
|
|
6
6
|
import * as React from 'react';
|
|
7
7
|
import { createContext, lazy, memo, useContext, Component, useState, useMemo, Suspense, useEffect, useRef, useCallback } from 'react';
|
|
8
8
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
9
|
+
import { FileDown, FileSpreadsheet, TableProperties, Star, Moon, Sun, Monitor, ArrowLeft, AlertTriangle, ServerCrash, Clock, ShieldAlert, WifiOff, XIcon, Columns3, Link2, Sparkles, Search, Eye, ArrowRight, Trash2 } from 'lucide-react';
|
|
9
10
|
import { isActionToolResult, RESOLVED_STATUSES } from '@useatlas/types/action';
|
|
10
|
-
import { FileDown, FileSpreadsheet, TableProperties, Star, Moon, Sun, Monitor, ArrowLeft, XIcon, Columns3, Link2, Sparkles, Search, Eye, ArrowRight, Trash2 } from 'lucide-react';
|
|
11
11
|
import ReactMarkdown from 'react-markdown';
|
|
12
12
|
import remarkGfm from 'remark-gfm';
|
|
13
|
+
import { ScrollArea as ScrollArea$1, ToggleGroup as ToggleGroup$1, Slot, DropdownMenu as DropdownMenu$1, Dialog, Separator as Separator$1, AlertDialog as AlertDialog$1 } from 'radix-ui';
|
|
13
14
|
import { cva } from 'class-variance-authority';
|
|
14
|
-
import { Slot, ScrollArea as ScrollArea$1, ToggleGroup as ToggleGroup$1, DropdownMenu as DropdownMenu$1, Dialog, Separator as Separator$1, AlertDialog as AlertDialog$1 } from 'radix-ui';
|
|
15
|
-
import { clsx } from 'clsx';
|
|
16
|
-
import { twMerge } from 'tailwind-merge';
|
|
17
15
|
|
|
18
16
|
var AtlasUIContext = createContext(null);
|
|
19
17
|
function useAtlasConfig() {
|
|
@@ -43,9 +41,30 @@ function ActionAuthProvider({
|
|
|
43
41
|
);
|
|
44
42
|
return /* @__PURE__ */ jsx(ActionAuthContext.Provider, { value, children });
|
|
45
43
|
}
|
|
46
|
-
function
|
|
44
|
+
function ErrorIcon({ clientCode }) {
|
|
45
|
+
switch (clientCode) {
|
|
46
|
+
case "offline":
|
|
47
|
+
return /* @__PURE__ */ jsx(WifiOff, { className: "size-4 shrink-0" });
|
|
48
|
+
case "api_unreachable":
|
|
49
|
+
return /* @__PURE__ */ jsx(ServerCrash, { className: "size-4 shrink-0" });
|
|
50
|
+
case "auth_failure":
|
|
51
|
+
return /* @__PURE__ */ jsx(ShieldAlert, { className: "size-4 shrink-0" });
|
|
52
|
+
case "rate_limited_http":
|
|
53
|
+
return /* @__PURE__ */ jsx(Clock, { className: "size-4 shrink-0" });
|
|
54
|
+
case "server_error":
|
|
55
|
+
return /* @__PURE__ */ jsx(ServerCrash, { className: "size-4 shrink-0" });
|
|
56
|
+
default:
|
|
57
|
+
return /* @__PURE__ */ jsx(AlertTriangle, { className: "size-4 shrink-0" });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function ErrorBanner({
|
|
61
|
+
error,
|
|
62
|
+
authMode,
|
|
63
|
+
onRetry
|
|
64
|
+
}) {
|
|
47
65
|
const info = useMemo(() => parseChatError(error, authMode), [error, authMode]);
|
|
48
66
|
const [countdown, setCountdown] = useState(info.retryAfterSeconds ?? 0);
|
|
67
|
+
const [restoredOnline, setRestoredOnline] = useState(false);
|
|
49
68
|
useEffect(() => {
|
|
50
69
|
if (!info.retryAfterSeconds) return;
|
|
51
70
|
setCountdown(info.retryAfterSeconds);
|
|
@@ -60,11 +79,74 @@ function ErrorBanner({ error, authMode }) {
|
|
|
60
79
|
}, 1e3);
|
|
61
80
|
return () => clearInterval(interval);
|
|
62
81
|
}, [info.retryAfterSeconds]);
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (info.retryAfterSeconds && countdown === 0 && onRetry) {
|
|
84
|
+
onRetry();
|
|
85
|
+
}
|
|
86
|
+
}, [countdown, info.retryAfterSeconds, onRetry]);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (info.clientCode !== "offline") return;
|
|
89
|
+
function handleOnline() {
|
|
90
|
+
setRestoredOnline(true);
|
|
91
|
+
onRetry?.();
|
|
92
|
+
}
|
|
93
|
+
window.addEventListener("online", handleOnline);
|
|
94
|
+
return () => {
|
|
95
|
+
window.removeEventListener("online", handleOnline);
|
|
96
|
+
};
|
|
97
|
+
}, [info.clientCode, onRetry]);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
try {
|
|
100
|
+
if (typeof window !== "undefined" && window.parent !== window) {
|
|
101
|
+
window.parent.postMessage(
|
|
102
|
+
{
|
|
103
|
+
type: "atlas:error",
|
|
104
|
+
error: {
|
|
105
|
+
code: info.clientCode ?? info.code ?? "unknown",
|
|
106
|
+
message: info.title,
|
|
107
|
+
detail: info.detail,
|
|
108
|
+
retryable: info.retryable
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"*"
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
}
|
|
116
|
+
}, [info.clientCode, info.code, info.title, info.detail, info.retryable]);
|
|
117
|
+
if (info.clientCode === "offline" && restoredOnline) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
63
120
|
const detail = info.retryAfterSeconds && countdown > 0 ? `Try again in ${countdown} second${countdown !== 1 ? "s" : ""}.` : info.detail;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
121
|
+
const showRetry = info.retryable && onRetry && countdown === 0 && info.clientCode !== "offline";
|
|
122
|
+
return /* @__PURE__ */ jsx(
|
|
123
|
+
"div",
|
|
124
|
+
{
|
|
125
|
+
className: "mb-2 rounded-lg border border-red-300 bg-red-50 text-red-700 dark:border-red-900/50 dark:bg-red-950/20 dark:text-red-400 px-4 py-3 text-sm",
|
|
126
|
+
role: "alert",
|
|
127
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
128
|
+
/* @__PURE__ */ jsx(ErrorIcon, { clientCode: info.clientCode }),
|
|
129
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
130
|
+
/* @__PURE__ */ jsx("p", { className: "font-medium", children: info.title }),
|
|
131
|
+
detail && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs opacity-80", children: detail }),
|
|
132
|
+
info.requestId && /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs opacity-60", children: [
|
|
133
|
+
"Request ID: ",
|
|
134
|
+
info.requestId
|
|
135
|
+
] }),
|
|
136
|
+
showRetry && /* @__PURE__ */ jsx(
|
|
137
|
+
Button,
|
|
138
|
+
{
|
|
139
|
+
variant: "link",
|
|
140
|
+
size: "sm",
|
|
141
|
+
onClick: onRetry,
|
|
142
|
+
className: "mt-2 h-auto p-0 text-xs font-medium text-red-700 dark:text-red-400",
|
|
143
|
+
children: "Try again"
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
] })
|
|
147
|
+
] })
|
|
148
|
+
}
|
|
149
|
+
);
|
|
68
150
|
}
|
|
69
151
|
function ApiKeyBar({
|
|
70
152
|
apiKey,
|
|
@@ -82,7 +164,7 @@ function ApiKeyBar({
|
|
|
82
164
|
setDraft(apiKey);
|
|
83
165
|
setEditing(true);
|
|
84
166
|
},
|
|
85
|
-
className: "rounded border border-zinc-200 px-2 py-0.5 text-zinc-500 transition-colors hover:border-zinc-400 hover:text-zinc-800 dark:border-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-500 dark:hover:text-zinc-200",
|
|
167
|
+
className: "rounded border border-zinc-200 px-2 py-0.5 text-zinc-500 transition-colors hover:border-zinc-400 hover:text-zinc-800 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 dark:border-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-500 dark:hover:text-zinc-200",
|
|
86
168
|
children: "Change"
|
|
87
169
|
}
|
|
88
170
|
)
|
|
@@ -107,7 +189,7 @@ function ApiKeyBar({
|
|
|
107
189
|
value: draft,
|
|
108
190
|
onChange: (e) => setDraft(e.target.value),
|
|
109
191
|
placeholder: "Enter your API key...",
|
|
110
|
-
className: "flex-1 bg-transparent text-xs text-zinc-900 placeholder-zinc-400 outline-none dark:text-zinc-100 dark:placeholder-zinc-600",
|
|
192
|
+
className: "flex-1 bg-transparent text-xs text-zinc-900 placeholder-zinc-400 outline-none focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 dark:text-zinc-100 dark:placeholder-zinc-600",
|
|
111
193
|
autoFocus: true
|
|
112
194
|
}
|
|
113
195
|
),
|
|
@@ -116,7 +198,7 @@ function ApiKeyBar({
|
|
|
116
198
|
{
|
|
117
199
|
type: "submit",
|
|
118
200
|
disabled: !draft.trim(),
|
|
119
|
-
className: "rounded border border-zinc-200 px-2 py-0.5 text-xs text-zinc-500 transition-colors hover:border-zinc-400 hover:text-zinc-800 disabled:opacity-40 dark:border-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-500 dark:hover:text-zinc-200",
|
|
201
|
+
className: "rounded border border-zinc-200 px-2 py-0.5 text-xs text-zinc-500 transition-colors hover:border-zinc-400 hover:text-zinc-800 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:opacity-40 dark:border-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-500 dark:hover:text-zinc-200",
|
|
120
202
|
children: "Save"
|
|
121
203
|
}
|
|
122
204
|
),
|
|
@@ -125,7 +207,7 @@ function ApiKeyBar({
|
|
|
125
207
|
{
|
|
126
208
|
type: "button",
|
|
127
209
|
onClick: () => setEditing(false),
|
|
128
|
-
className: "text-xs text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300",
|
|
210
|
+
className: "rounded text-xs text-zinc-400 hover:text-zinc-600 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 dark:hover:text-zinc-300",
|
|
129
211
|
children: "Cancel"
|
|
130
212
|
}
|
|
131
213
|
)
|
|
@@ -182,7 +264,7 @@ function ManagedAuthCard() {
|
|
|
182
264
|
value: name,
|
|
183
265
|
onChange: (e) => setName(e.target.value),
|
|
184
266
|
placeholder: "Name (optional)",
|
|
185
|
-
className: "w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-900 placeholder-zinc-400 outline-none focus:border-blue-500 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 dark:placeholder-zinc-600"
|
|
267
|
+
className: "w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-900 placeholder-zinc-400 outline-none focus-visible:border-blue-500 focus-visible:ring-[3px] focus-visible:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 dark:placeholder-zinc-600"
|
|
186
268
|
}
|
|
187
269
|
),
|
|
188
270
|
/* @__PURE__ */ jsx(
|
|
@@ -193,7 +275,7 @@ function ManagedAuthCard() {
|
|
|
193
275
|
onChange: (e) => setEmail(e.target.value),
|
|
194
276
|
placeholder: "Email",
|
|
195
277
|
required: true,
|
|
196
|
-
className: "w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-900 placeholder-zinc-400 outline-none focus:border-blue-500 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 dark:placeholder-zinc-600"
|
|
278
|
+
className: "w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-900 placeholder-zinc-400 outline-none focus-visible:border-blue-500 focus-visible:ring-[3px] focus-visible:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 dark:placeholder-zinc-600"
|
|
197
279
|
}
|
|
198
280
|
),
|
|
199
281
|
/* @__PURE__ */ jsx(
|
|
@@ -205,7 +287,7 @@ function ManagedAuthCard() {
|
|
|
205
287
|
placeholder: "Password",
|
|
206
288
|
required: true,
|
|
207
289
|
minLength: 8,
|
|
208
|
-
className: "w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-900 placeholder-zinc-400 outline-none focus:border-blue-500 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 dark:placeholder-zinc-600"
|
|
290
|
+
className: "w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-900 placeholder-zinc-400 outline-none focus-visible:border-blue-500 focus-visible:ring-[3px] focus-visible:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 dark:placeholder-zinc-600"
|
|
209
291
|
}
|
|
210
292
|
),
|
|
211
293
|
error && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600 dark:text-red-400", children: error }),
|
|
@@ -214,7 +296,7 @@ function ManagedAuthCard() {
|
|
|
214
296
|
{
|
|
215
297
|
type: "submit",
|
|
216
298
|
disabled: loading,
|
|
217
|
-
className: "w-full rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-500 disabled:opacity-40",
|
|
299
|
+
className: "w-full rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-500 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-blue-500/50 disabled:opacity-40",
|
|
218
300
|
children: loading ? "..." : view === "login" ? "Sign in" : "Create account"
|
|
219
301
|
}
|
|
220
302
|
)
|
|
@@ -225,14 +307,14 @@ function ManagedAuthCard() {
|
|
|
225
307
|
/* @__PURE__ */ jsx("button", { onClick: () => {
|
|
226
308
|
setView("signup");
|
|
227
309
|
setError("");
|
|
228
|
-
}, className: "text-blue-600 hover:underline dark:text-blue-400", children: "Create one" })
|
|
310
|
+
}, className: "rounded text-blue-600 hover:underline focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-blue-500/50 dark:text-blue-400", children: "Create one" })
|
|
229
311
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
230
312
|
"Already have an account?",
|
|
231
313
|
" ",
|
|
232
314
|
/* @__PURE__ */ jsx("button", { onClick: () => {
|
|
233
315
|
setView("login");
|
|
234
316
|
setError("");
|
|
235
|
-
}, className: "text-blue-600 hover:underline dark:text-blue-400", children: "Sign in" })
|
|
317
|
+
}, className: "rounded text-blue-600 hover:underline focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-blue-500/50 dark:text-blue-400", children: "Sign in" })
|
|
236
318
|
] }) })
|
|
237
319
|
] }) });
|
|
238
320
|
}
|
|
@@ -292,7 +374,7 @@ function downloadCSV(csv, filename = "atlas-results.csv") {
|
|
|
292
374
|
a.download = filename;
|
|
293
375
|
a.click();
|
|
294
376
|
} catch (err) {
|
|
295
|
-
console.error("CSV download failed:", err);
|
|
377
|
+
console.error("CSV download failed:", err instanceof Error ? err.message : String(err));
|
|
296
378
|
window.alert("CSV download failed");
|
|
297
379
|
} finally {
|
|
298
380
|
if (url) {
|
|
@@ -311,31 +393,31 @@ function coerceExcelCell(v) {
|
|
|
311
393
|
return String(v);
|
|
312
394
|
}
|
|
313
395
|
async function downloadExcel(columns, rows, filename = "atlas-results.xlsx") {
|
|
314
|
-
let
|
|
396
|
+
let ExcelJS;
|
|
315
397
|
try {
|
|
316
|
-
|
|
317
|
-
'
|
|
398
|
+
ExcelJS = await import(
|
|
399
|
+
'exceljs'
|
|
318
400
|
/* webpackIgnore: true */
|
|
319
401
|
);
|
|
320
402
|
} catch (err) {
|
|
321
|
-
console.error("Failed to load
|
|
403
|
+
console.error("Failed to load exceljs library:", err instanceof Error ? err.message : String(err));
|
|
322
404
|
window.alert("Excel export is unavailable. The spreadsheet library failed to load.");
|
|
323
405
|
return;
|
|
324
406
|
}
|
|
325
407
|
let url = null;
|
|
326
408
|
try {
|
|
327
|
-
const
|
|
409
|
+
const wb = new ExcelJS.Workbook();
|
|
410
|
+
const ws = wb.addWorksheet("Results");
|
|
411
|
+
ws.columns = columns.map((col) => ({ header: col, key: col }));
|
|
412
|
+
for (const row of rows) {
|
|
328
413
|
const obj = {};
|
|
329
414
|
for (const col of columns) {
|
|
330
415
|
obj[col] = coerceExcelCell(row[col]);
|
|
331
416
|
}
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
const
|
|
335
|
-
const
|
|
336
|
-
XLSX.utils.book_append_sheet(wb, ws, "Results");
|
|
337
|
-
const wbOut = XLSX.write(wb, { bookType: "xlsx", type: "array" });
|
|
338
|
-
const blob = new Blob([wbOut], {
|
|
417
|
+
ws.addRow(obj);
|
|
418
|
+
}
|
|
419
|
+
const buffer = await wb.xlsx.writeBuffer();
|
|
420
|
+
const blob = new Blob([buffer], {
|
|
339
421
|
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
340
422
|
});
|
|
341
423
|
url = URL.createObjectURL(blob);
|
|
@@ -344,8 +426,8 @@ async function downloadExcel(columns, rows, filename = "atlas-results.xlsx") {
|
|
|
344
426
|
a.download = filename;
|
|
345
427
|
a.click();
|
|
346
428
|
} catch (err) {
|
|
347
|
-
|
|
348
|
-
|
|
429
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
430
|
+
console.error("Excel download failed:", detail);
|
|
349
431
|
window.alert(`Excel download failed: ${detail}
|
|
350
432
|
|
|
351
433
|
You can try the CSV download as an alternative.`);
|
|
@@ -409,13 +491,19 @@ function LoadingCard({ label }) {
|
|
|
409
491
|
label
|
|
410
492
|
] });
|
|
411
493
|
}
|
|
412
|
-
function
|
|
494
|
+
function DataTableInner({
|
|
413
495
|
columns,
|
|
414
496
|
rows,
|
|
415
497
|
maxRows = 10
|
|
416
498
|
}) {
|
|
417
499
|
const [sortCol, setSortCol] = useState(null);
|
|
418
500
|
const [sortDir, setSortDir] = useState("asc");
|
|
501
|
+
if (rows.length === 0) {
|
|
502
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-zinc-200 px-4 py-8 text-center dark:border-zinc-700", children: [
|
|
503
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-zinc-500 dark:text-zinc-400", children: "Query returned no results" }),
|
|
504
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-zinc-400 dark:text-zinc-500", children: "Try adjusting your query filters or criteria" })
|
|
505
|
+
] });
|
|
506
|
+
}
|
|
419
507
|
const hasMore = rows.length > maxRows;
|
|
420
508
|
const cell = (row, colIdx) => {
|
|
421
509
|
if (Array.isArray(row)) return row[colIdx];
|
|
@@ -458,8 +546,17 @@ function DataTable({
|
|
|
458
546
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { className: "border-b border-zinc-200 bg-zinc-100/80 dark:border-zinc-700 dark:bg-zinc-800/80", children: columns.map((col, i) => /* @__PURE__ */ jsxs(
|
|
459
547
|
"th",
|
|
460
548
|
{
|
|
549
|
+
tabIndex: 0,
|
|
550
|
+
role: "columnheader",
|
|
551
|
+
"aria-sort": sortCol === i ? sortDir === "asc" ? "ascending" : "descending" : "none",
|
|
461
552
|
onClick: () => handleSort(i),
|
|
462
|
-
|
|
553
|
+
onKeyDown: (e) => {
|
|
554
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
555
|
+
e.preventDefault();
|
|
556
|
+
handleSort(i);
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
className: "group cursor-pointer select-none whitespace-nowrap px-3 py-2 text-left font-medium text-zinc-500 transition-colors hover:text-zinc-800 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 dark:text-zinc-400 dark:hover:text-zinc-200",
|
|
463
560
|
children: [
|
|
464
561
|
col,
|
|
465
562
|
sortCol === i ? sortDir === "asc" ? " \u25B2" : " \u25BC" : ""
|
|
@@ -485,6 +582,18 @@ function DataTable({
|
|
|
485
582
|
] })
|
|
486
583
|
] });
|
|
487
584
|
}
|
|
585
|
+
function DataTable(props) {
|
|
586
|
+
return /* @__PURE__ */ jsx(
|
|
587
|
+
ErrorBoundary,
|
|
588
|
+
{
|
|
589
|
+
fallbackRender: (_error, reset) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700 dark:border-red-900/50 dark:bg-red-950/20 dark:text-red-400", children: [
|
|
590
|
+
/* @__PURE__ */ jsx("span", { children: "Unable to render results." }),
|
|
591
|
+
/* @__PURE__ */ jsx(Button, { variant: "link", onClick: reset, children: "Retry" })
|
|
592
|
+
] }),
|
|
593
|
+
children: /* @__PURE__ */ jsx(DataTableInner, { ...props })
|
|
594
|
+
}
|
|
595
|
+
);
|
|
596
|
+
}
|
|
488
597
|
function CopyButton({ text, label = "Copy" }) {
|
|
489
598
|
const [state, setState] = useState("idle");
|
|
490
599
|
return /* @__PURE__ */ jsx(
|
|
@@ -539,7 +648,7 @@ function SQLBlock({ sql }) {
|
|
|
539
648
|
/* @__PURE__ */ jsx("div", { className: "absolute right-2 top-2", children: /* @__PURE__ */ jsx(CopyButton, { text: sql, label: "Copy SQL" }) })
|
|
540
649
|
] });
|
|
541
650
|
}
|
|
542
|
-
var ResultChart = lazy(() => import('./result-chart-
|
|
651
|
+
var ResultChart = lazy(() => import('./result-chart-C3EJTN5G.js').then((m) => ({ default: m.ResultChart })));
|
|
543
652
|
var ChartFallback = /* @__PURE__ */ jsx("div", { className: "h-64 animate-pulse rounded-lg bg-zinc-100 dark:bg-zinc-800" });
|
|
544
653
|
function toStringRows(columns, rows) {
|
|
545
654
|
return rows.map((row) => columns.map((col) => row[col] == null ? "" : String(row[col])));
|
|
@@ -710,7 +819,8 @@ function borderColor(status) {
|
|
|
710
819
|
case "denied":
|
|
711
820
|
case "failed":
|
|
712
821
|
return "border-red-300 dark:border-red-900/50";
|
|
713
|
-
|
|
822
|
+
case "rolled_back":
|
|
823
|
+
case "timed_out":
|
|
714
824
|
return "border-zinc-200 dark:border-zinc-700";
|
|
715
825
|
}
|
|
716
826
|
}
|
|
@@ -732,7 +842,7 @@ function ActionApprovalCard({ part }) {
|
|
|
732
842
|
const effectiveStatus = cardState.phase === "resolved" ? cardState.status : toolResult.status;
|
|
733
843
|
const isPending = effectiveStatus === "pending_approval" && cardState.phase !== "submitting";
|
|
734
844
|
const isSubmitting = cardState.phase === "submitting";
|
|
735
|
-
const resolvedResult = cardState.phase === "resolved" ? cardState.result : toolResult.result;
|
|
845
|
+
const resolvedResult = cardState.phase === "resolved" ? cardState.result : toolResult.status === "approved" || toolResult.status === "executed" || toolResult.status === "auto_approved" ? toolResult.result : void 0;
|
|
736
846
|
async function callAction(endpoint, body) {
|
|
737
847
|
if (!actionAuth) {
|
|
738
848
|
console.warn("ActionApprovalCard: No ActionAuthProvider found. API calls will be sent without authentication.");
|
|
@@ -758,8 +868,10 @@ function ActionApprovalCard({ part }) {
|
|
|
758
868
|
} catch {
|
|
759
869
|
throw new Error("Action was already resolved, but the response could not be read. Refresh the page.");
|
|
760
870
|
}
|
|
761
|
-
|
|
762
|
-
|
|
871
|
+
if (typeof data2.status !== "string" || !RESOLVED_STATUSES.has(data2.status)) {
|
|
872
|
+
throw new Error("Action was already resolved with an unrecognized status. Refresh the page.");
|
|
873
|
+
}
|
|
874
|
+
const label = data2.status.replace(/_/g, " ");
|
|
763
875
|
throw new Error(`This action was already ${label} by another user or policy.`);
|
|
764
876
|
}
|
|
765
877
|
if (!res.ok) {
|
|
@@ -772,8 +884,8 @@ function ActionApprovalCard({ part }) {
|
|
|
772
884
|
} catch {
|
|
773
885
|
throw new Error("Action succeeded, but the response could not be read. Refresh the page.");
|
|
774
886
|
}
|
|
775
|
-
if (typeof data.status !== "string") {
|
|
776
|
-
throw new Error("Action succeeded, but the server returned an
|
|
887
|
+
if (typeof data.status !== "string" || !RESOLVED_STATUSES.has(data.status)) {
|
|
888
|
+
throw new Error("Action succeeded, but the server returned an unrecognized status. Refresh the page.");
|
|
777
889
|
}
|
|
778
890
|
setCardState({ phase: "resolved", status: data.status, result: data.result });
|
|
779
891
|
}
|
|
@@ -816,11 +928,11 @@ function ActionApprovalCard({ part }) {
|
|
|
816
928
|
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Result: " }),
|
|
817
929
|
typeof resolvedResult === "string" ? resolvedResult : safeStringify(resolvedResult)
|
|
818
930
|
] }),
|
|
819
|
-
toolResult.
|
|
931
|
+
toolResult.status === "failed" && /* @__PURE__ */ jsxs("div", { className: "mb-2 rounded bg-red-50 p-2 text-xs text-red-700 dark:bg-red-900/20 dark:text-red-400", children: [
|
|
820
932
|
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Error: " }),
|
|
821
933
|
toolResult.error
|
|
822
934
|
] }),
|
|
823
|
-
toolResult.
|
|
935
|
+
toolResult.status === "denied" && RESOLVED_STATUSES.has(effectiveStatus) && /* @__PURE__ */ jsxs("div", { className: "mb-2 text-xs text-zinc-500 dark:text-zinc-400", children: [
|
|
824
936
|
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Reason: " }),
|
|
825
937
|
toolResult.reason
|
|
826
938
|
] })
|
|
@@ -833,7 +945,7 @@ function ActionApprovalCard({ part }) {
|
|
|
833
945
|
{
|
|
834
946
|
onClick: handleApprove,
|
|
835
947
|
disabled: isSubmitting,
|
|
836
|
-
className: "inline-flex items-center gap-1.5 rounded bg-blue-600 px-3 py-1.5 text-xs font-medium text-white transition-colors hover:bg-blue-500 disabled:opacity-40",
|
|
948
|
+
className: "inline-flex items-center gap-1.5 rounded bg-blue-600 px-3 py-1.5 text-xs font-medium text-white transition-colors hover:bg-blue-500 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-blue-500/50 disabled:opacity-40",
|
|
837
949
|
children: [
|
|
838
950
|
isSubmitting && cardState.action === "approve" && /* @__PURE__ */ jsx("span", { className: "inline-block h-3 w-3 animate-spin rounded-full border-2 border-white/30 border-t-white" }),
|
|
839
951
|
"Approve"
|
|
@@ -845,7 +957,7 @@ function ActionApprovalCard({ part }) {
|
|
|
845
957
|
{
|
|
846
958
|
onClick: () => setShowDenyInput(true),
|
|
847
959
|
disabled: isSubmitting,
|
|
848
|
-
className: "rounded border border-zinc-300 px-3 py-1.5 text-xs font-medium text-zinc-600 transition-colors hover:border-zinc-400 hover:text-zinc-800 disabled:opacity-40 dark:border-zinc-600 dark:text-zinc-400 dark:hover:border-zinc-500 dark:hover:text-zinc-200",
|
|
960
|
+
className: "rounded border border-zinc-300 px-3 py-1.5 text-xs font-medium text-zinc-600 transition-colors hover:border-zinc-400 hover:text-zinc-800 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:opacity-40 dark:border-zinc-600 dark:text-zinc-400 dark:hover:border-zinc-500 dark:hover:text-zinc-200",
|
|
849
961
|
children: "Deny"
|
|
850
962
|
}
|
|
851
963
|
) : /* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-2", children: [
|
|
@@ -855,7 +967,7 @@ function ActionApprovalCard({ part }) {
|
|
|
855
967
|
value: denyReason,
|
|
856
968
|
onChange: (e) => setDenyReason(e.target.value),
|
|
857
969
|
placeholder: "Reason (optional)",
|
|
858
|
-
className: "flex-1 rounded border border-zinc-200 bg-white px-2 py-1 text-xs text-zinc-900 placeholder-zinc-400 outline-none focus:border-red-400 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 dark:placeholder-zinc-600",
|
|
970
|
+
className: "flex-1 rounded border border-zinc-200 bg-white px-2 py-1 text-xs text-zinc-900 placeholder-zinc-400 outline-none focus-visible:border-red-400 focus-visible:ring-[3px] focus-visible:ring-red-400/30 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 dark:placeholder-zinc-600",
|
|
859
971
|
disabled: isSubmitting
|
|
860
972
|
}
|
|
861
973
|
),
|
|
@@ -864,7 +976,7 @@ function ActionApprovalCard({ part }) {
|
|
|
864
976
|
{
|
|
865
977
|
onClick: handleDeny,
|
|
866
978
|
disabled: isSubmitting,
|
|
867
|
-
className: "inline-flex items-center gap-1.5 rounded bg-red-600 px-3 py-1.5 text-xs font-medium text-white transition-colors hover:bg-red-500 disabled:opacity-40",
|
|
979
|
+
className: "inline-flex items-center gap-1.5 rounded bg-red-600 px-3 py-1.5 text-xs font-medium text-white transition-colors hover:bg-red-500 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-red-500/50 disabled:opacity-40",
|
|
868
980
|
children: [
|
|
869
981
|
isSubmitting && cardState.action === "deny" && /* @__PURE__ */ jsx("span", { className: "inline-block h-3 w-3 animate-spin rounded-full border-2 border-white/30 border-t-white" }),
|
|
870
982
|
"Confirm Deny"
|
|
@@ -879,7 +991,7 @@ function ActionApprovalCard({ part }) {
|
|
|
879
991
|
setDenyReason("");
|
|
880
992
|
},
|
|
881
993
|
disabled: isSubmitting,
|
|
882
|
-
className: "text-xs text-zinc-400 hover:text-zinc-600 disabled:opacity-40 dark:hover:text-zinc-300",
|
|
994
|
+
className: "rounded text-xs text-zinc-400 hover:text-zinc-600 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:opacity-40 dark:hover:text-zinc-300",
|
|
883
995
|
children: "Cancel"
|
|
884
996
|
}
|
|
885
997
|
)
|
|
@@ -888,7 +1000,7 @@ function ActionApprovalCard({ part }) {
|
|
|
888
1000
|
] })
|
|
889
1001
|
] });
|
|
890
1002
|
}
|
|
891
|
-
var ResultChart2 = lazy(() => import('./result-chart-
|
|
1003
|
+
var ResultChart2 = lazy(() => import('./result-chart-C3EJTN5G.js').then((m) => ({ default: m.ResultChart })));
|
|
892
1004
|
var ALLOWED_IMAGE_MIME = /* @__PURE__ */ new Set(["image/png", "image/jpeg"]);
|
|
893
1005
|
var PythonErrorBoundary = class extends Component {
|
|
894
1006
|
constructor(props) {
|
|
@@ -1172,63 +1284,12 @@ var STARTER_PROMPTS = [
|
|
|
1172
1284
|
"What is the headcount breakdown by department?",
|
|
1173
1285
|
"What is total MRR by plan type?"
|
|
1174
1286
|
];
|
|
1175
|
-
function cn(...inputs) {
|
|
1176
|
-
return twMerge(clsx(inputs));
|
|
1177
|
-
}
|
|
1178
|
-
var buttonVariants = cva(
|
|
1179
|
-
"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1180
|
-
{
|
|
1181
|
-
variants: {
|
|
1182
|
-
variant: {
|
|
1183
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
1184
|
-
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
1185
|
-
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
1186
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
1187
|
-
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
1188
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
1189
|
-
},
|
|
1190
|
-
size: {
|
|
1191
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
1192
|
-
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
1193
|
-
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
1194
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
1195
|
-
icon: "size-9",
|
|
1196
|
-
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
1197
|
-
"icon-sm": "size-8",
|
|
1198
|
-
"icon-lg": "size-10"
|
|
1199
|
-
}
|
|
1200
|
-
},
|
|
1201
|
-
defaultVariants: {
|
|
1202
|
-
variant: "default",
|
|
1203
|
-
size: "default"
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
);
|
|
1207
|
-
function Button({
|
|
1208
|
-
className,
|
|
1209
|
-
variant = "default",
|
|
1210
|
-
size = "default",
|
|
1211
|
-
asChild = false,
|
|
1212
|
-
...props
|
|
1213
|
-
}) {
|
|
1214
|
-
const Comp = asChild ? Slot.Root : "button";
|
|
1215
|
-
return /* @__PURE__ */ jsx(
|
|
1216
|
-
Comp,
|
|
1217
|
-
{
|
|
1218
|
-
"data-slot": "button",
|
|
1219
|
-
"data-variant": variant,
|
|
1220
|
-
"data-size": size,
|
|
1221
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
1222
|
-
...props
|
|
1223
|
-
}
|
|
1224
|
-
);
|
|
1225
|
-
}
|
|
1226
1287
|
function FollowUpChips({
|
|
1227
1288
|
suggestions,
|
|
1228
1289
|
onSelect
|
|
1229
1290
|
}) {
|
|
1230
1291
|
if (suggestions.length === 0) return null;
|
|
1231
|
-
return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 pt-1", children: suggestions.map((s, i) => /* @__PURE__ */ jsx(
|
|
1292
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 pt-1", role: "group", "aria-label": "Suggested follow-up questions", children: suggestions.map((s, i) => /* @__PURE__ */ jsx(
|
|
1232
1293
|
Button,
|
|
1233
1294
|
{
|
|
1234
1295
|
variant: "outline",
|
|
@@ -1364,7 +1425,7 @@ function DeleteConfirmation({
|
|
|
1364
1425
|
"button",
|
|
1365
1426
|
{
|
|
1366
1427
|
onClick: onCancel,
|
|
1367
|
-
className: "rounded px-2 py-0.5 text-zinc-500 transition-colors hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200",
|
|
1428
|
+
className: "rounded px-2 py-0.5 text-zinc-500 transition-colors hover:text-zinc-800 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 dark:text-zinc-400 dark:hover:text-zinc-200",
|
|
1368
1429
|
children: "Cancel"
|
|
1369
1430
|
}
|
|
1370
1431
|
),
|
|
@@ -1372,7 +1433,7 @@ function DeleteConfirmation({
|
|
|
1372
1433
|
"button",
|
|
1373
1434
|
{
|
|
1374
1435
|
onClick: onConfirm,
|
|
1375
|
-
className: "rounded bg-red-600 px-2 py-0.5 text-white transition-colors hover:bg-red-500",
|
|
1436
|
+
className: "rounded bg-red-600 px-2 py-0.5 text-white transition-colors hover:bg-red-500 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-red-500/50 ",
|
|
1376
1437
|
children: "Delete"
|
|
1377
1438
|
}
|
|
1378
1439
|
)
|
|
@@ -1402,6 +1463,7 @@ function ConversationItem({
|
|
|
1402
1463
|
const [confirmDelete, setConfirmDelete] = useState(false);
|
|
1403
1464
|
const [deleting, setDeleting] = useState(false);
|
|
1404
1465
|
const [starPending, setStarPending] = useState(false);
|
|
1466
|
+
const [error, setError] = useState(null);
|
|
1405
1467
|
if (confirmDelete) {
|
|
1406
1468
|
return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-red-200 bg-red-50/50 dark:border-red-900/30 dark:bg-red-950/10", children: /* @__PURE__ */ jsx(
|
|
1407
1469
|
DeleteConfirmation,
|
|
@@ -1410,12 +1472,11 @@ function ConversationItem({
|
|
|
1410
1472
|
onConfirm: async () => {
|
|
1411
1473
|
setDeleting(true);
|
|
1412
1474
|
try {
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
console.warn("Failed to delete conversation:", err);
|
|
1475
|
+
await onDelete();
|
|
1476
|
+
setConfirmDelete(false);
|
|
1477
|
+
} catch {
|
|
1478
|
+
setError("Failed to delete");
|
|
1479
|
+
setTimeout(() => setError(null), 3e3);
|
|
1419
1480
|
} finally {
|
|
1420
1481
|
setDeleting(false);
|
|
1421
1482
|
}
|
|
@@ -1435,11 +1496,11 @@ function ConversationItem({
|
|
|
1435
1496
|
onSelect();
|
|
1436
1497
|
}
|
|
1437
1498
|
},
|
|
1438
|
-
className: `group flex w-full cursor-pointer items-center gap-2 rounded-lg px-3 py-2.5 text-left text-sm transition-colors ${isActive ? "bg-blue-50 text-blue-700 dark:bg-blue-600/10 dark:text-blue-400" : "text-zinc-700 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800"}`,
|
|
1499
|
+
className: `group flex w-full cursor-pointer items-center gap-2 rounded-lg px-3 py-2.5 text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 ${isActive ? "bg-blue-50 text-blue-700 dark:bg-blue-600/10 dark:text-blue-400" : "text-zinc-700 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800"}`,
|
|
1439
1500
|
children: [
|
|
1440
1501
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1441
1502
|
/* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium", children: conversation.title || "New conversation" }),
|
|
1442
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-400 dark:text-zinc-500", children: relativeTime(conversation.updatedAt) })
|
|
1503
|
+
error ? /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500 dark:text-red-400", children: error }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-400 dark:text-zinc-500", children: relativeTime(conversation.updatedAt) })
|
|
1443
1504
|
] }),
|
|
1444
1505
|
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [
|
|
1445
1506
|
/* @__PURE__ */ jsx(
|
|
@@ -1453,8 +1514,9 @@ function ConversationItem({
|
|
|
1453
1514
|
setStarPending(true);
|
|
1454
1515
|
try {
|
|
1455
1516
|
await onStar(!conversation.starred);
|
|
1456
|
-
} catch
|
|
1457
|
-
|
|
1517
|
+
} catch {
|
|
1518
|
+
setError("Failed to update");
|
|
1519
|
+
setTimeout(() => setError(null), 3e3);
|
|
1458
1520
|
} finally {
|
|
1459
1521
|
setStarPending(false);
|
|
1460
1522
|
}
|
|
@@ -1495,7 +1557,7 @@ function ConversationList({
|
|
|
1495
1557
|
emptyMessage
|
|
1496
1558
|
}) {
|
|
1497
1559
|
if (conversations.length === 0) {
|
|
1498
|
-
return /* @__PURE__ */ jsx("div", { className: "px-3 py-6 text-center text-xs text-zinc-
|
|
1560
|
+
return /* @__PURE__ */ jsx("div", { className: "px-3 py-6 text-center text-xs text-zinc-500 dark:text-zinc-400", children: emptyMessage ?? "No conversations yet" });
|
|
1499
1561
|
}
|
|
1500
1562
|
function renderItems(items) {
|
|
1501
1563
|
return items.map((c) => /* @__PURE__ */ jsx(
|
|
@@ -1536,6 +1598,14 @@ function ConversationSidebar({
|
|
|
1536
1598
|
onMobileClose
|
|
1537
1599
|
}) {
|
|
1538
1600
|
const [filter, setFilter] = useState("all");
|
|
1601
|
+
useEffect(() => {
|
|
1602
|
+
if (!mobileOpen) return;
|
|
1603
|
+
function handleKeyDown(e) {
|
|
1604
|
+
if (e.key === "Escape") onMobileClose();
|
|
1605
|
+
}
|
|
1606
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1607
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1608
|
+
}, [mobileOpen, onMobileClose]);
|
|
1539
1609
|
const starredConversations = conversations.filter((c) => c.starred);
|
|
1540
1610
|
const filteredConversations = filter === "saved" ? starredConversations : conversations;
|
|
1541
1611
|
const sidebar = /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col border-r border-zinc-200 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-950", children: [
|
|
@@ -1545,7 +1615,7 @@ function ConversationSidebar({
|
|
|
1545
1615
|
"button",
|
|
1546
1616
|
{
|
|
1547
1617
|
onClick: onNewChat,
|
|
1548
|
-
className: "rounded-lg border border-zinc-200 px-3 py-1.5 text-xs font-medium text-zinc-600 transition-colors hover:border-zinc-400 hover:text-zinc-900 dark:border-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-500 dark:hover:text-zinc-200",
|
|
1618
|
+
className: "rounded-lg border border-zinc-200 px-3 py-1.5 text-xs font-medium text-zinc-600 transition-colors hover:border-zinc-400 hover:text-zinc-900 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 dark:border-zinc-700 dark:text-zinc-400 dark:hover:border-zinc-500 dark:hover:text-zinc-200",
|
|
1549
1619
|
children: "+ New"
|
|
1550
1620
|
}
|
|
1551
1621
|
)
|
|
@@ -1897,6 +1967,19 @@ function SheetTitle({
|
|
|
1897
1967
|
}
|
|
1898
1968
|
);
|
|
1899
1969
|
}
|
|
1970
|
+
function SheetDescription({
|
|
1971
|
+
className,
|
|
1972
|
+
...props
|
|
1973
|
+
}) {
|
|
1974
|
+
return /* @__PURE__ */ jsx(
|
|
1975
|
+
Dialog.Description,
|
|
1976
|
+
{
|
|
1977
|
+
"data-slot": "sheet-description",
|
|
1978
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
1979
|
+
...props
|
|
1980
|
+
}
|
|
1981
|
+
);
|
|
1982
|
+
}
|
|
1900
1983
|
function ScrollArea({
|
|
1901
1984
|
className,
|
|
1902
1985
|
children,
|
|
@@ -2348,10 +2431,13 @@ function SchemaExplorer({
|
|
|
2348
2431
|
onOpenChange(false);
|
|
2349
2432
|
}
|
|
2350
2433
|
return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(SheetContent, { side: "right", className: "flex w-full flex-col p-0 sm:max-w-xl", children: [
|
|
2351
|
-
/* @__PURE__ */
|
|
2352
|
-
/* @__PURE__ */
|
|
2353
|
-
|
|
2354
|
-
|
|
2434
|
+
/* @__PURE__ */ jsxs(SheetHeader, { className: "px-4 pt-4", children: [
|
|
2435
|
+
/* @__PURE__ */ jsxs(SheetTitle, { className: "flex items-center gap-2 text-base", children: [
|
|
2436
|
+
/* @__PURE__ */ jsx(TableProperties, { className: "size-4" }),
|
|
2437
|
+
"Schema Explorer"
|
|
2438
|
+
] }),
|
|
2439
|
+
/* @__PURE__ */ jsx(SheetDescription, { className: "sr-only", children: "Browse tables, columns, joins, and query patterns from the semantic layer" })
|
|
2440
|
+
] }),
|
|
2355
2441
|
/* @__PURE__ */ jsx(Separator, { className: "mt-3" }),
|
|
2356
2442
|
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden pt-3", children: loading ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-400", children: "Loading schema..." }) }) : error ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center px-4", children: /* @__PURE__ */ jsx("p", { className: "text-center text-xs text-red-500", children: error }) }) : selectedName ? detailError ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-2 px-4", children: [
|
|
2357
2443
|
/* @__PURE__ */ jsx("p", { className: "text-center text-xs text-red-500", children: detailError }),
|
|
@@ -2519,7 +2605,9 @@ function AtlasChat(props) {
|
|
|
2519
2605
|
sidebar = false,
|
|
2520
2606
|
schemaExplorer: schemaExplorerEnabled = false,
|
|
2521
2607
|
authClient = noopAuthClient,
|
|
2522
|
-
toolRenderers
|
|
2608
|
+
toolRenderers,
|
|
2609
|
+
chatEndpoint = "/api/v1/chat",
|
|
2610
|
+
conversationsEndpoint = "/api/v1/conversations"
|
|
2523
2611
|
} = props;
|
|
2524
2612
|
useEffect(() => {
|
|
2525
2613
|
setTheme(propTheme);
|
|
@@ -2530,7 +2618,9 @@ function AtlasChat(props) {
|
|
|
2530
2618
|
propApiKey,
|
|
2531
2619
|
sidebar,
|
|
2532
2620
|
schemaExplorerEnabled,
|
|
2533
|
-
toolRenderers
|
|
2621
|
+
toolRenderers,
|
|
2622
|
+
chatEndpoint,
|
|
2623
|
+
conversationsEndpoint
|
|
2534
2624
|
}
|
|
2535
2625
|
) });
|
|
2536
2626
|
}
|
|
@@ -2538,7 +2628,9 @@ function AtlasChatInner({
|
|
|
2538
2628
|
propApiKey,
|
|
2539
2629
|
sidebar,
|
|
2540
2630
|
schemaExplorerEnabled,
|
|
2541
|
-
toolRenderers
|
|
2631
|
+
toolRenderers,
|
|
2632
|
+
chatEndpoint,
|
|
2633
|
+
conversationsEndpoint
|
|
2542
2634
|
}) {
|
|
2543
2635
|
const { apiUrl, isCrossOrigin, authClient } = useAtlasConfig();
|
|
2544
2636
|
const dark = useDarkMode();
|
|
@@ -2572,7 +2664,8 @@ function AtlasChatInner({
|
|
|
2572
2664
|
apiUrl,
|
|
2573
2665
|
enabled: sidebar,
|
|
2574
2666
|
getHeaders,
|
|
2575
|
-
getCredentials
|
|
2667
|
+
getCredentials,
|
|
2668
|
+
conversationsEndpoint
|
|
2576
2669
|
});
|
|
2577
2670
|
const refreshConvosRef = useRef(convos.refresh);
|
|
2578
2671
|
refreshConvosRef.current = convos.refresh;
|
|
@@ -2664,7 +2757,7 @@ function AtlasChatInner({
|
|
|
2664
2757
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
2665
2758
|
}
|
|
2666
2759
|
return new DefaultChatTransport({
|
|
2667
|
-
api: `${apiUrl}
|
|
2760
|
+
api: `${apiUrl}${chatEndpoint}`,
|
|
2668
2761
|
headers,
|
|
2669
2762
|
credentials: isCrossOrigin ? "include" : void 0,
|
|
2670
2763
|
body: () => conversationIdRef.current ? { conversationId: conversationIdRef.current } : {},
|
|
@@ -2682,7 +2775,7 @@ function AtlasChatInner({
|
|
|
2682
2775
|
return response;
|
|
2683
2776
|
})
|
|
2684
2777
|
});
|
|
2685
|
-
}, [apiKey, apiUrl, isCrossOrigin]);
|
|
2778
|
+
}, [apiKey, apiUrl, isCrossOrigin, chatEndpoint]);
|
|
2686
2779
|
const { messages, setMessages, sendMessage, status, error } = useChat({ transport });
|
|
2687
2780
|
const isLoading = status === "streaming" || status === "submitted";
|
|
2688
2781
|
useEffect(() => {
|
|
@@ -2707,17 +2800,12 @@ function AtlasChatInner({
|
|
|
2707
2800
|
setLoadingConversation(true);
|
|
2708
2801
|
try {
|
|
2709
2802
|
const uiMessages = await convos.loadConversation(id);
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
setMobileMenuOpen(false);
|
|
2715
|
-
} else {
|
|
2716
|
-
setHealthWarning("Could not load conversation. It may have been deleted.");
|
|
2717
|
-
setTimeout(() => setHealthWarning(""), 5e3);
|
|
2718
|
-
}
|
|
2803
|
+
setMessages(uiMessages);
|
|
2804
|
+
setConversationId(id);
|
|
2805
|
+
convos.setSelectedId(id);
|
|
2806
|
+
setMobileMenuOpen(false);
|
|
2719
2807
|
} catch (err) {
|
|
2720
|
-
console.warn("Failed to load conversation:", err);
|
|
2808
|
+
console.warn("Failed to load conversation:", err instanceof Error ? err.message : String(err));
|
|
2721
2809
|
setHealthWarning("Failed to load conversation. Please try again.");
|
|
2722
2810
|
setTimeout(() => setHealthWarning(""), 5e3);
|
|
2723
2811
|
} finally {
|
|
@@ -2751,14 +2839,16 @@ function AtlasChatInner({
|
|
|
2751
2839
|
onMobileClose: () => setMobileMenuOpen(false)
|
|
2752
2840
|
}
|
|
2753
2841
|
),
|
|
2754
|
-
/* @__PURE__ */ jsx("main", { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-4xl flex-1 flex-col overflow-hidden p-4", children: [
|
|
2842
|
+
/* @__PURE__ */ jsx("main", { id: "main", tabIndex: -1, className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-4xl flex-1 flex-col overflow-hidden p-4", children: [
|
|
2755
2843
|
/* @__PURE__ */ jsx("header", { className: "mb-4 flex-none border-b border-zinc-100 pb-3 dark:border-zinc-800", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2756
2844
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2757
2845
|
showSidebar && /* @__PURE__ */ jsx(
|
|
2758
|
-
|
|
2846
|
+
Button,
|
|
2759
2847
|
{
|
|
2848
|
+
variant: "ghost",
|
|
2849
|
+
size: "icon",
|
|
2760
2850
|
onClick: () => setMobileMenuOpen(true),
|
|
2761
|
-
className: "
|
|
2851
|
+
className: "size-11 text-zinc-400 hover:text-zinc-700 md:hidden dark:hover:text-zinc-200",
|
|
2762
2852
|
"aria-label": "Open conversation history",
|
|
2763
2853
|
children: MenuIcon
|
|
2764
2854
|
}
|
|
@@ -2787,8 +2877,10 @@ function AtlasChatInner({
|
|
|
2787
2877
|
isSignedIn && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2788
2878
|
/* @__PURE__ */ jsx("span", { className: "hidden text-xs text-zinc-500 sm:inline dark:text-zinc-400", children: managedSession.data?.user?.email }),
|
|
2789
2879
|
/* @__PURE__ */ jsx(
|
|
2790
|
-
|
|
2880
|
+
Button,
|
|
2791
2881
|
{
|
|
2882
|
+
variant: "outline",
|
|
2883
|
+
size: "sm",
|
|
2792
2884
|
onClick: () => {
|
|
2793
2885
|
authClient.signOut().catch((err) => {
|
|
2794
2886
|
console.error("Sign out failed:", err);
|
|
@@ -2796,75 +2888,101 @@ function AtlasChatInner({
|
|
|
2796
2888
|
setTimeout(() => setHealthWarning(""), 5e3);
|
|
2797
2889
|
});
|
|
2798
2890
|
},
|
|
2799
|
-
className: "
|
|
2891
|
+
className: "text-xs text-zinc-500 dark:text-zinc-400",
|
|
2800
2892
|
children: "Sign out"
|
|
2801
2893
|
}
|
|
2802
2894
|
)
|
|
2803
2895
|
] })
|
|
2804
2896
|
] })
|
|
2805
2897
|
] }) }),
|
|
2806
|
-
healthWarning && /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-zinc-400 dark:text-zinc-500", children: healthWarning }),
|
|
2898
|
+
(healthWarning || convos.fetchError) && /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-zinc-400 dark:text-zinc-500", children: healthWarning || convos.fetchError }),
|
|
2807
2899
|
isManaged && !isSignedIn ? /* @__PURE__ */ jsx(ManagedAuthCard, {}) : /* @__PURE__ */ jsxs(ActionAuthProvider, { getHeaders, getCredentials, children: [
|
|
2808
2900
|
authMode === "simple-key" && !propApiKey && /* @__PURE__ */ jsx("div", { className: "mb-3 flex-none", children: /* @__PURE__ */ jsx(ApiKeyBar, { apiKey, onSave: handleSaveApiKey }) }),
|
|
2809
|
-
/* @__PURE__ */ jsx(ScrollArea, { viewportRef: scrollRef, className: "min-h-0 flex-1", children: /* @__PURE__ */
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
/* @__PURE__ */ jsx("p", {
|
|
2901
|
+
/* @__PURE__ */ jsx(ScrollArea, { viewportRef: scrollRef, className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(
|
|
2902
|
+
ErrorBoundary,
|
|
2903
|
+
{
|
|
2904
|
+
fallbackRender: (_error, reset) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-2 p-6 text-sm text-red-600 dark:text-red-400", children: [
|
|
2905
|
+
/* @__PURE__ */ jsx("p", { children: "Failed to render messages." }),
|
|
2906
|
+
/* @__PURE__ */ jsx(Button, { variant: "link", size: "sm", onClick: reset, className: "text-xs", children: "Try again" })
|
|
2814
2907
|
] }),
|
|
2815
|
-
/* @__PURE__ */
|
|
2816
|
-
"
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
const displayText = parseSuggestions(part.text).text;
|
|
2838
|
-
if (!displayText.trim()) return null;
|
|
2839
|
-
return /* @__PURE__ */ jsx("div", { className: "max-w-[90%]", children: /* @__PURE__ */ jsx("div", { className: "rounded-xl bg-zinc-100 px-4 py-3 text-sm text-zinc-800 dark:bg-zinc-800 dark:text-zinc-200", children: /* @__PURE__ */ jsx(Markdown, { content: displayText }) }) }, i);
|
|
2840
|
-
}
|
|
2841
|
-
if (isToolUIPart(part)) {
|
|
2842
|
-
return /* @__PURE__ */ jsx("div", { className: "max-w-[95%]", children: /* @__PURE__ */ jsx(ToolPart, { part, toolRenderers }) }, i);
|
|
2908
|
+
children: /* @__PURE__ */ jsxs("div", { "data-atlas-messages": true, className: "space-y-4 pb-4 pr-3", children: [
|
|
2909
|
+
messages.length === 0 && !error && /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-6", children: [
|
|
2910
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
2911
|
+
/* @__PURE__ */ jsx("p", { className: "text-lg font-medium text-zinc-500 dark:text-zinc-400", children: "What would you like to know?" }),
|
|
2912
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-zinc-500 dark:text-zinc-500", children: "Ask a question about your data to get started" })
|
|
2913
|
+
] }),
|
|
2914
|
+
/* @__PURE__ */ jsx("div", { className: "grid w-full max-w-lg grid-cols-1 gap-2 sm:grid-cols-2", children: STARTER_PROMPTS.map((prompt) => /* @__PURE__ */ jsx(
|
|
2915
|
+
Button,
|
|
2916
|
+
{
|
|
2917
|
+
variant: "outline",
|
|
2918
|
+
onClick: () => handleSend(prompt),
|
|
2919
|
+
className: "h-auto whitespace-normal justify-start rounded-lg bg-zinc-50 px-3 py-2.5 text-left text-sm text-zinc-500 hover:text-zinc-800 dark:bg-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-200",
|
|
2920
|
+
children: prompt
|
|
2921
|
+
},
|
|
2922
|
+
prompt
|
|
2923
|
+
)) })
|
|
2924
|
+
] }),
|
|
2925
|
+
messages.map((m, msgIndex) => {
|
|
2926
|
+
if (m.role === "user") {
|
|
2927
|
+
return /* @__PURE__ */ jsx("div", { className: "flex justify-end", role: "article", "aria-label": "Message from you", children: /* @__PURE__ */ jsx("div", { className: "max-w-[85%] rounded-xl bg-blue-600 px-4 py-3 text-sm text-white", children: m.parts?.map(
|
|
2928
|
+
(part, i) => part.type === "text" ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: part.text }, i) : null
|
|
2929
|
+
) }) }, m.id);
|
|
2843
2930
|
}
|
|
2844
|
-
|
|
2931
|
+
const isLastAssistant = m.role === "assistant" && msgIndex === messages.length - 1;
|
|
2932
|
+
const hasVisibleParts = m.parts?.some(
|
|
2933
|
+
(p) => p.type === "text" && p.text.trim() || isToolUIPart(p)
|
|
2934
|
+
);
|
|
2935
|
+
if (!hasVisibleParts && !isLastAssistant) return null;
|
|
2936
|
+
const lastTextWithSuggestions = m.parts?.filter((p) => p.type === "text" && !!p.text.trim()).findLast((p) => parseSuggestions(p.text).suggestions.length > 0);
|
|
2937
|
+
const suggestions = lastTextWithSuggestions ? parseSuggestions(lastTextWithSuggestions.text).suggestions : [];
|
|
2938
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", role: "article", "aria-label": "Message from Atlas", children: [
|
|
2939
|
+
m.parts?.map((part, i) => {
|
|
2940
|
+
if (part.type === "text" && part.text.trim()) {
|
|
2941
|
+
const displayText = parseSuggestions(part.text).text;
|
|
2942
|
+
if (!displayText.trim()) return null;
|
|
2943
|
+
return /* @__PURE__ */ jsx("div", { className: "max-w-[90%]", children: /* @__PURE__ */ jsx("div", { className: "rounded-xl bg-zinc-100 px-4 py-3 text-sm text-zinc-800 dark:bg-zinc-800 dark:text-zinc-200", children: /* @__PURE__ */ jsx(Markdown, { content: displayText }) }) }, i);
|
|
2944
|
+
}
|
|
2945
|
+
if (isToolUIPart(part)) {
|
|
2946
|
+
return /* @__PURE__ */ jsx("div", { className: "max-w-[95%]", children: /* @__PURE__ */ jsx(ToolPart, { part, toolRenderers }) }, i);
|
|
2947
|
+
}
|
|
2948
|
+
return null;
|
|
2949
|
+
}),
|
|
2950
|
+
isLastAssistant && !hasVisibleParts && !isLoading && error && /* @__PURE__ */ jsx("div", { className: "max-w-[90%]", children: /* @__PURE__ */ jsx("div", { className: "rounded-xl bg-red-50 px-4 py-3 text-sm text-red-700 dark:bg-red-950/30 dark:text-red-400", children: error.message ? `Something went wrong generating a response: ${error.message}. Try sending your message again.` : "Something went wrong generating a response. Try sending your message again." }) }),
|
|
2951
|
+
isLastAssistant && !isLoading && hasVisibleParts && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2952
|
+
/* @__PURE__ */ jsx(
|
|
2953
|
+
FollowUpChips,
|
|
2954
|
+
{
|
|
2955
|
+
suggestions,
|
|
2956
|
+
onSelect: handleSend
|
|
2957
|
+
}
|
|
2958
|
+
),
|
|
2959
|
+
conversationId && sidebar && convos.available && /* @__PURE__ */ jsx(
|
|
2960
|
+
SaveButton,
|
|
2961
|
+
{
|
|
2962
|
+
conversationId,
|
|
2963
|
+
conversations: convos.conversations,
|
|
2964
|
+
onStar: convos.starConversation
|
|
2965
|
+
}
|
|
2966
|
+
)
|
|
2967
|
+
] })
|
|
2968
|
+
] }, m.id);
|
|
2845
2969
|
}),
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
] })
|
|
2863
|
-
] }, m.id);
|
|
2864
|
-
}),
|
|
2865
|
-
isLoading && messages.length > 0 && /* @__PURE__ */ jsx(TypingIndicator, {})
|
|
2866
|
-
] }) }),
|
|
2867
|
-
error && /* @__PURE__ */ jsx(ErrorBanner, { error, authMode }),
|
|
2970
|
+
isLoading && messages.length > 0 && /* @__PURE__ */ jsx(TypingIndicator, {})
|
|
2971
|
+
] })
|
|
2972
|
+
}
|
|
2973
|
+
) }),
|
|
2974
|
+
error && /* @__PURE__ */ jsx(
|
|
2975
|
+
ErrorBanner,
|
|
2976
|
+
{
|
|
2977
|
+
error,
|
|
2978
|
+
authMode: authMode ?? "none",
|
|
2979
|
+
onRetry: messages.some((m) => m.role === "user") ? () => {
|
|
2980
|
+
const lastUserMsg = messages.toReversed().find((m) => m.role === "user");
|
|
2981
|
+
const text = lastUserMsg?.parts?.filter((p) => p.type === "text").map((p) => p.text).join(" ");
|
|
2982
|
+
if (text) handleSend(text);
|
|
2983
|
+
} : void 0
|
|
2984
|
+
}
|
|
2985
|
+
),
|
|
2868
2986
|
/* @__PURE__ */ jsxs(
|
|
2869
2987
|
"form",
|
|
2870
2988
|
{
|
|
@@ -2876,22 +2994,24 @@ function AtlasChatInner({
|
|
|
2876
2994
|
className: "flex flex-none gap-2 border-t border-zinc-100 pt-4 dark:border-zinc-800",
|
|
2877
2995
|
children: [
|
|
2878
2996
|
/* @__PURE__ */ jsx(
|
|
2879
|
-
|
|
2997
|
+
Input,
|
|
2880
2998
|
{
|
|
2881
2999
|
"data-atlas-input": true,
|
|
2882
3000
|
value: input,
|
|
2883
3001
|
onChange: (e) => setInput(e.target.value),
|
|
2884
3002
|
placeholder: "Ask a question about your data...",
|
|
2885
|
-
className: "min-w-0 flex-1
|
|
2886
|
-
disabled: isLoading || healthFailed
|
|
3003
|
+
className: "min-w-0 flex-1 py-3 text-base sm:text-sm",
|
|
3004
|
+
disabled: isLoading || healthFailed,
|
|
3005
|
+
"aria-label": "Chat message"
|
|
2887
3006
|
}
|
|
2888
3007
|
),
|
|
2889
3008
|
/* @__PURE__ */ jsx(
|
|
2890
|
-
|
|
3009
|
+
Button,
|
|
2891
3010
|
{
|
|
2892
3011
|
type: "submit",
|
|
2893
|
-
disabled: isLoading || healthFailed
|
|
2894
|
-
|
|
3012
|
+
disabled: isLoading || healthFailed,
|
|
3013
|
+
"aria-disabled": !(isLoading || healthFailed) && !input.trim() ? true : void 0,
|
|
3014
|
+
className: "shrink-0 px-5",
|
|
2895
3015
|
children: "Ask"
|
|
2896
3016
|
}
|
|
2897
3017
|
)
|