@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.js CHANGED
@@ -57,6 +57,7 @@ function useAIAnalyst(options) {
57
57
  }, [storageKey]);
58
58
  const [conversation, setConversation] = useState(() => loadFromStorage());
59
59
  const [schemas, setSchemas] = useState(/* @__PURE__ */ new Map());
60
+ const [allSchemas, setAllSchemas] = useState([]);
60
61
  const [isLoading, setIsLoading] = useState(false);
61
62
  const [error, setError] = useState(null);
62
63
  const [lastLoadedData, setLastLoadedData] = useState(null);
@@ -78,6 +79,34 @@ function useAIAnalyst(options) {
78
79
  );
79
80
  const messages = conversation.messages;
80
81
  const hasMessages = conversation.messages.length > 0;
82
+ const fetchAllSchemas = useCallback(async () => {
83
+ if (!configRef.current.endpoint)
84
+ return;
85
+ try {
86
+ const response = await fetch(configRef.current.endpoint, {
87
+ method: "POST",
88
+ headers: { "Content-Type": "application/json" },
89
+ body: JSON.stringify({ action: "get-all-schemas" })
90
+ });
91
+ if (!response.ok) {
92
+ throw new Error(`Failed to fetch all schemas: ${response.statusText}`);
93
+ }
94
+ const data = await response.json();
95
+ if (data.error) {
96
+ throw new Error(data.error);
97
+ }
98
+ setAllSchemas(data.schemas);
99
+ setSchemas((prev) => {
100
+ const newMap = new Map(prev);
101
+ for (const schema of data.schemas) {
102
+ newMap.set(schema.table, schema);
103
+ }
104
+ return newMap;
105
+ });
106
+ } catch (err) {
107
+ console.warn("[TinyPivot] Failed to fetch all schemas:", err);
108
+ }
109
+ }, []);
81
110
  const fetchTables = useCallback(async () => {
82
111
  if (!configRef.current.endpoint)
83
112
  return;
@@ -102,6 +131,7 @@ function useAIAnalyst(options) {
102
131
  // Capitalize
103
132
  description: t.description
104
133
  })));
134
+ await fetchAllSchemas();
105
135
  } catch (err) {
106
136
  console.warn("[TinyPivot] Failed to fetch tables:", err);
107
137
  onError?.({
@@ -111,7 +141,7 @@ function useAIAnalyst(options) {
111
141
  } finally {
112
142
  setIsLoadingTables(false);
113
143
  }
114
- }, [onError]);
144
+ }, [onError, fetchAllSchemas]);
115
145
  useEffect(() => {
116
146
  if (configRef.current.endpoint && (!config.dataSources || config.dataSources.length === 0)) {
117
147
  fetchTables();
@@ -143,6 +173,40 @@ function useAIAnalyst(options) {
143
173
  console.warn("Failed to fetch schema:", err);
144
174
  }
145
175
  }, []);
176
+ const fetchSampleData = useCallback(async (dataSource) => {
177
+ if (!configRef.current.endpoint)
178
+ return;
179
+ try {
180
+ const sql = `SELECT * FROM ${dataSource.table} LIMIT 100`;
181
+ const response = await fetch(configRef.current.endpoint, {
182
+ method: "POST",
183
+ headers: { "Content-Type": "application/json" },
184
+ body: JSON.stringify({
185
+ action: "query",
186
+ sql,
187
+ table: dataSource.table
188
+ })
189
+ });
190
+ if (!response.ok) {
191
+ throw new Error(`Failed to fetch sample data: ${response.statusText}`);
192
+ }
193
+ const result = await response.json();
194
+ if (result.error) {
195
+ throw new Error(result.error);
196
+ }
197
+ if (result.data && result.data.length > 0) {
198
+ setLastLoadedData(result.data);
199
+ onDataLoaded?.({
200
+ data: result.data,
201
+ query: sql,
202
+ dataSourceId: dataSource.id,
203
+ rowCount: result.data.length
204
+ });
205
+ }
206
+ } catch (err) {
207
+ console.warn("Failed to fetch sample data:", err);
208
+ }
209
+ }, [onDataLoaded]);
146
210
  const selectDataSource = useCallback(async (dataSourceId) => {
147
211
  const dataSource = effectiveDataSources.find((ds) => ds.id === dataSourceId);
148
212
  if (!dataSource) {
@@ -197,9 +261,10 @@ What would you like to know about this data?`
197
261
  }
198
262
  } else if (configRef.current.endpoint) {
199
263
  await fetchSchema(dataSource);
264
+ await fetchSampleData(dataSource);
200
265
  }
201
- }, [effectiveDataSources, fetchSchema, onConversationUpdate, onDataLoaded]);
202
- const callAIEndpoint = useCallback(async (userInput, currentConversation, currentSchemas, currentDataSources) => {
266
+ }, [effectiveDataSources, fetchSchema, fetchSampleData, onConversationUpdate, onDataLoaded]);
267
+ const callAIEndpoint = useCallback(async (userInput, currentConversation, currentSchemas, currentDataSources, currentAllSchemas) => {
203
268
  if (!configRef.current.endpoint) {
204
269
  throw new Error("No endpoint configured. Set `endpoint` in AI analyst config.");
205
270
  }
@@ -207,7 +272,8 @@ What would you like to know about this data?`
207
272
  const systemPrompt = buildSystemPrompt(
208
273
  currentDataSources,
209
274
  currentSchemas,
210
- dataSourceId
275
+ dataSourceId,
276
+ currentAllSchemas.length > 0 ? currentAllSchemas : void 0
211
277
  );
212
278
  const apiMessages = getMessagesForAPI(currentConversation);
213
279
  const messages2 = [
@@ -466,7 +532,7 @@ What would you like to know about this data?`
466
532
  });
467
533
  return;
468
534
  }
469
- const aiResponse = await callAIEndpoint(content, currentConv, schemas, effectiveDataSources);
535
+ const aiResponse = await callAIEndpoint(content, currentConv, schemas, effectiveDataSources, allSchemas);
470
536
  const sqlQuery = extractSQLFromResponse(aiResponse);
471
537
  if (sqlQuery) {
472
538
  const validation = validateSQLSafety(sqlQuery);