@smallwebco/tinypivot-react 1.0.60 → 1.0.62

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.cjs CHANGED
@@ -101,6 +101,7 @@ function useAIAnalyst(options) {
101
101
  }, [storageKey]);
102
102
  const [conversation, setConversation] = (0, import_react.useState)(() => loadFromStorage());
103
103
  const [schemas, setSchemas] = (0, import_react.useState)(/* @__PURE__ */ new Map());
104
+ const [allSchemas, setAllSchemas] = (0, import_react.useState)([]);
104
105
  const [isLoading, setIsLoading] = (0, import_react.useState)(false);
105
106
  const [error, setError] = (0, import_react.useState)(null);
106
107
  const [lastLoadedData, setLastLoadedData] = (0, import_react.useState)(null);
@@ -122,6 +123,34 @@ function useAIAnalyst(options) {
122
123
  );
123
124
  const messages = conversation.messages;
124
125
  const hasMessages = conversation.messages.length > 0;
126
+ const fetchAllSchemas = (0, import_react.useCallback)(async () => {
127
+ if (!configRef.current.endpoint)
128
+ return;
129
+ try {
130
+ const response = await fetch(configRef.current.endpoint, {
131
+ method: "POST",
132
+ headers: { "Content-Type": "application/json" },
133
+ body: JSON.stringify({ action: "get-all-schemas" })
134
+ });
135
+ if (!response.ok) {
136
+ throw new Error(`Failed to fetch all schemas: ${response.statusText}`);
137
+ }
138
+ const data = await response.json();
139
+ if (data.error) {
140
+ throw new Error(data.error);
141
+ }
142
+ setAllSchemas(data.schemas);
143
+ setSchemas((prev) => {
144
+ const newMap = new Map(prev);
145
+ for (const schema of data.schemas) {
146
+ newMap.set(schema.table, schema);
147
+ }
148
+ return newMap;
149
+ });
150
+ } catch (err) {
151
+ console.warn("[TinyPivot] Failed to fetch all schemas:", err);
152
+ }
153
+ }, []);
125
154
  const fetchTables = (0, import_react.useCallback)(async () => {
126
155
  if (!configRef.current.endpoint)
127
156
  return;
@@ -146,6 +175,7 @@ function useAIAnalyst(options) {
146
175
  // Capitalize
147
176
  description: t.description
148
177
  })));
178
+ await fetchAllSchemas();
149
179
  } catch (err) {
150
180
  console.warn("[TinyPivot] Failed to fetch tables:", err);
151
181
  onError?.({
@@ -155,7 +185,7 @@ function useAIAnalyst(options) {
155
185
  } finally {
156
186
  setIsLoadingTables(false);
157
187
  }
158
- }, [onError]);
188
+ }, [onError, fetchAllSchemas]);
159
189
  (0, import_react.useEffect)(() => {
160
190
  if (configRef.current.endpoint && (!config.dataSources || config.dataSources.length === 0)) {
161
191
  fetchTables();
@@ -187,6 +217,40 @@ function useAIAnalyst(options) {
187
217
  console.warn("Failed to fetch schema:", err);
188
218
  }
189
219
  }, []);
220
+ const fetchSampleData = (0, import_react.useCallback)(async (dataSource) => {
221
+ if (!configRef.current.endpoint)
222
+ return;
223
+ try {
224
+ const sql = `SELECT * FROM ${dataSource.table} LIMIT 100`;
225
+ const response = await fetch(configRef.current.endpoint, {
226
+ method: "POST",
227
+ headers: { "Content-Type": "application/json" },
228
+ body: JSON.stringify({
229
+ action: "query",
230
+ sql,
231
+ table: dataSource.table
232
+ })
233
+ });
234
+ if (!response.ok) {
235
+ throw new Error(`Failed to fetch sample data: ${response.statusText}`);
236
+ }
237
+ const result = await response.json();
238
+ if (result.error) {
239
+ throw new Error(result.error);
240
+ }
241
+ if (result.data && result.data.length > 0) {
242
+ setLastLoadedData(result.data);
243
+ onDataLoaded?.({
244
+ data: result.data,
245
+ query: sql,
246
+ dataSourceId: dataSource.id,
247
+ rowCount: result.data.length
248
+ });
249
+ }
250
+ } catch (err) {
251
+ console.warn("Failed to fetch sample data:", err);
252
+ }
253
+ }, [onDataLoaded]);
190
254
  const selectDataSource = (0, import_react.useCallback)(async (dataSourceId) => {
191
255
  const dataSource = effectiveDataSources.find((ds) => ds.id === dataSourceId);
192
256
  if (!dataSource) {
@@ -241,9 +305,10 @@ What would you like to know about this data?`
241
305
  }
242
306
  } else if (configRef.current.endpoint) {
243
307
  await fetchSchema(dataSource);
308
+ await fetchSampleData(dataSource);
244
309
  }
245
- }, [effectiveDataSources, fetchSchema, onConversationUpdate, onDataLoaded]);
246
- const callAIEndpoint = (0, import_react.useCallback)(async (userInput, currentConversation, currentSchemas, currentDataSources) => {
310
+ }, [effectiveDataSources, fetchSchema, fetchSampleData, onConversationUpdate, onDataLoaded]);
311
+ const callAIEndpoint = (0, import_react.useCallback)(async (userInput, currentConversation, currentSchemas, currentDataSources, currentAllSchemas) => {
247
312
  if (!configRef.current.endpoint) {
248
313
  throw new Error("No endpoint configured. Set `endpoint` in AI analyst config.");
249
314
  }
@@ -251,7 +316,8 @@ What would you like to know about this data?`
251
316
  const systemPrompt = (0, import_tinypivot_core.buildSystemPrompt)(
252
317
  currentDataSources,
253
318
  currentSchemas,
254
- dataSourceId
319
+ dataSourceId,
320
+ currentAllSchemas.length > 0 ? currentAllSchemas : void 0
255
321
  );
256
322
  const apiMessages = (0, import_tinypivot_core.getMessagesForAPI)(currentConversation);
257
323
  const messages2 = [
@@ -510,7 +576,7 @@ What would you like to know about this data?`
510
576
  });
511
577
  return;
512
578
  }
513
- const aiResponse = await callAIEndpoint(content, currentConv, schemas, effectiveDataSources);
579
+ const aiResponse = await callAIEndpoint(content, currentConv, schemas, effectiveDataSources, allSchemas);
514
580
  const sqlQuery = (0, import_tinypivot_core.extractSQLFromResponse)(aiResponse);
515
581
  if (sqlQuery) {
516
582
  const validation = (0, import_tinypivot_core.validateSQLSafety)(sqlQuery);