@trainly/react 1.1.3 → 1.3.1

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.
@@ -0,0 +1,304 @@
1
+ "use client";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
50
+ import * as React from "react";
51
+ import { useTrainly } from "../useTrainly";
52
+ export function TrainlyFileManager(_a) {
53
+ var _this = this;
54
+ var _b = _a.className, className = _b === void 0 ? "" : _b, onFileDeleted = _a.onFileDeleted, onError = _a.onError, _c = _a.showUploadButton, showUploadButton = _c === void 0 ? true : _c, _d = _a.maxFileSize, maxFileSize = _d === void 0 ? 5 : _d;
55
+ var _e = useTrainly(), listFiles = _e.listFiles, deleteFile = _e.deleteFile, upload = _e.upload, isLoading = _e.isLoading, error = _e.error;
56
+ var _f = React.useState([]), files = _f[0], setFiles = _f[1];
57
+ var _g = React.useState(false), isLoadingFiles = _g[0], setIsLoadingFiles = _g[1];
58
+ var _h = React.useState(null), isDeletingFile = _h[0], setIsDeletingFile = _h[1];
59
+ var _j = React.useState(false), isUploading = _j[0], setIsUploading = _j[1];
60
+ var fileInputRef = React.useRef(null);
61
+ // Load files on component mount
62
+ React.useEffect(function () {
63
+ loadFiles();
64
+ }, []);
65
+ var loadFiles = function () { return __awaiter(_this, void 0, void 0, function () {
66
+ var result, err_1, error_1;
67
+ return __generator(this, function (_a) {
68
+ switch (_a.label) {
69
+ case 0:
70
+ _a.trys.push([0, 2, 3, 4]);
71
+ setIsLoadingFiles(true);
72
+ return [4 /*yield*/, listFiles()];
73
+ case 1:
74
+ result = _a.sent();
75
+ setFiles(result.files);
76
+ return [3 /*break*/, 4];
77
+ case 2:
78
+ err_1 = _a.sent();
79
+ error_1 = err_1 instanceof Error ? err_1 : new Error(String(err_1));
80
+ console.error("Failed to load files:", error_1);
81
+ onError === null || onError === void 0 ? void 0 : onError(error_1);
82
+ return [3 /*break*/, 4];
83
+ case 3:
84
+ setIsLoadingFiles(false);
85
+ return [7 /*endfinally*/];
86
+ case 4: return [2 /*return*/];
87
+ }
88
+ });
89
+ }); };
90
+ var handleDeleteFile = function (fileId, filename) { return __awaiter(_this, void 0, void 0, function () {
91
+ var result, err_2, error_2;
92
+ return __generator(this, function (_a) {
93
+ switch (_a.label) {
94
+ case 0:
95
+ if (!confirm("Are you sure you want to delete \"".concat(filename, "\"? This action cannot be undone."))) {
96
+ return [2 /*return*/];
97
+ }
98
+ _a.label = 1;
99
+ case 1:
100
+ _a.trys.push([1, 3, 4, 5]);
101
+ setIsDeletingFile(fileId);
102
+ return [4 /*yield*/, deleteFile(fileId)];
103
+ case 2:
104
+ result = _a.sent();
105
+ // Remove file from local state
106
+ setFiles(function (prev) { return prev.filter(function (f) { return f.file_id !== fileId; }); });
107
+ // Notify parent component
108
+ onFileDeleted === null || onFileDeleted === void 0 ? void 0 : onFileDeleted(fileId, filename);
109
+ console.log("File deleted: ".concat(result.message));
110
+ return [3 /*break*/, 5];
111
+ case 3:
112
+ err_2 = _a.sent();
113
+ error_2 = err_2 instanceof Error ? err_2 : new Error(String(err_2));
114
+ console.error("Failed to delete file:", error_2);
115
+ onError === null || onError === void 0 ? void 0 : onError(error_2);
116
+ return [3 /*break*/, 5];
117
+ case 4:
118
+ setIsDeletingFile(null);
119
+ return [7 /*endfinally*/];
120
+ case 5: return [2 /*return*/];
121
+ }
122
+ });
123
+ }); };
124
+ var handleFileUpload = function (event) { return __awaiter(_this, void 0, void 0, function () {
125
+ var file, error_3, result, err_3, error_4;
126
+ var _a;
127
+ return __generator(this, function (_b) {
128
+ switch (_b.label) {
129
+ case 0:
130
+ file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
131
+ if (!file)
132
+ return [2 /*return*/];
133
+ // Check file size
134
+ if (file.size > maxFileSize * 1024 * 1024) {
135
+ error_3 = new Error("File size must be less than ".concat(maxFileSize, "MB"));
136
+ onError === null || onError === void 0 ? void 0 : onError(error_3);
137
+ return [2 /*return*/];
138
+ }
139
+ _b.label = 1;
140
+ case 1:
141
+ _b.trys.push([1, 5, 6, 7]);
142
+ setIsUploading(true);
143
+ return [4 /*yield*/, upload(file)];
144
+ case 2:
145
+ result = _b.sent();
146
+ if (!result.success) return [3 /*break*/, 4];
147
+ // Reload files to show the new upload
148
+ return [4 /*yield*/, loadFiles()];
149
+ case 3:
150
+ // Reload files to show the new upload
151
+ _b.sent();
152
+ console.log("File uploaded: ".concat(result.filename));
153
+ _b.label = 4;
154
+ case 4: return [3 /*break*/, 7];
155
+ case 5:
156
+ err_3 = _b.sent();
157
+ error_4 = err_3 instanceof Error ? err_3 : new Error(String(err_3));
158
+ console.error("Failed to upload file:", error_4);
159
+ onError === null || onError === void 0 ? void 0 : onError(error_4);
160
+ return [3 /*break*/, 7];
161
+ case 6:
162
+ setIsUploading(false);
163
+ // Clear the input
164
+ if (fileInputRef.current) {
165
+ fileInputRef.current.value = "";
166
+ }
167
+ return [7 /*endfinally*/];
168
+ case 7: return [2 /*return*/];
169
+ }
170
+ });
171
+ }); };
172
+ var formatFileSize = function (bytes) {
173
+ if (bytes === 0)
174
+ return "0 Bytes";
175
+ var k = 1024;
176
+ var sizes = ["Bytes", "KB", "MB", "GB"];
177
+ var i = Math.floor(Math.log(bytes) / Math.log(k));
178
+ return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + " " + sizes[i];
179
+ };
180
+ var formatDate = function (dateString) {
181
+ try {
182
+ var date = new Date(parseInt(dateString));
183
+ return date.toLocaleDateString() + " " + date.toLocaleTimeString();
184
+ }
185
+ catch (_a) {
186
+ return dateString;
187
+ }
188
+ };
189
+ var totalSize = files.reduce(function (sum, file) { return sum + file.size_bytes; }, 0);
190
+ var styles = {
191
+ container: {
192
+ border: "1px solid #e5e7eb",
193
+ borderRadius: "8px",
194
+ padding: "16px",
195
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif",
196
+ },
197
+ header: {
198
+ display: "flex",
199
+ justifyContent: "space-between",
200
+ alignItems: "flex-start",
201
+ marginBottom: "16px",
202
+ },
203
+ title: {
204
+ margin: "0 0 4px 0",
205
+ fontSize: "18px",
206
+ fontWeight: "600",
207
+ color: "#1f2937",
208
+ },
209
+ totalSize: {
210
+ margin: "0",
211
+ fontSize: "14px",
212
+ color: "#6b7280",
213
+ },
214
+ uploadButton: {
215
+ backgroundColor: "#3b82f6",
216
+ color: "white",
217
+ border: "none",
218
+ borderRadius: "6px",
219
+ padding: "8px 16px",
220
+ fontSize: "14px",
221
+ cursor: "pointer",
222
+ transition: "background-color 0.2s",
223
+ },
224
+ uploadButtonDisabled: {
225
+ backgroundColor: "#9ca3af",
226
+ cursor: "not-allowed",
227
+ },
228
+ error: {
229
+ backgroundColor: "#fef2f2",
230
+ color: "#dc2626",
231
+ padding: "12px",
232
+ borderRadius: "6px",
233
+ marginBottom: "16px",
234
+ fontSize: "14px",
235
+ },
236
+ loading: {
237
+ textAlign: "center",
238
+ padding: "32px",
239
+ color: "#6b7280",
240
+ fontSize: "14px",
241
+ },
242
+ emptyState: {
243
+ textAlign: "center",
244
+ padding: "32px",
245
+ color: "#6b7280",
246
+ },
247
+ emptyStateText: {
248
+ margin: "0 0 8px 0",
249
+ fontSize: "14px",
250
+ },
251
+ fileItem: {
252
+ display: "flex",
253
+ justifyContent: "space-between",
254
+ alignItems: "center",
255
+ padding: "12px",
256
+ border: "1px solid #f3f4f6",
257
+ borderRadius: "6px",
258
+ backgroundColor: "#f9fafb",
259
+ marginBottom: "8px",
260
+ transition: "background-color 0.2s",
261
+ },
262
+ fileName: {
263
+ fontWeight: "500",
264
+ color: "#1f2937",
265
+ fontSize: "14px",
266
+ marginBottom: "4px",
267
+ },
268
+ fileMeta: {
269
+ fontSize: "12px",
270
+ color: "#6b7280",
271
+ },
272
+ deleteButton: {
273
+ backgroundColor: "#dc2626",
274
+ color: "white",
275
+ border: "none",
276
+ borderRadius: "4px",
277
+ padding: "6px 12px",
278
+ fontSize: "12px",
279
+ cursor: "pointer",
280
+ transition: "background-color 0.2s",
281
+ },
282
+ deleteButtonDisabled: {
283
+ backgroundColor: "#9ca3af",
284
+ cursor: "not-allowed",
285
+ },
286
+ };
287
+ return (_jsxs("div", { className: className, style: styles.container, children: [_jsxs("div", { style: styles.header, children: [_jsxs("div", { children: [_jsxs("h3", { style: styles.title, children: ["Your Files (", files.length, ")"] }), _jsxs("p", { style: styles.totalSize, children: ["Total: ", formatFileSize(totalSize)] })] }), showUploadButton && (_jsxs("div", { children: [_jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileUpload, disabled: isUploading || isLoading, accept: ".pdf,.docx,.txt,.md,.csv,.json,.html,.xml,.yaml,.yml,.js,.py,.java,.cpp,.c,.h,.cs,.php,.rb,.sh,.bat,.ps1", style: { display: "none" } }), _jsx("button", { onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: isUploading || isLoading, style: __assign(__assign({}, styles.uploadButton), (isUploading || isLoading
288
+ ? styles.uploadButtonDisabled
289
+ : {})), children: isUploading ? "Uploading..." : "Upload File" })] }))] }), error && _jsx("div", { style: styles.error, children: error.message }), isLoadingFiles ? (_jsx("div", { style: styles.loading, children: "Loading files..." })) : files.length === 0 ? (_jsxs("div", { style: styles.emptyState, children: [_jsx("p", { style: styles.emptyStateText, children: "No files uploaded yet." }), showUploadButton && (_jsx("p", { style: styles.emptyStateText, children: "Click \"Upload File\" to add your first document." }))] })) : (_jsx("div", { children: files.map(function (file) { return (_jsxs("div", { style: styles.fileItem, onMouseEnter: function (e) {
290
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
291
+ }, onMouseLeave: function (e) {
292
+ e.currentTarget.style.backgroundColor = "#f9fafb";
293
+ }, children: [_jsxs("div", { children: [_jsx("div", { style: styles.fileName, children: file.filename }), _jsxs("div", { style: styles.fileMeta, children: [formatFileSize(file.size_bytes), " \u2022 ", file.chunk_count, " chunks \u2022 ", formatDate(file.upload_date)] })] }), _jsx("div", { children: _jsx("button", { onClick: function () { return handleDeleteFile(file.file_id, file.filename); }, disabled: isDeletingFile === file.file_id || isLoading, style: __assign(__assign({}, styles.deleteButton), (isDeletingFile === file.file_id || isLoading
294
+ ? styles.deleteButtonDisabled
295
+ : {})), onMouseEnter: function (e) {
296
+ if (!e.currentTarget.disabled) {
297
+ e.currentTarget.style.backgroundColor = "#b91c1c";
298
+ }
299
+ }, onMouseLeave: function (e) {
300
+ if (!e.currentTarget.disabled) {
301
+ e.currentTarget.style.backgroundColor = "#dc2626";
302
+ }
303
+ }, children: isDeletingFile === file.file_id ? "Deleting..." : "Delete" }) })] }, file.file_id)); }) }))] }));
304
+ }
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export { useTrainly } from "./useTrainly";
3
3
  export { TrainlyChat } from "./components/TrainlyChat";
4
4
  export { TrainlyUpload } from "./components/TrainlyUpload";
5
5
  export { TrainlyStatus } from "./components/TrainlyStatus";
6
- export type { TrainlyProviderProps, TrainlyConfig, ChatMessage, Citation, UploadResult, TrainlyError, } from "./types";
6
+ export { TrainlyFileManager } from "./components/TrainlyFileManager";
7
+ export type { TrainlyProviderProps, TrainlyConfig, ChatMessage, Citation, UploadResult, FileInfo, FileListResult, FileDeleteResult, TrainlyError, TrainlyFileManagerProps, } from "./types";
package/dist/index.js CHANGED
@@ -5,3 +5,4 @@ export { useTrainly } from "./useTrainly";
5
5
  export { TrainlyChat } from "./components/TrainlyChat";
6
6
  export { TrainlyUpload } from "./components/TrainlyUpload";
7
7
  export { TrainlyStatus } from "./components/TrainlyStatus";
8
+ export { TrainlyFileManager } from "./components/TrainlyFileManager";
package/dist/types.d.ts CHANGED
@@ -34,11 +34,59 @@ export interface UploadResult {
34
34
  size: number;
35
35
  message?: string;
36
36
  }
37
+ export interface BulkUploadFileResult {
38
+ filename: string;
39
+ success: boolean;
40
+ error: string | null;
41
+ file_id: string | null;
42
+ size_bytes: number;
43
+ processing_status: string;
44
+ message?: string;
45
+ }
46
+ export interface BulkUploadResult {
47
+ success: boolean;
48
+ total_files: number;
49
+ successful_uploads: number;
50
+ failed_uploads: number;
51
+ total_size_bytes: number;
52
+ chat_id: string;
53
+ user_id: string;
54
+ results: BulkUploadFileResult[];
55
+ message: string;
56
+ }
57
+ export interface FileInfo {
58
+ file_id: string;
59
+ filename: string;
60
+ upload_date: string;
61
+ size_bytes: number;
62
+ chunk_count: number;
63
+ }
64
+ export interface FileListResult {
65
+ success: boolean;
66
+ files: FileInfo[];
67
+ total_files: number;
68
+ total_size_bytes: number;
69
+ }
70
+ export interface FileDeleteResult {
71
+ success: boolean;
72
+ message: string;
73
+ file_id: string;
74
+ filename: string;
75
+ chunks_deleted: number;
76
+ size_bytes_freed: number;
77
+ }
37
78
  export interface TrainlyError {
38
79
  code: string;
39
80
  message: string;
40
81
  details?: any;
41
82
  }
83
+ export interface TrainlyFileManagerProps {
84
+ className?: string;
85
+ onFileDeleted?: (fileId: string, filename: string) => void;
86
+ onError?: (error: Error) => void;
87
+ showUploadButton?: boolean;
88
+ maxFileSize?: number;
89
+ }
42
90
  export interface TrainlyContextValue {
43
91
  ask: (question: string) => Promise<string>;
44
92
  askWithCitations: (question: string) => Promise<{
@@ -46,6 +94,9 @@ export interface TrainlyContextValue {
46
94
  citations: Citation[];
47
95
  }>;
48
96
  upload: (file: File) => Promise<UploadResult>;
97
+ listFiles: () => Promise<FileListResult>;
98
+ deleteFile: (fileId: string) => Promise<FileDeleteResult>;
99
+ bulkUploadFiles: (files: File[]) => Promise<BulkUploadResult>;
49
100
  connectWithOAuthToken: (idToken: string) => Promise<void>;
50
101
  isLoading: boolean;
51
102
  isConnected: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trainly/react",
3
- "version": "1.1.3",
3
+ "version": "1.3.1",
4
4
  "description": "Dead simple RAG integration for React apps with OAuth authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -25,7 +25,10 @@
25
25
  "auth0",
26
26
  "retrieval-augmented-generation",
27
27
  "semantic-search",
28
- "document-chat"
28
+ "document-chat",
29
+ "file-management",
30
+ "file-upload",
31
+ "file-deletion"
29
32
  ],
30
33
  "author": "Trainly",
31
34
  "license": "MIT",