@informedai/react 0.4.26 → 0.4.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -26,6 +26,14 @@ interface WidgetMessage {
26
26
  timestamp: string;
27
27
  taskContext?: string;
28
28
  kbSearch?: KbSearchInfo;
29
+ agentContext?: {
30
+ analyticsRun?: {
31
+ runId: string;
32
+ query: string;
33
+ status: string;
34
+ };
35
+ triages?: string[];
36
+ };
29
37
  }
30
38
  interface QuickAction {
31
39
  id: string;
@@ -128,6 +136,8 @@ interface InformedAssistantConfig {
128
136
  * Return the current values of all fields as they appear in your UI.
129
137
  */
130
138
  getCurrentFieldValues?: () => Record<string, unknown>;
139
+ /** Callback when an analytics run badge is clicked. If not provided, an inline panel is shown. */
140
+ onAnalyticsRunClick?: (runId: string, query: string, sessionId: string) => void;
131
141
  /** Custom theme overrides */
132
142
  theme?: Partial<WidgetTheme>;
133
143
  /** Position of the widget (for floating mode) */
@@ -152,6 +162,24 @@ interface WidgetTheme {
152
162
  /** Font family */
153
163
  fontFamily: string;
154
164
  }
165
+ interface SqlBreakdown {
166
+ baseDataset: string;
167
+ metrics: string[];
168
+ filters: string[];
169
+ grouping: string[];
170
+ sorting: string | null;
171
+ timeRange: string | null;
172
+ }
173
+ interface AnalyticsRunDetail {
174
+ id: string;
175
+ query: string;
176
+ status: string;
177
+ generatedSql: string | null;
178
+ structuredBreakdown: SqlBreakdown | null;
179
+ result: unknown[] | null;
180
+ createdAt: string;
181
+ parentRunId: string | null;
182
+ }
155
183
  interface SSEEvent {
156
184
  type: 'content' | 'done' | 'error' | 'session_update';
157
185
  content?: string;
@@ -345,6 +373,8 @@ interface InformedAIContextValue {
345
373
  startNewSession: () => Promise<void>;
346
374
  endSession: () => Promise<void>;
347
375
  clearError: () => void;
376
+ onAnalyticsRunClick?: (runId: string, query: string, sessionId: string) => void;
377
+ getAnalyticsRun: (sessionId: string, runId: string) => Promise<AnalyticsRunDetail>;
348
378
  }
349
379
  declare function useInformedAI(): InformedAIContextValue;
350
380
  interface InformedAIProviderProps {
@@ -463,7 +493,11 @@ declare class InformedAIClient {
463
493
  * Returns true if sendBeacon was used, false if fetch fallback was attempted.
464
494
  */
465
495
  endSessionBeacon(sessionId: string): boolean;
496
+ /**
497
+ * Get details of a specific analytics run.
498
+ */
499
+ getAnalyticsRun(sessionId: string, runId: string): Promise<AnalyticsRunDetail>;
466
500
  private processSSEStream;
467
501
  }
468
502
 
469
- export { AdminChatbot, type AdminChatbotConfig, type AdminChatbotTheme, type ChatMessage, type Document, type DocumentType, type DocumentTypeSchema, type FieldDefinition, InformedAIClient, InformedAIProvider, InformedAssistant, type InformedAssistantConfig, type QuickAction, type QuickActionGroup, type SSEEvent, type Session, SmartQuestionnaire, type SmartQuestionnaireConfig, type SmartQuestionnaireTheme, type TaskConfig, type TaskState, type UseSessionReturn, WebsiteChatbot, type WebsiteChatbotConfig, type WebsiteChatbotTheme, type WidgetMessage, type WidgetReadyContext, type WidgetTheme, useInformedAI, useSession };
503
+ export { AdminChatbot, type AdminChatbotConfig, type AdminChatbotTheme, type AnalyticsRunDetail, type ChatMessage, type Document, type DocumentType, type DocumentTypeSchema, type FieldDefinition, InformedAIClient, InformedAIProvider, InformedAssistant, type InformedAssistantConfig, type QuickAction, type QuickActionGroup, type SSEEvent, type Session, SmartQuestionnaire, type SmartQuestionnaireConfig, type SmartQuestionnaireTheme, type SqlBreakdown, type TaskConfig, type TaskState, type UseSessionReturn, WebsiteChatbot, type WebsiteChatbotConfig, type WebsiteChatbotTheme, type WidgetMessage, type WidgetReadyContext, type WidgetTheme, useInformedAI, useSession };
package/dist/index.d.ts CHANGED
@@ -26,6 +26,14 @@ interface WidgetMessage {
26
26
  timestamp: string;
27
27
  taskContext?: string;
28
28
  kbSearch?: KbSearchInfo;
29
+ agentContext?: {
30
+ analyticsRun?: {
31
+ runId: string;
32
+ query: string;
33
+ status: string;
34
+ };
35
+ triages?: string[];
36
+ };
29
37
  }
30
38
  interface QuickAction {
31
39
  id: string;
@@ -128,6 +136,8 @@ interface InformedAssistantConfig {
128
136
  * Return the current values of all fields as they appear in your UI.
129
137
  */
130
138
  getCurrentFieldValues?: () => Record<string, unknown>;
139
+ /** Callback when an analytics run badge is clicked. If not provided, an inline panel is shown. */
140
+ onAnalyticsRunClick?: (runId: string, query: string, sessionId: string) => void;
131
141
  /** Custom theme overrides */
132
142
  theme?: Partial<WidgetTheme>;
133
143
  /** Position of the widget (for floating mode) */
@@ -152,6 +162,24 @@ interface WidgetTheme {
152
162
  /** Font family */
153
163
  fontFamily: string;
154
164
  }
165
+ interface SqlBreakdown {
166
+ baseDataset: string;
167
+ metrics: string[];
168
+ filters: string[];
169
+ grouping: string[];
170
+ sorting: string | null;
171
+ timeRange: string | null;
172
+ }
173
+ interface AnalyticsRunDetail {
174
+ id: string;
175
+ query: string;
176
+ status: string;
177
+ generatedSql: string | null;
178
+ structuredBreakdown: SqlBreakdown | null;
179
+ result: unknown[] | null;
180
+ createdAt: string;
181
+ parentRunId: string | null;
182
+ }
155
183
  interface SSEEvent {
156
184
  type: 'content' | 'done' | 'error' | 'session_update';
157
185
  content?: string;
@@ -345,6 +373,8 @@ interface InformedAIContextValue {
345
373
  startNewSession: () => Promise<void>;
346
374
  endSession: () => Promise<void>;
347
375
  clearError: () => void;
376
+ onAnalyticsRunClick?: (runId: string, query: string, sessionId: string) => void;
377
+ getAnalyticsRun: (sessionId: string, runId: string) => Promise<AnalyticsRunDetail>;
348
378
  }
349
379
  declare function useInformedAI(): InformedAIContextValue;
350
380
  interface InformedAIProviderProps {
@@ -463,7 +493,11 @@ declare class InformedAIClient {
463
493
  * Returns true if sendBeacon was used, false if fetch fallback was attempted.
464
494
  */
465
495
  endSessionBeacon(sessionId: string): boolean;
496
+ /**
497
+ * Get details of a specific analytics run.
498
+ */
499
+ getAnalyticsRun(sessionId: string, runId: string): Promise<AnalyticsRunDetail>;
466
500
  private processSSEStream;
467
501
  }
468
502
 
469
- export { AdminChatbot, type AdminChatbotConfig, type AdminChatbotTheme, type ChatMessage, type Document, type DocumentType, type DocumentTypeSchema, type FieldDefinition, InformedAIClient, InformedAIProvider, InformedAssistant, type InformedAssistantConfig, type QuickAction, type QuickActionGroup, type SSEEvent, type Session, SmartQuestionnaire, type SmartQuestionnaireConfig, type SmartQuestionnaireTheme, type TaskConfig, type TaskState, type UseSessionReturn, WebsiteChatbot, type WebsiteChatbotConfig, type WebsiteChatbotTheme, type WidgetMessage, type WidgetReadyContext, type WidgetTheme, useInformedAI, useSession };
503
+ export { AdminChatbot, type AdminChatbotConfig, type AdminChatbotTheme, type AnalyticsRunDetail, type ChatMessage, type Document, type DocumentType, type DocumentTypeSchema, type FieldDefinition, InformedAIClient, InformedAIProvider, InformedAssistant, type InformedAssistantConfig, type QuickAction, type QuickActionGroup, type SSEEvent, type Session, SmartQuestionnaire, type SmartQuestionnaireConfig, type SmartQuestionnaireTheme, type SqlBreakdown, type TaskConfig, type TaskState, type UseSessionReturn, WebsiteChatbot, type WebsiteChatbotConfig, type WebsiteChatbotTheme, type WidgetMessage, type WidgetReadyContext, type WidgetTheme, useInformedAI, useSession };
package/dist/index.js CHANGED
@@ -216,6 +216,15 @@ var InformedAIClient = class {
216
216
  return false;
217
217
  }
218
218
  // ========================================================================
219
+ // Analytics
220
+ // ========================================================================
221
+ /**
222
+ * Get details of a specific analytics run.
223
+ */
224
+ async getAnalyticsRun(sessionId, runId) {
225
+ return this.request(`/widget/sessions/${sessionId}/analytics-runs/${runId}`);
226
+ }
227
+ // ========================================================================
219
228
  // SSE Stream Processing
220
229
  // ========================================================================
221
230
  async processSSEStream(response, onEvent) {
@@ -713,6 +722,10 @@ function InformedAIProvider({ config, children }) {
713
722
  const clearError = (0, import_react.useCallback)(() => {
714
723
  setError(null);
715
724
  }, []);
725
+ const getAnalyticsRun = (0, import_react.useCallback)(async (sessionId, runId) => {
726
+ if (!clientRef.current) throw new Error("Client not initialized");
727
+ return clientRef.current.getAnalyticsRun(sessionId, runId);
728
+ }, []);
716
729
  const value = {
717
730
  session,
718
731
  document,
@@ -727,7 +740,9 @@ function InformedAIProvider({ config, children }) {
727
740
  skipTask,
728
741
  startNewSession,
729
742
  endSession,
730
- clearError
743
+ clearError,
744
+ onAnalyticsRunClick: config.onAnalyticsRunClick,
745
+ getAnalyticsRun
731
746
  };
732
747
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InformedAIContext.Provider, { value, children });
733
748
  }
@@ -1150,6 +1165,7 @@ function MessageBubble({ message, theme, onQuickAction, isLatest = false, quickA
1150
1165
  const isUser = message.role === "user";
1151
1166
  const hasQuickActions = isLatest && message.quickActions && message.quickActions.length > 0;
1152
1167
  const hasKbSearch = message.kbSearch != null;
1168
+ const hasAnalyticsRun = message.agentContext?.analyticsRun != null;
1153
1169
  if ((message.type === "quick_actions" || !message.content) && hasQuickActions) {
1154
1170
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1155
1171
  GroupedQuickActions,
@@ -1188,6 +1204,14 @@ function MessageBubble({ message, theme, onQuickAction, isLatest = false, quickA
1188
1204
  ]
1189
1205
  }
1190
1206
  ),
1207
+ hasAnalyticsRun && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1208
+ AnalyticsBadge,
1209
+ {
1210
+ runId: message.agentContext.analyticsRun.runId,
1211
+ query: message.agentContext.analyticsRun.query,
1212
+ status: message.agentContext.analyticsRun.status
1213
+ }
1214
+ ),
1191
1215
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1192
1216
  "div",
1193
1217
  {
@@ -1323,6 +1347,182 @@ function GroupedQuickActions({ actions, groups, theme, onQuickAction }) {
1323
1347
  ] }, groupKey);
1324
1348
  }) });
1325
1349
  }
1350
+ function AnalyticsBadge({ runId, query, status }) {
1351
+ const { session, onAnalyticsRunClick, getAnalyticsRun } = useInformedAI();
1352
+ const [expanded, setExpanded] = (0, import_react2.useState)(false);
1353
+ const [runDetail, setRunDetail] = (0, import_react2.useState)(null);
1354
+ const [loading, setLoading] = (0, import_react2.useState)(false);
1355
+ const handleClick = () => {
1356
+ if (onAnalyticsRunClick && session) {
1357
+ onAnalyticsRunClick(runId, query, session.id);
1358
+ return;
1359
+ }
1360
+ setExpanded((prev) => !prev);
1361
+ };
1362
+ (0, import_react2.useEffect)(() => {
1363
+ if (expanded && !runDetail && !loading && session) {
1364
+ setLoading(true);
1365
+ getAnalyticsRun(session.id, runId).then(setRunDetail).catch((err) => console.warn("Failed to load analytics run:", err)).finally(() => setLoading(false));
1366
+ }
1367
+ }, [expanded, runDetail, loading, session, runId, getAnalyticsRun]);
1368
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "4px" }, children: [
1369
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1370
+ "button",
1371
+ {
1372
+ onClick: handleClick,
1373
+ style: {
1374
+ display: "inline-flex",
1375
+ alignItems: "center",
1376
+ gap: "6px",
1377
+ padding: "4px 10px",
1378
+ backgroundColor: status === "completed" ? "#ede9fe" : "#fef3c7",
1379
+ border: "none",
1380
+ borderRadius: "12px",
1381
+ fontSize: "11px",
1382
+ color: status === "completed" ? "#6d28d9" : "#92400e",
1383
+ cursor: "pointer",
1384
+ transition: "opacity 0.15s"
1385
+ },
1386
+ onMouseOver: (e) => {
1387
+ e.currentTarget.style.opacity = "0.8";
1388
+ },
1389
+ onMouseOut: (e) => {
1390
+ e.currentTarget.style.opacity = "1";
1391
+ },
1392
+ title: `Analytics query: ${query}`,
1393
+ children: [
1394
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChartIcon, { size: 12 }),
1395
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Analytics query" }),
1396
+ !onAnalyticsRunClick && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "9px", marginLeft: "2px" }, children: expanded ? "\u25B2" : "\u25BC" })
1397
+ ]
1398
+ }
1399
+ ),
1400
+ expanded && !onAnalyticsRunClick && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AnalyticsRunPanel, { detail: runDetail, loading })
1401
+ ] });
1402
+ }
1403
+ function AnalyticsRunPanel({ detail, loading }) {
1404
+ const [sqlExpanded, setSqlExpanded] = (0, import_react2.useState)(false);
1405
+ if (loading) {
1406
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "12px", fontSize: "12px", color: "#737373" }, children: "Loading analytics details..." });
1407
+ }
1408
+ if (!detail) return null;
1409
+ const breakdown = detail.structuredBreakdown;
1410
+ const rows = detail.result;
1411
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1412
+ "div",
1413
+ {
1414
+ style: {
1415
+ marginTop: "6px",
1416
+ padding: "12px",
1417
+ backgroundColor: "#faf5ff",
1418
+ borderRadius: "8px",
1419
+ fontSize: "12px",
1420
+ lineHeight: 1.5,
1421
+ border: "1px solid #e9d5ff"
1422
+ },
1423
+ children: [
1424
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontWeight: 600, color: "#6d28d9", marginBottom: "8px" }, children: detail.query }),
1425
+ breakdown && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "4px", marginBottom: "8px" }, children: [
1426
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BreakdownItem, { label: "Dataset", value: breakdown.baseDataset }),
1427
+ breakdown.metrics.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BreakdownItem, { label: "Metrics", value: breakdown.metrics.join(", ") }),
1428
+ breakdown.filters.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BreakdownItem, { label: "Filters", value: breakdown.filters.join(", ") }),
1429
+ breakdown.grouping.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BreakdownItem, { label: "Grouped by", value: breakdown.grouping.join(", ") }),
1430
+ breakdown.sorting && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BreakdownItem, { label: "Sorted", value: breakdown.sorting }),
1431
+ breakdown.timeRange && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BreakdownItem, { label: "Time range", value: breakdown.timeRange })
1432
+ ] }),
1433
+ detail.generatedSql && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1434
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1435
+ "button",
1436
+ {
1437
+ onClick: () => setSqlExpanded((prev) => !prev),
1438
+ style: {
1439
+ background: "none",
1440
+ border: "none",
1441
+ padding: 0,
1442
+ fontSize: "11px",
1443
+ color: "#7c3aed",
1444
+ cursor: "pointer",
1445
+ textDecoration: "underline"
1446
+ },
1447
+ children: sqlExpanded ? "Hide SQL" : "Show SQL"
1448
+ }
1449
+ ),
1450
+ sqlExpanded && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1451
+ "pre",
1452
+ {
1453
+ style: {
1454
+ marginTop: "4px",
1455
+ padding: "8px",
1456
+ backgroundColor: "#1e1b4b",
1457
+ color: "#c4b5fd",
1458
+ borderRadius: "6px",
1459
+ fontSize: "10px",
1460
+ overflowX: "auto",
1461
+ whiteSpace: "pre-wrap",
1462
+ wordBreak: "break-all"
1463
+ },
1464
+ children: detail.generatedSql
1465
+ }
1466
+ )
1467
+ ] }),
1468
+ rows && rows.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginTop: "8px" }, children: [
1469
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { fontSize: "11px", color: "#737373", marginBottom: "4px" }, children: [
1470
+ "Results (",
1471
+ rows.length,
1472
+ " row",
1473
+ rows.length !== 1 ? "s" : "",
1474
+ ")"
1475
+ ] }),
1476
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { overflowX: "auto" }, children: [
1477
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: { borderCollapse: "collapse", fontSize: "10px", width: "100%" }, children: [
1478
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: Object.keys(rows[0]).map((key) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1479
+ "th",
1480
+ {
1481
+ style: {
1482
+ padding: "4px 8px",
1483
+ backgroundColor: "#ede9fe",
1484
+ borderBottom: "1px solid #d8b4fe",
1485
+ textAlign: "left",
1486
+ fontWeight: 600,
1487
+ whiteSpace: "nowrap"
1488
+ },
1489
+ children: key
1490
+ },
1491
+ key
1492
+ )) }) }),
1493
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: rows.slice(0, 5).map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: Object.values(row).map((val, j) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1494
+ "td",
1495
+ {
1496
+ style: {
1497
+ padding: "3px 8px",
1498
+ borderBottom: "1px solid #f3e8ff",
1499
+ whiteSpace: "nowrap"
1500
+ },
1501
+ children: String(val ?? "")
1502
+ },
1503
+ j
1504
+ )) }, i)) })
1505
+ ] }),
1506
+ rows.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { fontSize: "10px", color: "#737373", marginTop: "4px" }, children: [
1507
+ "+ ",
1508
+ rows.length - 5,
1509
+ " more rows"
1510
+ ] })
1511
+ ] })
1512
+ ] })
1513
+ ]
1514
+ }
1515
+ );
1516
+ }
1517
+ function BreakdownItem({ label, value }) {
1518
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "6px" }, children: [
1519
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: "#737373", minWidth: "70px" }, children: [
1520
+ label,
1521
+ ":"
1522
+ ] }),
1523
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#1c1917" }, children: value })
1524
+ ] });
1525
+ }
1326
1526
  function SparklesIcon({ color = "currentColor" }) {
1327
1527
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", children: [
1328
1528
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z" }),
@@ -1339,6 +1539,13 @@ function MinimizeIcon() {
1339
1539
  function ChevronRightIcon({ size = 16, color = "currentColor" }) {
1340
1540
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M9 18l6-6-6-6" }) });
1341
1541
  }
1542
+ function ChartIcon({ size = 16, color = "currentColor" }) {
1543
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1544
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "18", y1: "20", x2: "18", y2: "10" }),
1545
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "20", x2: "12", y2: "4" }),
1546
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "6", y1: "20", x2: "6", y2: "14" })
1547
+ ] });
1548
+ }
1342
1549
  function BookIcon({ size = 16, color = "currentColor" }) {
1343
1550
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1344
1551
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4 19.5A2.5 2.5 0 016.5 17H20" }),
package/dist/index.mjs CHANGED
@@ -183,6 +183,15 @@ var InformedAIClient = class {
183
183
  return false;
184
184
  }
185
185
  // ========================================================================
186
+ // Analytics
187
+ // ========================================================================
188
+ /**
189
+ * Get details of a specific analytics run.
190
+ */
191
+ async getAnalyticsRun(sessionId, runId) {
192
+ return this.request(`/widget/sessions/${sessionId}/analytics-runs/${runId}`);
193
+ }
194
+ // ========================================================================
186
195
  // SSE Stream Processing
187
196
  // ========================================================================
188
197
  async processSSEStream(response, onEvent) {
@@ -680,6 +689,10 @@ function InformedAIProvider({ config, children }) {
680
689
  const clearError = useCallback(() => {
681
690
  setError(null);
682
691
  }, []);
692
+ const getAnalyticsRun = useCallback(async (sessionId, runId) => {
693
+ if (!clientRef.current) throw new Error("Client not initialized");
694
+ return clientRef.current.getAnalyticsRun(sessionId, runId);
695
+ }, []);
683
696
  const value = {
684
697
  session,
685
698
  document,
@@ -694,7 +707,9 @@ function InformedAIProvider({ config, children }) {
694
707
  skipTask,
695
708
  startNewSession,
696
709
  endSession,
697
- clearError
710
+ clearError,
711
+ onAnalyticsRunClick: config.onAnalyticsRunClick,
712
+ getAnalyticsRun
698
713
  };
699
714
  return /* @__PURE__ */ jsx(InformedAIContext.Provider, { value, children });
700
715
  }
@@ -1117,6 +1132,7 @@ function MessageBubble({ message, theme, onQuickAction, isLatest = false, quickA
1117
1132
  const isUser = message.role === "user";
1118
1133
  const hasQuickActions = isLatest && message.quickActions && message.quickActions.length > 0;
1119
1134
  const hasKbSearch = message.kbSearch != null;
1135
+ const hasAnalyticsRun = message.agentContext?.analyticsRun != null;
1120
1136
  if ((message.type === "quick_actions" || !message.content) && hasQuickActions) {
1121
1137
  return /* @__PURE__ */ jsx2(
1122
1138
  GroupedQuickActions,
@@ -1155,6 +1171,14 @@ function MessageBubble({ message, theme, onQuickAction, isLatest = false, quickA
1155
1171
  ]
1156
1172
  }
1157
1173
  ),
1174
+ hasAnalyticsRun && /* @__PURE__ */ jsx2(
1175
+ AnalyticsBadge,
1176
+ {
1177
+ runId: message.agentContext.analyticsRun.runId,
1178
+ query: message.agentContext.analyticsRun.query,
1179
+ status: message.agentContext.analyticsRun.status
1180
+ }
1181
+ ),
1158
1182
  /* @__PURE__ */ jsx2(
1159
1183
  "div",
1160
1184
  {
@@ -1290,6 +1314,182 @@ function GroupedQuickActions({ actions, groups, theme, onQuickAction }) {
1290
1314
  ] }, groupKey);
1291
1315
  }) });
1292
1316
  }
1317
+ function AnalyticsBadge({ runId, query, status }) {
1318
+ const { session, onAnalyticsRunClick, getAnalyticsRun } = useInformedAI();
1319
+ const [expanded, setExpanded] = useState2(false);
1320
+ const [runDetail, setRunDetail] = useState2(null);
1321
+ const [loading, setLoading] = useState2(false);
1322
+ const handleClick = () => {
1323
+ if (onAnalyticsRunClick && session) {
1324
+ onAnalyticsRunClick(runId, query, session.id);
1325
+ return;
1326
+ }
1327
+ setExpanded((prev) => !prev);
1328
+ };
1329
+ useEffect2(() => {
1330
+ if (expanded && !runDetail && !loading && session) {
1331
+ setLoading(true);
1332
+ getAnalyticsRun(session.id, runId).then(setRunDetail).catch((err) => console.warn("Failed to load analytics run:", err)).finally(() => setLoading(false));
1333
+ }
1334
+ }, [expanded, runDetail, loading, session, runId, getAnalyticsRun]);
1335
+ return /* @__PURE__ */ jsxs("div", { style: { marginBottom: "4px" }, children: [
1336
+ /* @__PURE__ */ jsxs(
1337
+ "button",
1338
+ {
1339
+ onClick: handleClick,
1340
+ style: {
1341
+ display: "inline-flex",
1342
+ alignItems: "center",
1343
+ gap: "6px",
1344
+ padding: "4px 10px",
1345
+ backgroundColor: status === "completed" ? "#ede9fe" : "#fef3c7",
1346
+ border: "none",
1347
+ borderRadius: "12px",
1348
+ fontSize: "11px",
1349
+ color: status === "completed" ? "#6d28d9" : "#92400e",
1350
+ cursor: "pointer",
1351
+ transition: "opacity 0.15s"
1352
+ },
1353
+ onMouseOver: (e) => {
1354
+ e.currentTarget.style.opacity = "0.8";
1355
+ },
1356
+ onMouseOut: (e) => {
1357
+ e.currentTarget.style.opacity = "1";
1358
+ },
1359
+ title: `Analytics query: ${query}`,
1360
+ children: [
1361
+ /* @__PURE__ */ jsx2(ChartIcon, { size: 12 }),
1362
+ /* @__PURE__ */ jsx2("span", { children: "Analytics query" }),
1363
+ !onAnalyticsRunClick && /* @__PURE__ */ jsx2("span", { style: { fontSize: "9px", marginLeft: "2px" }, children: expanded ? "\u25B2" : "\u25BC" })
1364
+ ]
1365
+ }
1366
+ ),
1367
+ expanded && !onAnalyticsRunClick && /* @__PURE__ */ jsx2(AnalyticsRunPanel, { detail: runDetail, loading })
1368
+ ] });
1369
+ }
1370
+ function AnalyticsRunPanel({ detail, loading }) {
1371
+ const [sqlExpanded, setSqlExpanded] = useState2(false);
1372
+ if (loading) {
1373
+ return /* @__PURE__ */ jsx2("div", { style: { padding: "12px", fontSize: "12px", color: "#737373" }, children: "Loading analytics details..." });
1374
+ }
1375
+ if (!detail) return null;
1376
+ const breakdown = detail.structuredBreakdown;
1377
+ const rows = detail.result;
1378
+ return /* @__PURE__ */ jsxs(
1379
+ "div",
1380
+ {
1381
+ style: {
1382
+ marginTop: "6px",
1383
+ padding: "12px",
1384
+ backgroundColor: "#faf5ff",
1385
+ borderRadius: "8px",
1386
+ fontSize: "12px",
1387
+ lineHeight: 1.5,
1388
+ border: "1px solid #e9d5ff"
1389
+ },
1390
+ children: [
1391
+ /* @__PURE__ */ jsx2("div", { style: { fontWeight: 600, color: "#6d28d9", marginBottom: "8px" }, children: detail.query }),
1392
+ breakdown && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "4px", marginBottom: "8px" }, children: [
1393
+ /* @__PURE__ */ jsx2(BreakdownItem, { label: "Dataset", value: breakdown.baseDataset }),
1394
+ breakdown.metrics.length > 0 && /* @__PURE__ */ jsx2(BreakdownItem, { label: "Metrics", value: breakdown.metrics.join(", ") }),
1395
+ breakdown.filters.length > 0 && /* @__PURE__ */ jsx2(BreakdownItem, { label: "Filters", value: breakdown.filters.join(", ") }),
1396
+ breakdown.grouping.length > 0 && /* @__PURE__ */ jsx2(BreakdownItem, { label: "Grouped by", value: breakdown.grouping.join(", ") }),
1397
+ breakdown.sorting && /* @__PURE__ */ jsx2(BreakdownItem, { label: "Sorted", value: breakdown.sorting }),
1398
+ breakdown.timeRange && /* @__PURE__ */ jsx2(BreakdownItem, { label: "Time range", value: breakdown.timeRange })
1399
+ ] }),
1400
+ detail.generatedSql && /* @__PURE__ */ jsxs("div", { children: [
1401
+ /* @__PURE__ */ jsx2(
1402
+ "button",
1403
+ {
1404
+ onClick: () => setSqlExpanded((prev) => !prev),
1405
+ style: {
1406
+ background: "none",
1407
+ border: "none",
1408
+ padding: 0,
1409
+ fontSize: "11px",
1410
+ color: "#7c3aed",
1411
+ cursor: "pointer",
1412
+ textDecoration: "underline"
1413
+ },
1414
+ children: sqlExpanded ? "Hide SQL" : "Show SQL"
1415
+ }
1416
+ ),
1417
+ sqlExpanded && /* @__PURE__ */ jsx2(
1418
+ "pre",
1419
+ {
1420
+ style: {
1421
+ marginTop: "4px",
1422
+ padding: "8px",
1423
+ backgroundColor: "#1e1b4b",
1424
+ color: "#c4b5fd",
1425
+ borderRadius: "6px",
1426
+ fontSize: "10px",
1427
+ overflowX: "auto",
1428
+ whiteSpace: "pre-wrap",
1429
+ wordBreak: "break-all"
1430
+ },
1431
+ children: detail.generatedSql
1432
+ }
1433
+ )
1434
+ ] }),
1435
+ rows && rows.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: "8px" }, children: [
1436
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "11px", color: "#737373", marginBottom: "4px" }, children: [
1437
+ "Results (",
1438
+ rows.length,
1439
+ " row",
1440
+ rows.length !== 1 ? "s" : "",
1441
+ ")"
1442
+ ] }),
1443
+ /* @__PURE__ */ jsxs("div", { style: { overflowX: "auto" }, children: [
1444
+ /* @__PURE__ */ jsxs("table", { style: { borderCollapse: "collapse", fontSize: "10px", width: "100%" }, children: [
1445
+ /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { children: Object.keys(rows[0]).map((key) => /* @__PURE__ */ jsx2(
1446
+ "th",
1447
+ {
1448
+ style: {
1449
+ padding: "4px 8px",
1450
+ backgroundColor: "#ede9fe",
1451
+ borderBottom: "1px solid #d8b4fe",
1452
+ textAlign: "left",
1453
+ fontWeight: 600,
1454
+ whiteSpace: "nowrap"
1455
+ },
1456
+ children: key
1457
+ },
1458
+ key
1459
+ )) }) }),
1460
+ /* @__PURE__ */ jsx2("tbody", { children: rows.slice(0, 5).map((row, i) => /* @__PURE__ */ jsx2("tr", { children: Object.values(row).map((val, j) => /* @__PURE__ */ jsx2(
1461
+ "td",
1462
+ {
1463
+ style: {
1464
+ padding: "3px 8px",
1465
+ borderBottom: "1px solid #f3e8ff",
1466
+ whiteSpace: "nowrap"
1467
+ },
1468
+ children: String(val ?? "")
1469
+ },
1470
+ j
1471
+ )) }, i)) })
1472
+ ] }),
1473
+ rows.length > 5 && /* @__PURE__ */ jsxs("div", { style: { fontSize: "10px", color: "#737373", marginTop: "4px" }, children: [
1474
+ "+ ",
1475
+ rows.length - 5,
1476
+ " more rows"
1477
+ ] })
1478
+ ] })
1479
+ ] })
1480
+ ]
1481
+ }
1482
+ );
1483
+ }
1484
+ function BreakdownItem({ label, value }) {
1485
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "6px" }, children: [
1486
+ /* @__PURE__ */ jsxs("span", { style: { color: "#737373", minWidth: "70px" }, children: [
1487
+ label,
1488
+ ":"
1489
+ ] }),
1490
+ /* @__PURE__ */ jsx2("span", { style: { color: "#1c1917" }, children: value })
1491
+ ] });
1492
+ }
1293
1493
  function SparklesIcon({ color = "currentColor" }) {
1294
1494
  return /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", children: [
1295
1495
  /* @__PURE__ */ jsx2("path", { d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z" }),
@@ -1306,6 +1506,13 @@ function MinimizeIcon() {
1306
1506
  function ChevronRightIcon({ size = 16, color = "currentColor" }) {
1307
1507
  return /* @__PURE__ */ jsx2("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx2("path", { d: "M9 18l6-6-6-6" }) });
1308
1508
  }
1509
+ function ChartIcon({ size = 16, color = "currentColor" }) {
1510
+ return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1511
+ /* @__PURE__ */ jsx2("line", { x1: "18", y1: "20", x2: "18", y2: "10" }),
1512
+ /* @__PURE__ */ jsx2("line", { x1: "12", y1: "20", x2: "12", y2: "4" }),
1513
+ /* @__PURE__ */ jsx2("line", { x1: "6", y1: "20", x2: "6", y2: "14" })
1514
+ ] });
1515
+ }
1309
1516
  function BookIcon({ size = 16, color = "currentColor" }) {
1310
1517
  return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1311
1518
  /* @__PURE__ */ jsx2("path", { d: "M4 19.5A2.5 2.5 0 016.5 17H20" }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@informedai/react",
3
- "version": "0.4.26",
3
+ "version": "0.4.28",
4
4
  "description": "React SDK for InformedAI Assistant - AI-powered content creation widget",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",