@useatlas/react 0.0.1 → 0.0.2

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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -2
  3. package/dist/{chunk-5SEVKHS5.cjs → chunk-35SCTKSW.js} +100 -7
  4. package/dist/chunk-35SCTKSW.js.map +1 -0
  5. package/dist/{chunk-UIRB6L36.cjs → chunk-DZFSZSQB.cjs} +46 -54
  6. package/dist/chunk-DZFSZSQB.cjs.map +1 -0
  7. package/dist/{chunk-2WFDP7G5.js → chunk-FMSGREKS.js} +46 -54
  8. package/dist/chunk-FMSGREKS.js.map +1 -0
  9. package/dist/{chunk-44HBZYKP.js → chunk-IDXGFWFS.cjs} +109 -3
  10. package/dist/chunk-IDXGFWFS.cjs.map +1 -0
  11. package/dist/global.d.ts +36 -0
  12. package/dist/hooks.cjs +10 -10
  13. package/dist/hooks.cjs.map +1 -1
  14. package/dist/hooks.d.cts +2 -2
  15. package/dist/hooks.d.ts +2 -2
  16. package/dist/hooks.js +3 -3
  17. package/dist/hooks.js.map +1 -1
  18. package/dist/index.cjs +385 -265
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +224 -4
  21. package/dist/index.d.ts +224 -4
  22. package/dist/index.js +328 -208
  23. package/dist/index.js.map +1 -1
  24. package/dist/lib/widget-types.d.ts +232 -0
  25. package/dist/{result-chart-YLCKBNV4.cjs → result-chart-ANZOT6FL.cjs} +24 -34
  26. package/dist/result-chart-ANZOT6FL.cjs.map +1 -0
  27. package/dist/{result-chart-NFAJ4IQ5.js → result-chart-C3EJTN5G.js} +22 -32
  28. package/dist/result-chart-C3EJTN5G.js.map +1 -0
  29. package/dist/widget.css +2 -2
  30. package/dist/widget.js +215 -246
  31. package/package.json +26 -16
  32. package/src/components/__tests__/data-table.test.tsx +125 -0
  33. package/src/components/actions/action-approval-card.tsx +26 -19
  34. package/src/components/actions/action-status-badge.tsx +3 -3
  35. package/src/components/atlas-chat.tsx +97 -37
  36. package/src/components/chart/result-chart.tsx +13 -37
  37. package/src/components/chat/api-key-bar.tsx +4 -4
  38. package/src/components/chat/data-table.tsx +42 -3
  39. package/src/components/chat/error-banner.tsx +108 -5
  40. package/src/components/chat/follow-up-chips.tsx +1 -1
  41. package/src/components/chat/managed-auth-card.tsx +6 -6
  42. package/src/components/conversations/conversation-item.tsx +19 -14
  43. package/src/components/conversations/conversation-list.tsx +3 -3
  44. package/src/components/conversations/conversation-sidebar.tsx +15 -4
  45. package/src/components/conversations/delete-confirmation.tsx +2 -2
  46. package/src/components/error-boundary.tsx +66 -0
  47. package/src/components/schema-explorer/schema-explorer.tsx +4 -0
  48. package/src/env.d.ts +9 -7
  49. package/src/global.d.ts +36 -0
  50. package/src/hooks/__tests__/use-atlas-conversations.test.tsx +4 -6
  51. package/src/hooks/use-atlas-chat.ts +1 -1
  52. package/src/hooks/use-atlas-conversations.ts +2 -2
  53. package/src/hooks/use-conversations.ts +60 -68
  54. package/src/index.ts +8 -0
  55. package/src/lib/action-types.ts +2 -2
  56. package/src/lib/helpers.ts +16 -16
  57. package/src/lib/types.ts +3 -2
  58. package/src/lib/widget-types.ts +232 -0
  59. package/src/test-setup.ts +2 -2
  60. package/dist/chunk-2WFDP7G5.js.map +0 -1
  61. package/dist/chunk-44HBZYKP.js.map +0 -1
  62. package/dist/chunk-5SEVKHS5.cjs.map +0 -1
  63. package/dist/chunk-UIRB6L36.cjs.map +0 -1
  64. package/dist/result-chart-NFAJ4IQ5.js.map +0 -1
  65. package/dist/result-chart-YLCKBNV4.cjs.map +0 -1
@@ -82,7 +82,7 @@ export function downloadCSV(csv: string, filename = "atlas-results.csv") {
82
82
  a.download = filename;
83
83
  a.click();
84
84
  } catch (err) {
85
- console.error("CSV download failed:", err);
85
+ console.error("CSV download failed:", err instanceof Error ? err.message : String(err));
86
86
  window.alert("CSV download failed");
87
87
  } finally {
88
88
  if (url) {
@@ -105,36 +105,36 @@ export function coerceExcelCell(v: unknown): unknown {
105
105
  return String(v);
106
106
  }
107
107
 
108
- /** Trigger an Excel (.xlsx) download in the browser. Dynamically imports xlsx to avoid bundle bloat. */
108
+ /** Trigger an Excel (.xlsx) download in the browser. Dynamically imports exceljs to avoid bundle bloat. */
109
109
  export async function downloadExcel(
110
110
  columns: string[],
111
111
  rows: Record<string, unknown>[],
112
112
  filename = "atlas-results.xlsx",
113
113
  ) {
114
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
115
- let XLSX: any;
114
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- exceljs is an optional peer dependency; its types may not be available in consumer projects
115
+ let ExcelJS: any;
116
116
  try {
117
- XLSX = await import("xlsx" /* webpackIgnore: true */);
117
+ ExcelJS = await import("exceljs" /* webpackIgnore: true */);
118
118
  } catch (err) {
119
- console.error("Failed to load xlsx library:", err);
119
+ console.error("Failed to load exceljs library:", err instanceof Error ? err.message : String(err));
120
120
  window.alert("Excel export is unavailable. The spreadsheet library failed to load.");
121
121
  return;
122
122
  }
123
123
 
124
124
  let url: string | null = null;
125
125
  try {
126
- const data = rows.map((row) => {
126
+ const wb = new ExcelJS.Workbook();
127
+ const ws = wb.addWorksheet("Results");
128
+ ws.columns = columns.map((col: string) => ({ header: col, key: col }));
129
+ for (const row of rows) {
127
130
  const obj: Record<string, unknown> = {};
128
131
  for (const col of columns) {
129
132
  obj[col] = coerceExcelCell(row[col]);
130
133
  }
131
- return obj;
132
- });
133
- const ws = XLSX.utils.json_to_sheet(data, { header: columns });
134
- const wb = XLSX.utils.book_new();
135
- XLSX.utils.book_append_sheet(wb, ws, "Results");
136
- const wbOut = XLSX.write(wb, { bookType: "xlsx", type: "array" });
137
- const blob = new Blob([wbOut], {
134
+ ws.addRow(obj);
135
+ }
136
+ const buffer = await wb.xlsx.writeBuffer();
137
+ const blob = new Blob([buffer], {
138
138
  type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
139
139
  });
140
140
  url = URL.createObjectURL(blob);
@@ -143,8 +143,8 @@ export async function downloadExcel(
143
143
  a.download = filename;
144
144
  a.click();
145
145
  } catch (err) {
146
- console.error("Excel download failed:", err);
147
- const detail = err instanceof Error ? err.message : "Unknown error";
146
+ const detail = err instanceof Error ? err.message : String(err);
147
+ console.error("Excel download failed:", detail);
148
148
  window.alert(`Excel download failed: ${detail}\n\nYou can try the CSV download as an alternative.`);
149
149
  } finally {
150
150
  if (url) {
package/src/lib/types.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * All types are canonical from @useatlas/types — no local duplication.
5
5
  */
6
6
 
7
- export { AUTH_MODES, DB_TYPES, CHAT_ERROR_CODES } from "@useatlas/types";
7
+ export { AUTH_MODES, DB_TYPES, CHAT_ERROR_CODES, CLIENT_ERROR_CODES } from "@useatlas/types";
8
8
  export type {
9
9
  AuthMode,
10
10
  MessageRole,
@@ -18,6 +18,7 @@ export type {
18
18
  ConnectionInfo,
19
19
  ChatErrorCode,
20
20
  ChatErrorInfo,
21
+ ClientErrorCode,
21
22
  Dimension,
22
23
  Join,
23
24
  Measure,
@@ -26,4 +27,4 @@ export type {
26
27
  SemanticEntityDetail,
27
28
  EntityData,
28
29
  } from "@useatlas/types";
29
- export { authErrorMessage, parseChatError } from "@useatlas/types/errors";
30
+ export { authErrorMessage, parseChatError, classifyClientError } from "@useatlas/types/errors";
@@ -0,0 +1,232 @@
1
+ /**
2
+ * TypeScript type definitions for the Atlas widget script-tag API.
3
+ *
4
+ * When embedded via `<script src="https://api.example.com/widget.js">`,
5
+ * the loader exposes `window.Atlas` with a programmatic API for controlling
6
+ * the chat widget.
7
+ *
8
+ * **Usage for embedders:**
9
+ *
10
+ * Add a triple-slash reference at the top of your script to get full
11
+ * autocomplete and type-checking:
12
+ *
13
+ * ```ts
14
+ * /// <reference types="@useatlas/react/widget" />
15
+ *
16
+ * Atlas.open();
17
+ * Atlas.ask("How many users signed up today?");
18
+ * Atlas.on("queryComplete", (detail) => {
19
+ * console.log("Query returned", detail.rowCount, "rows");
20
+ * });
21
+ * ```
22
+ *
23
+ * @module
24
+ */
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // Event map
28
+ // ---------------------------------------------------------------------------
29
+
30
+ /**
31
+ * Map of event names to their detail payloads.
32
+ *
33
+ * Used by {@link AtlasWidget.on} to provide type-safe event handling.
34
+ */
35
+ export interface AtlasWidgetEventMap {
36
+ /** Fired when the widget panel opens. */
37
+ open: Record<string, never>;
38
+ /** Fired when the widget panel closes. */
39
+ close: Record<string, never>;
40
+ /** Fired when a SQL query completes inside the widget. */
41
+ queryComplete: { sql?: string; rowCount?: number };
42
+ /** Fired when the widget encounters an error. */
43
+ error: { code?: string; message?: string };
44
+ }
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Script-tag configuration (data-* attributes)
48
+ // ---------------------------------------------------------------------------
49
+
50
+ /**
51
+ * Configuration options read from `data-*` attributes on the `<script>` tag.
52
+ *
53
+ * @example
54
+ * ```html
55
+ * <script src="https://api.example.com/widget.js"
56
+ * data-api-url="https://api.example.com"
57
+ * data-api-key="sk-..."
58
+ * data-theme="dark"
59
+ * data-position="bottom-left"
60
+ * data-on-open="onAtlasOpen"
61
+ * data-on-error="onAtlasError">
62
+ * </script>
63
+ * ```
64
+ */
65
+ export interface AtlasWidgetConfig {
66
+ /**
67
+ * Base URL of the Atlas API (required).
68
+ *
69
+ * Must use `http:` or `https:` protocol.
70
+ */
71
+ apiUrl: string;
72
+ /**
73
+ * API key for authentication (optional).
74
+ *
75
+ * Passed to the widget iframe as an auth token.
76
+ */
77
+ apiKey?: string;
78
+ /**
79
+ * Widget color theme (optional, default `"light"`).
80
+ */
81
+ theme?: "light" | "dark";
82
+ /**
83
+ * Position of the floating chat bubble (optional, default `"bottom-right"`).
84
+ */
85
+ position?: "bottom-right" | "bottom-left";
86
+ /**
87
+ * Name of a global function called when the widget opens (optional).
88
+ *
89
+ * The function must exist on `window` at the time the event fires.
90
+ */
91
+ onOpen?: string;
92
+ /**
93
+ * Name of a global function called when the widget closes (optional).
94
+ */
95
+ onClose?: string;
96
+ /**
97
+ * Name of a global function called when a query completes (optional).
98
+ */
99
+ onQueryComplete?: string;
100
+ /**
101
+ * Name of a global function called when the widget encounters an error (optional).
102
+ */
103
+ onError?: string;
104
+ }
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // Programmatic API
108
+ // ---------------------------------------------------------------------------
109
+
110
+ /**
111
+ * Programmatic API exposed on `window.Atlas` after the widget script loads.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * /// <reference types="@useatlas/react/widget" />
116
+ *
117
+ * // Open the widget
118
+ * Atlas.open();
119
+ *
120
+ * // Send a question programmatically
121
+ * Atlas.ask("What are the top 10 customers by revenue?");
122
+ *
123
+ * // Listen for events
124
+ * Atlas.on("queryComplete", (detail) => {
125
+ * console.log(`Query returned ${detail.rowCount} rows`);
126
+ * });
127
+ *
128
+ * // Change theme at runtime
129
+ * Atlas.setTheme("dark");
130
+ *
131
+ * // Clean up when done
132
+ * Atlas.destroy();
133
+ * ```
134
+ */
135
+ export interface AtlasWidget {
136
+ /**
137
+ * Opens the widget panel.
138
+ *
139
+ * No-op if the widget has been destroyed.
140
+ */
141
+ open(): void;
142
+
143
+ /**
144
+ * Closes the widget panel.
145
+ *
146
+ * No-op if the widget has been destroyed.
147
+ */
148
+ close(): void;
149
+
150
+ /**
151
+ * Toggles the widget panel open or closed.
152
+ *
153
+ * No-op if the widget has been destroyed.
154
+ */
155
+ toggle(): void;
156
+
157
+ /**
158
+ * Opens the widget and sends a question to the Atlas agent.
159
+ *
160
+ * @param question - The natural-language question to ask.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * Atlas.ask("How many users signed up this week?");
165
+ * ```
166
+ */
167
+ ask(question: string): void;
168
+
169
+ /**
170
+ * Removes the widget from the DOM, cleans up all event listeners,
171
+ * and deletes `window.Atlas`.
172
+ *
173
+ * After calling `destroy()`, all other methods become no-ops.
174
+ */
175
+ destroy(): void;
176
+
177
+ /**
178
+ * Binds a type-safe event listener.
179
+ *
180
+ * Supported events: `"open"`, `"close"`, `"queryComplete"`, `"error"`.
181
+ *
182
+ * @param event - The event name.
183
+ * @param handler - Callback receiving the event detail payload.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * Atlas.on("error", (detail) => {
188
+ * console.error(`Atlas error [${detail.code}]: ${detail.message}`);
189
+ * });
190
+ * ```
191
+ */
192
+ on<K extends keyof AtlasWidgetEventMap>(
193
+ event: K,
194
+ handler: (detail: AtlasWidgetEventMap[K]) => void,
195
+ ): void;
196
+
197
+ /**
198
+ * Sends an authentication token to the widget iframe.
199
+ *
200
+ * Use this when the auth token is obtained after the script tag loads
201
+ * (e.g., after a user logs in).
202
+ *
203
+ * @param token - The authentication token string.
204
+ */
205
+ setAuthToken(token: string): void;
206
+
207
+ /**
208
+ * Sets the widget color theme at runtime.
209
+ *
210
+ * @param theme - `"light"` or `"dark"`.
211
+ */
212
+ setTheme(theme: "light" | "dark"): void;
213
+ }
214
+
215
+ /**
216
+ * Pre-load command queue entry.
217
+ *
218
+ * Before the widget script loads, `window.Atlas` can be set to an array
219
+ * of queued commands that are replayed once the widget initializes:
220
+ *
221
+ * ```ts
222
+ * window.Atlas = window.Atlas || [];
223
+ * Atlas.push(["open"]);
224
+ * Atlas.push(["ask", "How many users signed up today?"]);
225
+ * ```
226
+ *
227
+ * Each entry is a tuple of `[methodName, ...args]`.
228
+ */
229
+ export type AtlasWidgetCommand = [
230
+ keyof AtlasWidget,
231
+ ...unknown[],
232
+ ];
package/src/test-setup.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Window } from "happy-dom";
1
+ import { GlobalWindow } from "happy-dom";
2
2
 
3
- const win = new Window({ url: "http://localhost:3000" });
3
+ const win = new GlobalWindow({ url: "http://localhost:3000" });
4
4
 
5
5
  const DOM_GLOBALS = [
6
6
  "document", "navigator", "location", "history", "screen",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/theme-init-script.ts","../src/hooks/use-dark-mode.ts","../src/hooks/use-conversations.ts"],"names":[],"mappings":"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","file":"chunk-2WFDP7G5.js","sourcesContent":["/**\n * Blocking inline script for layout.tsx — prevents dark-mode flash on load.\n *\n * This file intentionally has NO \"use client\" directive so it can be imported\n * by server components (layout.tsx). The storage key must stay in sync with\n * use-dark-mode.ts.\n */\n\nexport const THEME_STORAGE_KEY = \"atlas-theme\";\n\n/**\n * Returns the inline script string for the blocking `<script>` in layout.tsx.\n * Reads atlas-theme from localStorage and sets the `dark` class before first paint.\n */\nexport function buildThemeInitScript(): string {\n return `try{var t=localStorage.getItem(\"${THEME_STORAGE_KEY}\");var d=t===\"dark\"||(t!==\"light\"&&window.matchMedia(\"(prefers-color-scheme:dark)\").matches);if(d)document.documentElement.classList.add(\"dark\")}catch(e){}`;\n}\n","\"use client\";\n\nimport { createContext, useSyncExternalStore } from \"react\";\n\n// ---------------------------------------------------------------------------\n// Theme types & constants\n// ---------------------------------------------------------------------------\n\nimport { THEME_STORAGE_KEY } from \"./theme-init-script\";\n\nexport type ThemeMode = \"light\" | \"dark\" | \"system\";\n\nexport { THEME_STORAGE_KEY };\n\n/**\n * Default brand color — must match `brand.css` `:root { --atlas-brand }` and\n * the `ATLAS_BRAND_COLOR` default in `packages/api/src/lib/settings.ts`.\n */\nexport const DEFAULT_BRAND_COLOR = \"oklch(0.759 0.148 167.71)\";\n\n/** Basic oklch format check — prevents obviously invalid values from breaking the theme. */\nexport const OKLCH_RE = /^oklch\\(\\s*[\\d.]+\\s+[\\d.]+\\s+[\\d.]+\\s*(?:\\/\\s*[\\d.%]+\\s*)?\\)$/;\n\n// ---------------------------------------------------------------------------\n// Shared state — single source of truth for the chosen mode.\n// Listeners are notified on change so useSyncExternalStore re-renders.\n// ---------------------------------------------------------------------------\n\nlet _mode: ThemeMode = \"system\";\nconst _listeners = new Set<() => void>();\n\nfunction notify() {\n for (const fn of _listeners) fn();\n}\n\n/** Read stored preference (called once on module load in the browser). */\nfunction init() {\n try {\n const stored = localStorage.getItem(THEME_STORAGE_KEY);\n if (stored === \"light\" || stored === \"dark\" || stored === \"system\") {\n _mode = stored;\n }\n } catch (err) {\n console.warn(\"Could not read theme preference from localStorage:\", err);\n }\n}\n\nif (typeof window !== \"undefined\") init();\n\n// ---------------------------------------------------------------------------\n// Derived boolean: is the effective theme dark?\n// ---------------------------------------------------------------------------\n\nfunction systemPrefersDark(): boolean {\n return typeof window !== \"undefined\" && window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n}\n\nfunction resolveIsDark(mode: ThemeMode): boolean {\n if (mode === \"dark\") return true;\n if (mode === \"light\") return false;\n return systemPrefersDark();\n}\n\nfunction applyClass(isDark: boolean) {\n if (typeof document === \"undefined\") return;\n document.documentElement.classList.toggle(\"dark\", isDark);\n}\n\n// ---------------------------------------------------------------------------\n// External store for isDark (reacts to both mode changes AND system changes)\n// ---------------------------------------------------------------------------\n\nfunction subscribeIsDark(onChange: () => void) {\n _listeners.add(onChange);\n\n // Also listen for system preference changes (relevant when mode === \"system\").\n // Apply dark class immediately on OS change so the DOM stays in sync before React re-renders.\n const mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n const handler = () => {\n applyClass(resolveIsDark(_mode));\n onChange();\n };\n mq.addEventListener(\"change\", handler);\n\n return () => {\n _listeners.delete(onChange);\n mq.removeEventListener(\"change\", handler);\n };\n}\n\nfunction getSnapshotIsDark() {\n return resolveIsDark(_mode);\n}\n\nfunction getServerSnapshotIsDark() {\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// External store for mode\n// ---------------------------------------------------------------------------\n\nfunction subscribeMode(onChange: () => void) {\n _listeners.add(onChange);\n return () => {\n _listeners.delete(onChange);\n };\n}\n\nfunction getSnapshotMode() {\n return _mode;\n}\n\nfunction getServerSnapshotMode(): ThemeMode {\n return \"system\";\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function setTheme(mode: ThemeMode) {\n _mode = mode;\n const isDark = resolveIsDark(mode);\n applyClass(isDark);\n try {\n localStorage.setItem(THEME_STORAGE_KEY, mode);\n } catch (err) {\n console.warn(\"Could not persist theme preference to localStorage:\", err);\n }\n notify();\n}\n\n/** Apply --atlas-brand on :root so theme tokens update without reload. */\nexport function applyBrandColor(color: string) {\n if (typeof document === \"undefined\") return;\n document.documentElement.style.setProperty(\"--atlas-brand\", color);\n}\n\nexport const DarkModeContext = createContext(false);\n\n/** Returns whether the effective theme is dark. */\nexport function useDarkMode(): boolean {\n return useSyncExternalStore(subscribeIsDark, getSnapshotIsDark, getServerSnapshotIsDark);\n}\n\n/** Returns the current ThemeMode (\"light\" | \"dark\" | \"system\"). */\nexport function useThemeMode(): ThemeMode {\n return useSyncExternalStore(subscribeMode, getSnapshotMode, getServerSnapshotMode);\n}\n","\"use client\";\n\nimport { useState, useCallback, useRef } from \"react\";\nimport type { Conversation, ConversationWithMessages, Message } from \"../lib/types\";\nimport type { UIMessage } from \"@ai-sdk/react\";\n\nexport interface UseConversationsOptions {\n apiUrl: string;\n enabled: boolean;\n getHeaders: () => Record<string, string>;\n getCredentials: () => RequestCredentials;\n}\n\nexport interface UseConversationsReturn {\n conversations: Conversation[];\n total: number;\n loading: boolean;\n available: boolean;\n selectedId: string | null;\n setSelectedId: (id: string | null) => void;\n fetchList: () => Promise<void>;\n loadConversation: (id: string) => Promise<UIMessage[] | null>;\n deleteConversation: (id: string) => Promise<boolean>;\n starConversation: (id: string, starred: boolean) => Promise<boolean>;\n refresh: () => Promise<void>;\n}\n\nexport function transformMessages(messages: Message[]): UIMessage[] {\n return messages\n .filter((m) => m.role === \"user\" || m.role === \"assistant\")\n .map((m) => {\n const content = typeof m.content === \"string\"\n ? m.content\n : JSON.stringify(m.content);\n\n return {\n id: m.id,\n role: m.role as \"user\" | \"assistant\",\n parts: [{ type: \"text\" as const, text: content }],\n };\n });\n}\n\nexport function useConversations(opts: UseConversationsOptions): UseConversationsReturn {\n const [conversations, setConversations] = useState<Conversation[]>([]);\n const [total, setTotal] = useState(0);\n const [loading, setLoading] = useState(false);\n const [available, setAvailable] = useState(true);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const fetchedRef = useRef(false);\n const networkFailRef = useRef(0);\n\n const fetchList = useCallback(async () => {\n if (!opts.enabled || !available) return;\n setLoading(true);\n try {\n const res = await fetch(`${opts.apiUrl}/api/v1/conversations?limit=50`, {\n headers: opts.getHeaders(),\n credentials: opts.getCredentials(),\n });\n\n if (res.status === 404) {\n setAvailable(false);\n return;\n }\n\n if (!res.ok) {\n const errorBody = await res.json().catch(() => null);\n if (errorBody?.code === \"not_available\") {\n setAvailable(false);\n return;\n }\n console.warn(`fetchList: HTTP ${res.status}`, errorBody);\n return;\n }\n\n const data = await res.json();\n setConversations(data.conversations ?? []);\n setTotal(data.total ?? 0);\n fetchedRef.current = true;\n } catch (err) {\n console.warn(\"fetchList error:\", err);\n // Network error before any successful fetch — disable temporarily.\n // A subsequent explicit fetchList() call can retry.\n if (!fetchedRef.current) {\n networkFailRef.current += 1;\n if (networkFailRef.current >= 3) setAvailable(false);\n }\n } finally {\n setLoading(false);\n }\n }, [opts.apiUrl, opts.enabled, opts.getHeaders, opts.getCredentials, available]);\n\n const loadConversation = useCallback(async (id: string): Promise<UIMessage[] | null> => {\n try {\n const res = await fetch(`${opts.apiUrl}/api/v1/conversations/${id}`, {\n headers: opts.getHeaders(),\n credentials: opts.getCredentials(),\n });\n\n if (!res.ok) {\n console.warn(`loadConversation: HTTP ${res.status} for ${id}`);\n return null;\n }\n\n const data: ConversationWithMessages = await res.json();\n return transformMessages(data.messages);\n } catch (err) {\n console.warn(\"loadConversation error:\", err);\n return null;\n }\n }, [opts.apiUrl, opts.getHeaders, opts.getCredentials]);\n\n const deleteConversation = useCallback(async (id: string): Promise<boolean> => {\n try {\n const res = await fetch(`${opts.apiUrl}/api/v1/conversations/${id}`, {\n method: \"DELETE\",\n headers: opts.getHeaders(),\n credentials: opts.getCredentials(),\n });\n\n if (!res.ok) {\n console.warn(`deleteConversation: HTTP ${res.status} for ${id}`);\n return false;\n }\n\n setConversations((prev) => prev.filter((c) => c.id !== id));\n setTotal((prev) => Math.max(0, prev - 1));\n\n if (selectedId === id) setSelectedId(null);\n\n return true;\n } catch (err) {\n console.warn(\"deleteConversation error:\", err);\n return false;\n }\n }, [opts.apiUrl, opts.getHeaders, opts.getCredentials, selectedId]);\n\n const starConversation = useCallback(async (id: string, starred: boolean): Promise<boolean> => {\n // Optimistic update\n setConversations((prev) =>\n prev.map((c) => (c.id === id ? { ...c, starred } : c)),\n );\n try {\n const res = await fetch(`${opts.apiUrl}/api/v1/conversations/${id}/star`, {\n method: \"PATCH\",\n headers: { ...opts.getHeaders(), \"Content-Type\": \"application/json\" },\n credentials: opts.getCredentials(),\n body: JSON.stringify({ starred }),\n });\n\n if (!res.ok) {\n console.warn(`starConversation: HTTP ${res.status} for ${id}`);\n // Rollback\n setConversations((prev) =>\n prev.map((c) => (c.id === id ? { ...c, starred: !starred } : c)),\n );\n return false;\n }\n\n return true;\n } catch (err) {\n console.warn(\"starConversation error:\", err);\n // Rollback\n setConversations((prev) =>\n prev.map((c) => (c.id === id ? { ...c, starred: !starred } : c)),\n );\n return false;\n }\n }, [opts.apiUrl, opts.getHeaders, opts.getCredentials]);\n\n const refresh = useCallback(async () => {\n await fetchList();\n }, [fetchList]);\n\n return {\n conversations,\n total,\n loading,\n available,\n selectedId,\n setSelectedId,\n fetchList,\n loadConversation,\n deleteConversation,\n starConversation,\n refresh,\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/chart/chart-detection.ts"],"names":[],"mappings":"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","file":"chunk-44HBZYKP.js","sourcesContent":["/* Chart detection — pure functions, zero React deps. Kept framework-agnostic for direct unit testing. */\n\nexport type ColumnType = \"numeric\" | \"date\" | \"categorical\" | \"unknown\";\n\nexport type ClassifiedColumn = {\n index: number;\n header: string;\n type: ColumnType;\n uniqueCount: number;\n};\n\nexport type ChartType = \"bar\" | \"line\" | \"pie\" | \"area\" | \"stacked-bar\" | \"scatter\";\n\nexport type ChartRecommendation = {\n type: ChartType;\n categoryColumn: ClassifiedColumn;\n valueColumns: [ClassifiedColumn, ...ClassifiedColumn[]];\n reason: string;\n};\n\nexport type RechartsRow = Record<string, string | number>;\n\ntype NonChartableResult = {\n chartable: false;\n columns: ClassifiedColumn[];\n};\n\ntype ChartableResult = {\n chartable: true;\n columns: ClassifiedColumn[];\n recommendations: [ChartRecommendation, ...ChartRecommendation[]];\n data: RechartsRow[];\n};\n\nexport type ChartDetectionResult = NonChartableResult | ChartableResult;\n\n/* ------------------------------------------------------------------ */\n/* Color palettes (Tailwind weights) */\n/* ------------------------------------------------------------------ */\n\nexport const CHART_COLORS_LIGHT = [\n \"#3b82f6\", // blue-500\n \"#10b981\", // emerald-500\n \"#f59e0b\", // amber-500\n \"#ef4444\", // red-500\n \"#8b5cf6\", // violet-500\n \"#06b6d4\", // cyan-500\n \"#f97316\", // orange-500\n \"#ec4899\", // pink-500\n];\n\nexport const CHART_COLORS_DARK = [\n \"#60a5fa\", // blue-400\n \"#34d399\", // emerald-400\n \"#fbbf24\", // amber-400\n \"#f87171\", // red-400\n \"#a78bfa\", // violet-400\n \"#22d3ee\", // cyan-400\n \"#fb923c\", // orange-400\n \"#f472b6\", // pink-400\n];\n\n/* ------------------------------------------------------------------ */\n/* Column classification */\n/* ------------------------------------------------------------------ */\n\nconst DATE_HEADER_HINTS = /^(date|month|year|quarter|week|day|period|time|timestamp)$/i;\nconst CATEGORICAL_HEADER_HINTS = /^(name|type|category|status|region|country|industry|department|plan|tier|segment|group|label|source|channel)$/i;\nconst SKIP_HEADER_HINTS = /^(id|uuid|_id|pk|key)$/i;\n\nconst ISO_DATE_RE = /^\\d{4}-\\d{2}/;\nconst MONTH_NAME_RE = /^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i;\nconst YEAR_ONLY_RE = /^(19|20)\\d{2}$/;\nconst QUARTER_RE = /^Q[1-4]\\s*\\d{4}$/i;\n\nexport function classifyColumn(header: string, values: string[]): ColumnType {\n const nonEmpty = values.filter((v) => v !== \"\" && v != null);\n if (nonEmpty.length === 0) return \"unknown\";\n\n // Header hint: skip ID-like columns\n if (SKIP_HEADER_HINTS.test(header)) return \"unknown\";\n\n // Numeric check: >80% parse as finite numbers (date check takes priority for overlapping values)\n const numericCount = nonEmpty.filter((v) => {\n const n = Number(v.replace(/,/g, \"\"));\n return isFinite(n);\n }).length;\n const numericRatio = numericCount / nonEmpty.length;\n\n // Date check: >70% match date patterns (>30% when header hints match)\n const dateCount = nonEmpty.filter(\n (v) => ISO_DATE_RE.test(v) || MONTH_NAME_RE.test(v) || YEAR_ONLY_RE.test(v) || QUARTER_RE.test(v),\n ).length;\n const dateRatio = dateCount / nonEmpty.length;\n\n // Header hint tiebreaker: if header matches date keywords...\n // (a) ...and at least some values look date-like, trust the header\n // (b) ...and values aren't overwhelmingly numeric (catches year-only values)\n if (DATE_HEADER_HINTS.test(header) && dateRatio > 0.3) return \"date\";\n if (DATE_HEADER_HINTS.test(header) && numericRatio < 0.9) return \"date\";\n\n if (dateRatio > 0.7) return \"date\";\n if (numericRatio > 0.8) return \"numeric\";\n\n // Categorical header hint\n if (CATEGORICAL_HEADER_HINTS.test(header)) return \"categorical\";\n\n // Categorical fallback: text values with <50 unique entries (higher cardinality suggests free-text or IDs)\n const unique = new Set(nonEmpty);\n if (unique.size < 50) return \"categorical\";\n\n return \"unknown\";\n}\n\n/* ------------------------------------------------------------------ */\n/* Chart recommendation engine */\n/* ------------------------------------------------------------------ */\n\nexport function detectCharts(headers: string[], rows: string[][]): ChartDetectionResult {\n if (headers.length === 0 || rows.length < 2) {\n return { chartable: false, columns: [] };\n }\n\n // Deduplicate headers so chart dataKey matches transformed data keys\n const seen = new Map<string, number>();\n const dedupedHeaders = headers.map((h) => {\n const count = seen.get(h) ?? 0;\n seen.set(h, count + 1);\n return count > 0 ? `${h}_${count + 1}` : h;\n });\n\n const columns: ClassifiedColumn[] = dedupedHeaders.map((header, index) => {\n const values = rows.map((r) => r[index] ?? \"\");\n const type = classifyColumn(header, values);\n const uniqueCount = new Set(values.filter((v) => v !== \"\")).size;\n return { index, header, type, uniqueCount };\n });\n\n const dateColumns = columns.filter((c) => c.type === \"date\");\n const numericColumns = columns.filter((c) => c.type === \"numeric\");\n const categoricalColumns = columns.filter((c) => c.type === \"categorical\");\n\n if (numericColumns.length === 0) {\n return { chartable: false, columns };\n }\n\n const recommendations: ChartRecommendation[] = [];\n\n // Line: date + numeric (time-series, highest priority)\n if (dateColumns.length >= 1 && numericColumns.length >= 1) {\n recommendations.push({\n type: \"line\",\n categoryColumn: dateColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Time-series: ${dateColumns[0].header} vs ${numericColumns.map((c) => c.header).join(\", \")}`,\n });\n }\n\n // Area: alternative to line for date + numeric (volume/magnitude over time)\n if (dateColumns.length >= 1 && numericColumns.length >= 1) {\n recommendations.push({\n type: \"area\",\n categoryColumn: dateColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Volume over time: ${numericColumns.map((c) => c.header).join(\", \")} by ${dateColumns[0].header}`,\n });\n }\n\n // Stacked bar: categorical + multiple numeric columns (part-to-whole comparison)\n if (categoricalColumns.length >= 1 && numericColumns.length >= 2) {\n recommendations.push({\n type: \"stacked-bar\",\n categoryColumn: categoricalColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Stacked: ${numericColumns.map((c) => c.header).join(\", \")} by ${categoricalColumns[0].header}`,\n });\n }\n\n // Bar: categorical + numeric\n if (categoricalColumns.length >= 1 && numericColumns.length >= 1) {\n recommendations.push({\n type: \"bar\",\n categoryColumn: categoricalColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Comparison: ${numericColumns.map((c) => c.header).join(\", \")} by ${categoricalColumns[0].header}`,\n });\n }\n\n // Pie: first categorical column (2-7 unique values) + first numeric column\n if (categoricalColumns.length >= 1 && numericColumns.length >= 1) {\n const cat = categoricalColumns[0];\n if (cat.uniqueCount >= 2 && cat.uniqueCount <= 7) {\n recommendations.push({\n type: \"pie\",\n categoryColumn: cat,\n valueColumns: [numericColumns[0]],\n reason: `Distribution: ${numericColumns[0].header} by ${cat.header}`,\n });\n }\n }\n\n // Scatter: 2+ numeric columns (correlation analysis)\n if (numericColumns.length >= 2) {\n const [xCol, yCol, ...rest] = numericColumns;\n const scatterValues = rest.length > 0\n ? [yCol, ...rest] as [ClassifiedColumn, ...ClassifiedColumn[]]\n : [yCol] as [ClassifiedColumn, ...ClassifiedColumn[]];\n recommendations.push({\n type: \"scatter\",\n categoryColumn: xCol,\n valueColumns: scatterValues,\n reason: `Correlation: ${xCol.header} vs ${yCol.header}${rest.length > 0 ? ` (size: ${rest[0].header})` : \"\"}`,\n });\n }\n\n // Fallback: when all columns are numeric, treat first as category axis (often an index or bucket label)\n if (!recommendations.some((r) => r.type === \"bar\") && numericColumns.length >= 2) {\n const first = columns[0];\n const rest = numericColumns.filter((c) => c.index !== first.index);\n if (rest.length >= 1) {\n recommendations.push({\n type: \"bar\",\n categoryColumn: first,\n valueColumns: rest as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Fallback: ${rest.map((c) => c.header).join(\", \")} by ${first.header}`,\n });\n }\n }\n\n // Also allow bar for date columns (as a secondary option after line)\n if (dateColumns.length >= 1 && numericColumns.length >= 1 && !recommendations.some((r) => r.type === \"bar\")) {\n recommendations.push({\n type: \"bar\",\n categoryColumn: dateColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Comparison: ${numericColumns.map((c) => c.header).join(\", \")} by ${dateColumns[0].header}`,\n });\n }\n\n if (recommendations.length === 0) {\n return { chartable: false, columns };\n }\n\n const data = transformData(rows, recommendations[0]);\n\n return {\n chartable: true,\n columns,\n recommendations: recommendations as [ChartRecommendation, ...ChartRecommendation[]],\n data,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Data transform */\n/* ------------------------------------------------------------------ */\n\nfunction parseNumericValue(raw: string): number {\n const cleaned = raw.replace(/[$%,\\s]/g, \"\");\n if (cleaned === \"\" || cleaned === \"-\") return 0;\n const num = Number(cleaned);\n return isFinite(num) ? num : 0;\n}\n\nfunction isFiniteNumeric(raw: string): boolean {\n const cleaned = raw.replace(/[$%,\\s]/g, \"\");\n if (cleaned === \"\" || cleaned === \"-\") return false;\n return isFinite(Number(cleaned));\n}\n\nexport function transformData(\n rows: string[][],\n recommendation: ChartRecommendation,\n): RechartsRow[] {\n const catIdx = recommendation.categoryColumn.index;\n const catHeader = recommendation.categoryColumn.header;\n const valIdxs = recommendation.valueColumns.map((c) => c.index);\n\n // Scatter: both axes are numeric — categoryColumn is x, first valueColumn is y, optional z for size\n // Filter out rows where x or y are non-numeric to avoid misleading zero-origin clusters\n if (recommendation.type === \"scatter\") {\n const yIdx = recommendation.valueColumns[0].index;\n return rows.flatMap((row) => {\n const rawX = row[catIdx] ?? \"\";\n const rawY = row[yIdx] ?? \"\";\n if (!isFiniteNumeric(rawX) || !isFiniteNumeric(rawY)) return [];\n const record: RechartsRow = {};\n record[catHeader] = parseNumericValue(rawX);\n for (const vc of recommendation.valueColumns) {\n record[vc.header] = parseNumericValue(row[vc.index] ?? \"0\");\n }\n return [record];\n });\n }\n\n // Cap rows for bar/stacked-bar charts with many categories\n let effectiveRows = rows;\n if ((recommendation.type === \"bar\" || recommendation.type === \"stacked-bar\") && rows.length > 30) {\n // Sort by first value column descending, take top 20\n const valIdx = valIdxs[0];\n effectiveRows = [...rows]\n .sort((a, b) => {\n const av = parseNumericValue(a[valIdx] ?? \"0\");\n const bv = parseNumericValue(b[valIdx] ?? \"0\");\n return bv - av;\n })\n .slice(0, 20);\n }\n\n return effectiveRows.map((row) => {\n const record: RechartsRow = {};\n record[catHeader] = row[catIdx] ?? \"\";\n for (const vc of recommendation.valueColumns) {\n record[vc.header] = parseNumericValue(row[vc.index] ?? \"0\");\n }\n return record;\n });\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/chart/chart-detection.ts"],"names":[],"mappings":"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","file":"chunk-5SEVKHS5.cjs","sourcesContent":["/* Chart detection — pure functions, zero React deps. Kept framework-agnostic for direct unit testing. */\n\nexport type ColumnType = \"numeric\" | \"date\" | \"categorical\" | \"unknown\";\n\nexport type ClassifiedColumn = {\n index: number;\n header: string;\n type: ColumnType;\n uniqueCount: number;\n};\n\nexport type ChartType = \"bar\" | \"line\" | \"pie\" | \"area\" | \"stacked-bar\" | \"scatter\";\n\nexport type ChartRecommendation = {\n type: ChartType;\n categoryColumn: ClassifiedColumn;\n valueColumns: [ClassifiedColumn, ...ClassifiedColumn[]];\n reason: string;\n};\n\nexport type RechartsRow = Record<string, string | number>;\n\ntype NonChartableResult = {\n chartable: false;\n columns: ClassifiedColumn[];\n};\n\ntype ChartableResult = {\n chartable: true;\n columns: ClassifiedColumn[];\n recommendations: [ChartRecommendation, ...ChartRecommendation[]];\n data: RechartsRow[];\n};\n\nexport type ChartDetectionResult = NonChartableResult | ChartableResult;\n\n/* ------------------------------------------------------------------ */\n/* Color palettes (Tailwind weights) */\n/* ------------------------------------------------------------------ */\n\nexport const CHART_COLORS_LIGHT = [\n \"#3b82f6\", // blue-500\n \"#10b981\", // emerald-500\n \"#f59e0b\", // amber-500\n \"#ef4444\", // red-500\n \"#8b5cf6\", // violet-500\n \"#06b6d4\", // cyan-500\n \"#f97316\", // orange-500\n \"#ec4899\", // pink-500\n];\n\nexport const CHART_COLORS_DARK = [\n \"#60a5fa\", // blue-400\n \"#34d399\", // emerald-400\n \"#fbbf24\", // amber-400\n \"#f87171\", // red-400\n \"#a78bfa\", // violet-400\n \"#22d3ee\", // cyan-400\n \"#fb923c\", // orange-400\n \"#f472b6\", // pink-400\n];\n\n/* ------------------------------------------------------------------ */\n/* Column classification */\n/* ------------------------------------------------------------------ */\n\nconst DATE_HEADER_HINTS = /^(date|month|year|quarter|week|day|period|time|timestamp)$/i;\nconst CATEGORICAL_HEADER_HINTS = /^(name|type|category|status|region|country|industry|department|plan|tier|segment|group|label|source|channel)$/i;\nconst SKIP_HEADER_HINTS = /^(id|uuid|_id|pk|key)$/i;\n\nconst ISO_DATE_RE = /^\\d{4}-\\d{2}/;\nconst MONTH_NAME_RE = /^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i;\nconst YEAR_ONLY_RE = /^(19|20)\\d{2}$/;\nconst QUARTER_RE = /^Q[1-4]\\s*\\d{4}$/i;\n\nexport function classifyColumn(header: string, values: string[]): ColumnType {\n const nonEmpty = values.filter((v) => v !== \"\" && v != null);\n if (nonEmpty.length === 0) return \"unknown\";\n\n // Header hint: skip ID-like columns\n if (SKIP_HEADER_HINTS.test(header)) return \"unknown\";\n\n // Numeric check: >80% parse as finite numbers (date check takes priority for overlapping values)\n const numericCount = nonEmpty.filter((v) => {\n const n = Number(v.replace(/,/g, \"\"));\n return isFinite(n);\n }).length;\n const numericRatio = numericCount / nonEmpty.length;\n\n // Date check: >70% match date patterns (>30% when header hints match)\n const dateCount = nonEmpty.filter(\n (v) => ISO_DATE_RE.test(v) || MONTH_NAME_RE.test(v) || YEAR_ONLY_RE.test(v) || QUARTER_RE.test(v),\n ).length;\n const dateRatio = dateCount / nonEmpty.length;\n\n // Header hint tiebreaker: if header matches date keywords...\n // (a) ...and at least some values look date-like, trust the header\n // (b) ...and values aren't overwhelmingly numeric (catches year-only values)\n if (DATE_HEADER_HINTS.test(header) && dateRatio > 0.3) return \"date\";\n if (DATE_HEADER_HINTS.test(header) && numericRatio < 0.9) return \"date\";\n\n if (dateRatio > 0.7) return \"date\";\n if (numericRatio > 0.8) return \"numeric\";\n\n // Categorical header hint\n if (CATEGORICAL_HEADER_HINTS.test(header)) return \"categorical\";\n\n // Categorical fallback: text values with <50 unique entries (higher cardinality suggests free-text or IDs)\n const unique = new Set(nonEmpty);\n if (unique.size < 50) return \"categorical\";\n\n return \"unknown\";\n}\n\n/* ------------------------------------------------------------------ */\n/* Chart recommendation engine */\n/* ------------------------------------------------------------------ */\n\nexport function detectCharts(headers: string[], rows: string[][]): ChartDetectionResult {\n if (headers.length === 0 || rows.length < 2) {\n return { chartable: false, columns: [] };\n }\n\n // Deduplicate headers so chart dataKey matches transformed data keys\n const seen = new Map<string, number>();\n const dedupedHeaders = headers.map((h) => {\n const count = seen.get(h) ?? 0;\n seen.set(h, count + 1);\n return count > 0 ? `${h}_${count + 1}` : h;\n });\n\n const columns: ClassifiedColumn[] = dedupedHeaders.map((header, index) => {\n const values = rows.map((r) => r[index] ?? \"\");\n const type = classifyColumn(header, values);\n const uniqueCount = new Set(values.filter((v) => v !== \"\")).size;\n return { index, header, type, uniqueCount };\n });\n\n const dateColumns = columns.filter((c) => c.type === \"date\");\n const numericColumns = columns.filter((c) => c.type === \"numeric\");\n const categoricalColumns = columns.filter((c) => c.type === \"categorical\");\n\n if (numericColumns.length === 0) {\n return { chartable: false, columns };\n }\n\n const recommendations: ChartRecommendation[] = [];\n\n // Line: date + numeric (time-series, highest priority)\n if (dateColumns.length >= 1 && numericColumns.length >= 1) {\n recommendations.push({\n type: \"line\",\n categoryColumn: dateColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Time-series: ${dateColumns[0].header} vs ${numericColumns.map((c) => c.header).join(\", \")}`,\n });\n }\n\n // Area: alternative to line for date + numeric (volume/magnitude over time)\n if (dateColumns.length >= 1 && numericColumns.length >= 1) {\n recommendations.push({\n type: \"area\",\n categoryColumn: dateColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Volume over time: ${numericColumns.map((c) => c.header).join(\", \")} by ${dateColumns[0].header}`,\n });\n }\n\n // Stacked bar: categorical + multiple numeric columns (part-to-whole comparison)\n if (categoricalColumns.length >= 1 && numericColumns.length >= 2) {\n recommendations.push({\n type: \"stacked-bar\",\n categoryColumn: categoricalColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Stacked: ${numericColumns.map((c) => c.header).join(\", \")} by ${categoricalColumns[0].header}`,\n });\n }\n\n // Bar: categorical + numeric\n if (categoricalColumns.length >= 1 && numericColumns.length >= 1) {\n recommendations.push({\n type: \"bar\",\n categoryColumn: categoricalColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Comparison: ${numericColumns.map((c) => c.header).join(\", \")} by ${categoricalColumns[0].header}`,\n });\n }\n\n // Pie: first categorical column (2-7 unique values) + first numeric column\n if (categoricalColumns.length >= 1 && numericColumns.length >= 1) {\n const cat = categoricalColumns[0];\n if (cat.uniqueCount >= 2 && cat.uniqueCount <= 7) {\n recommendations.push({\n type: \"pie\",\n categoryColumn: cat,\n valueColumns: [numericColumns[0]],\n reason: `Distribution: ${numericColumns[0].header} by ${cat.header}`,\n });\n }\n }\n\n // Scatter: 2+ numeric columns (correlation analysis)\n if (numericColumns.length >= 2) {\n const [xCol, yCol, ...rest] = numericColumns;\n const scatterValues = rest.length > 0\n ? [yCol, ...rest] as [ClassifiedColumn, ...ClassifiedColumn[]]\n : [yCol] as [ClassifiedColumn, ...ClassifiedColumn[]];\n recommendations.push({\n type: \"scatter\",\n categoryColumn: xCol,\n valueColumns: scatterValues,\n reason: `Correlation: ${xCol.header} vs ${yCol.header}${rest.length > 0 ? ` (size: ${rest[0].header})` : \"\"}`,\n });\n }\n\n // Fallback: when all columns are numeric, treat first as category axis (often an index or bucket label)\n if (!recommendations.some((r) => r.type === \"bar\") && numericColumns.length >= 2) {\n const first = columns[0];\n const rest = numericColumns.filter((c) => c.index !== first.index);\n if (rest.length >= 1) {\n recommendations.push({\n type: \"bar\",\n categoryColumn: first,\n valueColumns: rest as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Fallback: ${rest.map((c) => c.header).join(\", \")} by ${first.header}`,\n });\n }\n }\n\n // Also allow bar for date columns (as a secondary option after line)\n if (dateColumns.length >= 1 && numericColumns.length >= 1 && !recommendations.some((r) => r.type === \"bar\")) {\n recommendations.push({\n type: \"bar\",\n categoryColumn: dateColumns[0],\n valueColumns: numericColumns as [ClassifiedColumn, ...ClassifiedColumn[]],\n reason: `Comparison: ${numericColumns.map((c) => c.header).join(\", \")} by ${dateColumns[0].header}`,\n });\n }\n\n if (recommendations.length === 0) {\n return { chartable: false, columns };\n }\n\n const data = transformData(rows, recommendations[0]);\n\n return {\n chartable: true,\n columns,\n recommendations: recommendations as [ChartRecommendation, ...ChartRecommendation[]],\n data,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Data transform */\n/* ------------------------------------------------------------------ */\n\nfunction parseNumericValue(raw: string): number {\n const cleaned = raw.replace(/[$%,\\s]/g, \"\");\n if (cleaned === \"\" || cleaned === \"-\") return 0;\n const num = Number(cleaned);\n return isFinite(num) ? num : 0;\n}\n\nfunction isFiniteNumeric(raw: string): boolean {\n const cleaned = raw.replace(/[$%,\\s]/g, \"\");\n if (cleaned === \"\" || cleaned === \"-\") return false;\n return isFinite(Number(cleaned));\n}\n\nexport function transformData(\n rows: string[][],\n recommendation: ChartRecommendation,\n): RechartsRow[] {\n const catIdx = recommendation.categoryColumn.index;\n const catHeader = recommendation.categoryColumn.header;\n const valIdxs = recommendation.valueColumns.map((c) => c.index);\n\n // Scatter: both axes are numeric — categoryColumn is x, first valueColumn is y, optional z for size\n // Filter out rows where x or y are non-numeric to avoid misleading zero-origin clusters\n if (recommendation.type === \"scatter\") {\n const yIdx = recommendation.valueColumns[0].index;\n return rows.flatMap((row) => {\n const rawX = row[catIdx] ?? \"\";\n const rawY = row[yIdx] ?? \"\";\n if (!isFiniteNumeric(rawX) || !isFiniteNumeric(rawY)) return [];\n const record: RechartsRow = {};\n record[catHeader] = parseNumericValue(rawX);\n for (const vc of recommendation.valueColumns) {\n record[vc.header] = parseNumericValue(row[vc.index] ?? \"0\");\n }\n return [record];\n });\n }\n\n // Cap rows for bar/stacked-bar charts with many categories\n let effectiveRows = rows;\n if ((recommendation.type === \"bar\" || recommendation.type === \"stacked-bar\") && rows.length > 30) {\n // Sort by first value column descending, take top 20\n const valIdx = valIdxs[0];\n effectiveRows = [...rows]\n .sort((a, b) => {\n const av = parseNumericValue(a[valIdx] ?? \"0\");\n const bv = parseNumericValue(b[valIdx] ?? \"0\");\n return bv - av;\n })\n .slice(0, 20);\n }\n\n return effectiveRows.map((row) => {\n const record: RechartsRow = {};\n record[catHeader] = row[catIdx] ?? \"\";\n for (const vc of recommendation.valueColumns) {\n record[vc.header] = parseNumericValue(row[vc.index] ?? \"0\");\n }\n return record;\n });\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/theme-init-script.ts","../src/hooks/use-dark-mode.ts","../src/hooks/use-conversations.ts"],"names":["createContext","useSyncExternalStore","useState","useRef","useCallback"],"mappings":"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","file":"chunk-UIRB6L36.cjs","sourcesContent":["/**\n * Blocking inline script for layout.tsx — prevents dark-mode flash on load.\n *\n * This file intentionally has NO \"use client\" directive so it can be imported\n * by server components (layout.tsx). The storage key must stay in sync with\n * use-dark-mode.ts.\n */\n\nexport const THEME_STORAGE_KEY = \"atlas-theme\";\n\n/**\n * Returns the inline script string for the blocking `<script>` in layout.tsx.\n * Reads atlas-theme from localStorage and sets the `dark` class before first paint.\n */\nexport function buildThemeInitScript(): string {\n return `try{var t=localStorage.getItem(\"${THEME_STORAGE_KEY}\");var d=t===\"dark\"||(t!==\"light\"&&window.matchMedia(\"(prefers-color-scheme:dark)\").matches);if(d)document.documentElement.classList.add(\"dark\")}catch(e){}`;\n}\n","\"use client\";\n\nimport { createContext, useSyncExternalStore } from \"react\";\n\n// ---------------------------------------------------------------------------\n// Theme types & constants\n// ---------------------------------------------------------------------------\n\nimport { THEME_STORAGE_KEY } from \"./theme-init-script\";\n\nexport type ThemeMode = \"light\" | \"dark\" | \"system\";\n\nexport { THEME_STORAGE_KEY };\n\n/**\n * Default brand color — must match `brand.css` `:root { --atlas-brand }` and\n * the `ATLAS_BRAND_COLOR` default in `packages/api/src/lib/settings.ts`.\n */\nexport const DEFAULT_BRAND_COLOR = \"oklch(0.759 0.148 167.71)\";\n\n/** Basic oklch format check — prevents obviously invalid values from breaking the theme. */\nexport const OKLCH_RE = /^oklch\\(\\s*[\\d.]+\\s+[\\d.]+\\s+[\\d.]+\\s*(?:\\/\\s*[\\d.%]+\\s*)?\\)$/;\n\n// ---------------------------------------------------------------------------\n// Shared state — single source of truth for the chosen mode.\n// Listeners are notified on change so useSyncExternalStore re-renders.\n// ---------------------------------------------------------------------------\n\nlet _mode: ThemeMode = \"system\";\nconst _listeners = new Set<() => void>();\n\nfunction notify() {\n for (const fn of _listeners) fn();\n}\n\n/** Read stored preference (called once on module load in the browser). */\nfunction init() {\n try {\n const stored = localStorage.getItem(THEME_STORAGE_KEY);\n if (stored === \"light\" || stored === \"dark\" || stored === \"system\") {\n _mode = stored;\n }\n } catch (err) {\n console.warn(\"Could not read theme preference from localStorage:\", err);\n }\n}\n\nif (typeof window !== \"undefined\") init();\n\n// ---------------------------------------------------------------------------\n// Derived boolean: is the effective theme dark?\n// ---------------------------------------------------------------------------\n\nfunction systemPrefersDark(): boolean {\n return typeof window !== \"undefined\" && window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n}\n\nfunction resolveIsDark(mode: ThemeMode): boolean {\n if (mode === \"dark\") return true;\n if (mode === \"light\") return false;\n return systemPrefersDark();\n}\n\nfunction applyClass(isDark: boolean) {\n if (typeof document === \"undefined\") return;\n document.documentElement.classList.toggle(\"dark\", isDark);\n}\n\n// ---------------------------------------------------------------------------\n// External store for isDark (reacts to both mode changes AND system changes)\n// ---------------------------------------------------------------------------\n\nfunction subscribeIsDark(onChange: () => void) {\n _listeners.add(onChange);\n\n // Also listen for system preference changes (relevant when mode === \"system\").\n // Apply dark class immediately on OS change so the DOM stays in sync before React re-renders.\n const mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n const handler = () => {\n applyClass(resolveIsDark(_mode));\n onChange();\n };\n mq.addEventListener(\"change\", handler);\n\n return () => {\n _listeners.delete(onChange);\n mq.removeEventListener(\"change\", handler);\n };\n}\n\nfunction getSnapshotIsDark() {\n return resolveIsDark(_mode);\n}\n\nfunction getServerSnapshotIsDark() {\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// External store for mode\n// ---------------------------------------------------------------------------\n\nfunction subscribeMode(onChange: () => void) {\n _listeners.add(onChange);\n return () => {\n _listeners.delete(onChange);\n };\n}\n\nfunction getSnapshotMode() {\n return _mode;\n}\n\nfunction getServerSnapshotMode(): ThemeMode {\n return \"system\";\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function setTheme(mode: ThemeMode) {\n _mode = mode;\n const isDark = resolveIsDark(mode);\n applyClass(isDark);\n try {\n localStorage.setItem(THEME_STORAGE_KEY, mode);\n } catch (err) {\n console.warn(\"Could not persist theme preference to localStorage:\", err);\n }\n notify();\n}\n\n/** Apply --atlas-brand on :root so theme tokens update without reload. */\nexport function applyBrandColor(color: string) {\n if (typeof document === \"undefined\") return;\n document.documentElement.style.setProperty(\"--atlas-brand\", color);\n}\n\nexport const DarkModeContext = createContext(false);\n\n/** Returns whether the effective theme is dark. */\nexport function useDarkMode(): boolean {\n return useSyncExternalStore(subscribeIsDark, getSnapshotIsDark, getServerSnapshotIsDark);\n}\n\n/** Returns the current ThemeMode (\"light\" | \"dark\" | \"system\"). */\nexport function useThemeMode(): ThemeMode {\n return useSyncExternalStore(subscribeMode, getSnapshotMode, getServerSnapshotMode);\n}\n","\"use client\";\n\nimport { useState, useCallback, useRef } from \"react\";\nimport type { Conversation, ConversationWithMessages, Message } from \"../lib/types\";\nimport type { UIMessage } from \"@ai-sdk/react\";\n\nexport interface UseConversationsOptions {\n apiUrl: string;\n enabled: boolean;\n getHeaders: () => Record<string, string>;\n getCredentials: () => RequestCredentials;\n}\n\nexport interface UseConversationsReturn {\n conversations: Conversation[];\n total: number;\n loading: boolean;\n available: boolean;\n selectedId: string | null;\n setSelectedId: (id: string | null) => void;\n fetchList: () => Promise<void>;\n loadConversation: (id: string) => Promise<UIMessage[] | null>;\n deleteConversation: (id: string) => Promise<boolean>;\n starConversation: (id: string, starred: boolean) => Promise<boolean>;\n refresh: () => Promise<void>;\n}\n\nexport function transformMessages(messages: Message[]): UIMessage[] {\n return messages\n .filter((m) => m.role === \"user\" || m.role === \"assistant\")\n .map((m) => {\n const content = typeof m.content === \"string\"\n ? m.content\n : JSON.stringify(m.content);\n\n return {\n id: m.id,\n role: m.role as \"user\" | \"assistant\",\n parts: [{ type: \"text\" as const, text: content }],\n };\n });\n}\n\nexport function useConversations(opts: UseConversationsOptions): UseConversationsReturn {\n const [conversations, setConversations] = useState<Conversation[]>([]);\n const [total, setTotal] = useState(0);\n const [loading, setLoading] = useState(false);\n const [available, setAvailable] = useState(true);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const fetchedRef = useRef(false);\n const networkFailRef = useRef(0);\n\n const fetchList = useCallback(async () => {\n if (!opts.enabled || !available) return;\n setLoading(true);\n try {\n const res = await fetch(`${opts.apiUrl}/api/v1/conversations?limit=50`, {\n headers: opts.getHeaders(),\n credentials: opts.getCredentials(),\n });\n\n if (res.status === 404) {\n setAvailable(false);\n return;\n }\n\n if (!res.ok) {\n const errorBody = await res.json().catch(() => null);\n if (errorBody?.code === \"not_available\") {\n setAvailable(false);\n return;\n }\n console.warn(`fetchList: HTTP ${res.status}`, errorBody);\n return;\n }\n\n const data = await res.json();\n setConversations(data.conversations ?? []);\n setTotal(data.total ?? 0);\n fetchedRef.current = true;\n } catch (err) {\n console.warn(\"fetchList error:\", err);\n // Network error before any successful fetch — disable temporarily.\n // A subsequent explicit fetchList() call can retry.\n if (!fetchedRef.current) {\n networkFailRef.current += 1;\n if (networkFailRef.current >= 3) setAvailable(false);\n }\n } finally {\n setLoading(false);\n }\n }, [opts.apiUrl, opts.enabled, opts.getHeaders, opts.getCredentials, available]);\n\n const loadConversation = useCallback(async (id: string): Promise<UIMessage[] | null> => {\n try {\n const res = await fetch(`${opts.apiUrl}/api/v1/conversations/${id}`, {\n headers: opts.getHeaders(),\n credentials: opts.getCredentials(),\n });\n\n if (!res.ok) {\n console.warn(`loadConversation: HTTP ${res.status} for ${id}`);\n return null;\n }\n\n const data: ConversationWithMessages = await res.json();\n return transformMessages(data.messages);\n } catch (err) {\n console.warn(\"loadConversation error:\", err);\n return null;\n }\n }, [opts.apiUrl, opts.getHeaders, opts.getCredentials]);\n\n const deleteConversation = useCallback(async (id: string): Promise<boolean> => {\n try {\n const res = await fetch(`${opts.apiUrl}/api/v1/conversations/${id}`, {\n method: \"DELETE\",\n headers: opts.getHeaders(),\n credentials: opts.getCredentials(),\n });\n\n if (!res.ok) {\n console.warn(`deleteConversation: HTTP ${res.status} for ${id}`);\n return false;\n }\n\n setConversations((prev) => prev.filter((c) => c.id !== id));\n setTotal((prev) => Math.max(0, prev - 1));\n\n if (selectedId === id) setSelectedId(null);\n\n return true;\n } catch (err) {\n console.warn(\"deleteConversation error:\", err);\n return false;\n }\n }, [opts.apiUrl, opts.getHeaders, opts.getCredentials, selectedId]);\n\n const starConversation = useCallback(async (id: string, starred: boolean): Promise<boolean> => {\n // Optimistic update\n setConversations((prev) =>\n prev.map((c) => (c.id === id ? { ...c, starred } : c)),\n );\n try {\n const res = await fetch(`${opts.apiUrl}/api/v1/conversations/${id}/star`, {\n method: \"PATCH\",\n headers: { ...opts.getHeaders(), \"Content-Type\": \"application/json\" },\n credentials: opts.getCredentials(),\n body: JSON.stringify({ starred }),\n });\n\n if (!res.ok) {\n console.warn(`starConversation: HTTP ${res.status} for ${id}`);\n // Rollback\n setConversations((prev) =>\n prev.map((c) => (c.id === id ? { ...c, starred: !starred } : c)),\n );\n return false;\n }\n\n return true;\n } catch (err) {\n console.warn(\"starConversation error:\", err);\n // Rollback\n setConversations((prev) =>\n prev.map((c) => (c.id === id ? { ...c, starred: !starred } : c)),\n );\n return false;\n }\n }, [opts.apiUrl, opts.getHeaders, opts.getCredentials]);\n\n const refresh = useCallback(async () => {\n await fetchList();\n }, [fetchList]);\n\n return {\n conversations,\n total,\n loading,\n available,\n selectedId,\n setSelectedId,\n fetchList,\n loadConversation,\n deleteConversation,\n starConversation,\n refresh,\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/chart/result-chart.tsx"],"names":[],"mappings":"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","file":"result-chart-NFAJ4IQ5.js","sourcesContent":["\"use client\";\n\nimport { Component, type ReactNode, type ErrorInfo, useMemo, useId, useState } from \"react\";\nimport {\n ResponsiveContainer,\n BarChart,\n Bar,\n LineChart,\n Line,\n AreaChart,\n Area,\n ScatterChart,\n Scatter,\n ZAxis,\n PieChart,\n Pie,\n Cell,\n CartesianGrid,\n XAxis,\n YAxis,\n Tooltip,\n Legend,\n} from \"recharts\";\nimport {\n detectCharts,\n transformData,\n CHART_COLORS_LIGHT,\n CHART_COLORS_DARK,\n type ChartRecommendation,\n type ChartType,\n type RechartsRow,\n type ChartDetectionResult,\n} from \"./chart-detection\";\n\n/* ------------------------------------------------------------------ */\n/* Error boundary */\n/* ------------------------------------------------------------------ */\n\nclass ChartErrorBoundary extends Component<\n { children: ReactNode; fallback?: ReactNode },\n { hasError: boolean }\n> {\n constructor(props: { children: ReactNode; fallback?: ReactNode }) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): { hasError: boolean } {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n console.error(\"Chart rendering failed:\", error, info.componentStack);\n }\n\n render() {\n if (this.state.hasError) {\n return this.props.fallback ?? (\n <div className=\"rounded-lg border border-yellow-300 bg-yellow-50 px-3 py-2 text-xs text-yellow-700 dark:border-yellow-900/50 dark:bg-yellow-950/20 dark:text-yellow-400\">\n Chart could not be rendered. Switch to Table view to see your data.\n </div>\n );\n }\n return this.props.children;\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Theme helpers */\n/* ------------------------------------------------------------------ */\n\nfunction getColors(dark: boolean) {\n return dark ? CHART_COLORS_DARK : CHART_COLORS_LIGHT;\n}\n\nfunction themeTokens(dark: boolean) {\n return {\n grid: dark ? \"#3f3f46\" : \"#e4e4e7\",\n axis: dark ? \"#a1a1aa\" : \"#71717a\",\n tooltipBg: dark ? \"#18181b\" : \"#ffffff\",\n tooltipBorder: dark ? \"#3f3f46\" : \"#e4e4e7\",\n tooltipText: dark ? \"#e4e4e7\" : \"#27272a\",\n legendText: dark ? \"#a1a1aa\" : \"#71717a\",\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Number formatter for axis / tooltip */\n/* ------------------------------------------------------------------ */\n\nfunction formatNumber(value: unknown): string {\n const num = Number(value);\n if (!isFinite(num)) return String(value ?? \"\");\n if (Math.abs(num) >= 1_000_000) return `${(num / 1_000_000).toFixed(1)}M`;\n if (Math.abs(num) >= 1_000) return `${(num / 1_000).toFixed(1)}K`;\n return Number.isInteger(num) ? num.toLocaleString() : num.toFixed(2);\n}\n\nfunction truncateLabel(label: unknown, maxLen = 12): string {\n const str = String(label ?? \"\");\n return str.length > maxLen ? str.slice(0, maxLen) + \"\\u2026\" : str;\n}\n\n/* ------------------------------------------------------------------ */\n/* Tooltip */\n/* ------------------------------------------------------------------ */\n\nconst TOOLTIP_LABEL_STYLE = { fontWeight: 600, marginBottom: 4 } as const;\n\nconst tooltipStyleCache = new Map<boolean, React.CSSProperties>();\nfunction getTooltipStyle(dark: boolean): React.CSSProperties {\n let style = tooltipStyleCache.get(dark);\n if (!style) {\n const t = themeTokens(dark);\n style = {\n background: t.tooltipBg,\n border: `1px solid ${t.tooltipBorder}`,\n borderRadius: 6,\n padding: \"8px 12px\",\n fontSize: 12,\n color: t.tooltipText,\n };\n tooltipStyleCache.set(dark, style);\n }\n return style;\n}\n\nfunction ChartTooltip({ active, payload, label, dark }: {\n active?: boolean;\n payload?: Array<{ name: string; value: number; color: string }>;\n label?: string;\n dark: boolean;\n}) {\n if (!active || !payload?.length) return null;\n return (\n <div style={getTooltipStyle(dark)}>\n {label && <p style={TOOLTIP_LABEL_STYLE}>{label}</p>}\n {payload.map((entry, i) => (\n <p key={i} style={{ color: entry.color }}>\n {entry.name}: {typeof entry.value === \"number\" ? formatNumber(entry.value) : entry.value}\n </p>\n ))}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Sub-chart components */\n/* ------------------------------------------------------------------ */\n\nfunction BarChartView({\n data,\n rec,\n dark,\n}: {\n data: RechartsRow[];\n rec: ChartRecommendation;\n dark: boolean;\n}) {\n const colors = getColors(dark);\n const t = themeTokens(dark);\n const catKey = rec.categoryColumn.header;\n const valKeys = rec.valueColumns.map((c) => c.header);\n\n return (\n <div className=\"aspect-[4/3] sm:aspect-[16/9]\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={data} margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={t.grid} />\n <XAxis\n dataKey={catKey}\n tick={{ fill: t.axis, fontSize: 11 }}\n tickFormatter={(v: string) => truncateLabel(v)}\n angle={-45}\n textAnchor=\"end\"\n height={60}\n />\n <YAxis tick={{ fill: t.axis, fontSize: 11 }} tickFormatter={formatNumber} />\n <Tooltip content={<ChartTooltip dark={dark} />} />\n {valKeys.length > 1 && (\n <Legend wrapperStyle={{ fontSize: 12, color: t.legendText }} />\n )}\n {valKeys.map((key, i) => (\n <Bar\n key={key}\n dataKey={key}\n fill={colors[i % colors.length]}\n radius={[4, 4, 0, 0]}\n />\n ))}\n </BarChart>\n </ResponsiveContainer>\n </div>\n );\n}\n\nfunction LineChartView({\n data,\n rec,\n dark,\n}: {\n data: RechartsRow[];\n rec: ChartRecommendation;\n dark: boolean;\n}) {\n const colors = getColors(dark);\n const t = themeTokens(dark);\n const catKey = rec.categoryColumn.header;\n const valKeys = rec.valueColumns.map((c) => c.header);\n\n return (\n <div className=\"aspect-[4/3] sm:aspect-[16/9]\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <LineChart data={data} margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={t.grid} />\n <XAxis\n dataKey={catKey}\n tick={{ fill: t.axis, fontSize: 11 }}\n tickFormatter={(v: string) => truncateLabel(v)}\n angle={-45}\n textAnchor=\"end\"\n height={60}\n />\n <YAxis tick={{ fill: t.axis, fontSize: 11 }} tickFormatter={formatNumber} />\n <Tooltip content={<ChartTooltip dark={dark} />} />\n {valKeys.length > 1 && (\n <Legend wrapperStyle={{ fontSize: 12, color: t.legendText }} />\n )}\n {valKeys.map((key, i) => (\n <Line\n key={key}\n type=\"monotone\"\n dataKey={key}\n stroke={colors[i % colors.length]}\n strokeWidth={2}\n dot={{ r: 3, fill: colors[i % colors.length] }}\n activeDot={{ r: 5 }}\n />\n ))}\n </LineChart>\n </ResponsiveContainer>\n </div>\n );\n}\n\nfunction PieChartView({\n data,\n rec,\n dark,\n}: {\n data: RechartsRow[];\n rec: ChartRecommendation;\n dark: boolean;\n}) {\n const colors = getColors(dark);\n const t = themeTokens(dark);\n const catKey = rec.categoryColumn.header;\n const valKey = rec.valueColumns[0].header;\n\n const total = data.reduce((sum, d) => sum + (typeof d[valKey] === \"number\" ? (d[valKey] as number) : 0), 0);\n\n const hasNegative = data.some(d => typeof d[valKey] === \"number\" && (d[valKey] as number) < 0);\n if (total <= 0 || hasNegative) {\n return (\n <div className=\"flex aspect-[4/3] items-center justify-center text-xs text-zinc-400 sm:aspect-[16/9]\">\n Pie chart is not suitable for this data.\n </div>\n );\n }\n\n return (\n <div className=\"aspect-[4/3] sm:aspect-[16/9]\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <PieChart>\n <Pie\n data={data}\n dataKey={valKey}\n nameKey={catKey}\n cx=\"50%\"\n cy=\"50%\"\n innerRadius={40}\n outerRadius={100}\n label={({ name, value }: { name?: string; value?: number }) =>\n `${truncateLabel(String(name ?? \"\"), 10)} ${total > 0 && value != null ? ((value / total) * 100).toFixed(0) : 0}%`\n }\n labelLine={{ stroke: t.axis }}\n fontSize={11}\n >\n {data.map((_, i) => (\n <Cell key={i} fill={colors[i % colors.length]} />\n ))}\n </Pie>\n <Tooltip content={<ChartTooltip dark={dark} />} />\n </PieChart>\n </ResponsiveContainer>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Area chart */\n/* ------------------------------------------------------------------ */\n\nfunction AreaChartView({\n data,\n rec,\n dark,\n}: {\n data: RechartsRow[];\n rec: ChartRecommendation;\n dark: boolean;\n}) {\n const chartId = useId();\n const colors = getColors(dark);\n const t = themeTokens(dark);\n const catKey = rec.categoryColumn.header;\n const valKeys = rec.valueColumns.map((c) => c.header);\n\n return (\n <ResponsiveContainer width=\"100%\" height={300}>\n <AreaChart data={data} margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>\n <defs>\n {valKeys.map((key, i) => (\n <linearGradient key={key} id={`area-grad-${chartId}-${i}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"5%\" stopColor={colors[i % colors.length]} stopOpacity={0.3} />\n <stop offset=\"95%\" stopColor={colors[i % colors.length]} stopOpacity={0.05} />\n </linearGradient>\n ))}\n </defs>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={t.grid} />\n <XAxis\n dataKey={catKey}\n tick={{ fill: t.axis, fontSize: 11 }}\n tickFormatter={(v: string) => truncateLabel(v)}\n angle={-45}\n textAnchor=\"end\"\n height={60}\n />\n <YAxis tick={{ fill: t.axis, fontSize: 11 }} tickFormatter={formatNumber} />\n <Tooltip content={<ChartTooltip dark={dark} />} />\n {valKeys.length > 1 && (\n <Legend wrapperStyle={{ fontSize: 12, color: t.legendText }} />\n )}\n {valKeys.map((key, i) => (\n <Area\n key={key}\n type=\"monotone\"\n dataKey={key}\n stroke={colors[i % colors.length]}\n strokeWidth={2}\n fill={`url(#area-grad-${chartId}-${i})`}\n />\n ))}\n </AreaChart>\n </ResponsiveContainer>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Stacked bar chart */\n/* ------------------------------------------------------------------ */\n\nfunction StackedBarChartView({\n data,\n rec,\n dark,\n}: {\n data: RechartsRow[];\n rec: ChartRecommendation;\n dark: boolean;\n}) {\n const colors = getColors(dark);\n const t = themeTokens(dark);\n const catKey = rec.categoryColumn.header;\n const valKeys = rec.valueColumns.map((c) => c.header);\n\n return (\n <ResponsiveContainer width=\"100%\" height={300}>\n <BarChart data={data} margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={t.grid} />\n <XAxis\n dataKey={catKey}\n tick={{ fill: t.axis, fontSize: 11 }}\n tickFormatter={(v: string) => truncateLabel(v)}\n angle={-45}\n textAnchor=\"end\"\n height={60}\n />\n <YAxis tick={{ fill: t.axis, fontSize: 11 }} tickFormatter={formatNumber} />\n <Tooltip content={<ChartTooltip dark={dark} />} />\n <Legend wrapperStyle={{ fontSize: 12, color: t.legendText }} />\n {valKeys.map((key, i) => (\n <Bar\n key={key}\n dataKey={key}\n stackId=\"a\"\n fill={colors[i % colors.length]}\n radius={i === valKeys.length - 1 ? [4, 4, 0, 0] : undefined}\n />\n ))}\n </BarChart>\n </ResponsiveContainer>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Scatter chart */\n/* ------------------------------------------------------------------ */\n\nfunction ScatterChartView({\n data,\n rec,\n dark,\n}: {\n data: RechartsRow[];\n rec: ChartRecommendation;\n dark: boolean;\n}) {\n const colors = getColors(dark);\n const t = themeTokens(dark);\n const xKey = rec.categoryColumn.header;\n const yKey = rec.valueColumns[0].header;\n const zKey = rec.valueColumns.length > 1 ? rec.valueColumns[1].header : undefined;\n\n return (\n <ResponsiveContainer width=\"100%\" height={300}>\n <ScatterChart margin={{ top: 8, right: 8, bottom: 40, left: 8 }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={t.grid} />\n <XAxis\n dataKey={xKey}\n type=\"number\"\n name={xKey}\n tick={{ fill: t.axis, fontSize: 11 }}\n tickFormatter={formatNumber}\n />\n <YAxis\n dataKey={yKey}\n type=\"number\"\n name={yKey}\n tick={{ fill: t.axis, fontSize: 11 }}\n tickFormatter={formatNumber}\n />\n {zKey && <ZAxis dataKey={zKey} type=\"number\" name={zKey} range={[40, 400]} />}\n <Tooltip\n content={<ChartTooltip dark={dark} />}\n cursor={{ strokeDasharray: \"3 3\" }}\n />\n <Scatter\n data={data}\n fill={colors[0]}\n />\n </ScatterChart>\n </ResponsiveContainer>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Chart type selector */\n/* ------------------------------------------------------------------ */\n\nconst CHART_LABELS: Record<ChartType, string> = {\n bar: \"Bar\",\n line: \"Line\",\n pie: \"Pie\",\n area: \"Area\",\n \"stacked-bar\": \"Stacked\",\n scatter: \"Scatter\",\n};\n\nfunction ChartTypeSelector({\n recommendations,\n active,\n onChange,\n}: {\n recommendations: ChartRecommendation[];\n active: ChartType;\n onChange: (t: ChartType) => void;\n}) {\n if (recommendations.length <= 1) return null;\n\n const seen = new Set<ChartType>();\n const unique = recommendations.filter((r) => {\n if (seen.has(r.type)) return false;\n seen.add(r.type);\n return true;\n });\n\n if (unique.length <= 1) return null;\n\n return (\n <div className=\"flex gap-1\">\n {unique.map((rec) => (\n <button\n key={rec.type}\n onClick={() => onChange(rec.type)}\n className={`rounded px-2 py-0.5 text-xs font-medium transition-colors ${\n active === rec.type\n ? \"bg-blue-100 text-blue-700 dark:bg-blue-600/20 dark:text-blue-400\"\n : \"text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200\"\n }`}\n >\n {CHART_LABELS[rec.type]}\n </button>\n ))}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Chart renderer (inside error boundary) */\n/* ------------------------------------------------------------------ */\n\nfunction ChartRenderer({\n rows,\n rec,\n defaultData,\n defaultRec,\n dark,\n}: {\n rows: string[][];\n rec: ChartRecommendation;\n defaultData: RechartsRow[];\n defaultRec: ChartRecommendation;\n dark: boolean;\n}) {\n // Re-transform data when switching chart type (category axis may differ)\n const chartData = rec === defaultRec ? defaultData : transformData(rows, rec);\n const type = rec.type;\n\n return (\n <div className=\"p-2\">\n {type === \"bar\" ? <BarChartView data={chartData} rec={rec} dark={dark} />\n : type === \"line\" ? <LineChartView data={chartData} rec={rec} dark={dark} />\n : type === \"area\" ? <AreaChartView data={chartData} rec={rec} dark={dark} />\n : type === \"stacked-bar\" ? <StackedBarChartView data={chartData} rec={rec} dark={dark} />\n : type === \"scatter\" ? <ScatterChartView data={chartData} rec={rec} dark={dark} />\n : <PieChartView data={chartData} rec={rec} dark={dark} />}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Main ResultChart component */\n/* ------------------------------------------------------------------ */\n\nexport function ResultChart({\n headers,\n rows,\n dark,\n detectionResult,\n}: {\n headers: string[];\n rows: string[][];\n dark: boolean;\n detectionResult?: ChartDetectionResult;\n}) {\n const result = useMemo(\n () => detectionResult ?? detectCharts(headers, rows),\n [headers, rows, detectionResult],\n );\n\n const [activeType, setActiveType] = useState<ChartType | null>(null);\n\n if (!result.chartable) return null;\n\n const currentType = activeType ?? result.recommendations[0].type;\n const currentRec = result.recommendations.find((r) => r.type === currentType) ?? result.recommendations[0];\n\n return (\n <div className=\"overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-700\">\n <div className=\"flex items-center justify-between border-b border-zinc-100 bg-zinc-50/50 px-3 py-2 dark:border-zinc-800 dark:bg-zinc-900/50\">\n <span className=\"text-xs text-zinc-500 dark:text-zinc-400\">{currentRec.reason}</span>\n <ChartTypeSelector\n recommendations={result.recommendations}\n active={currentType}\n onChange={setActiveType}\n />\n </div>\n <ChartErrorBoundary key={currentType}>\n <ChartRenderer\n rows={rows}\n rec={currentRec}\n defaultData={result.data}\n defaultRec={result.recommendations[0]}\n dark={dark}\n />\n </ChartErrorBoundary>\n </div>\n );\n}\n"]}