@memori.ai/memori-react 8.38.3 → 8.38.4
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/CHANGELOG.md +13 -0
- package/dist/components/ChatInputs/ChatInputs.js +6 -2
- package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
- package/dist/components/FilePreview/FilePreview.css +49 -0
- package/dist/components/FilePreview/FilePreview.d.ts +2 -1
- package/dist/components/FilePreview/FilePreview.js +11 -10
- package/dist/components/FilePreview/FilePreview.js.map +1 -1
- package/dist/components/UploadButton/UploadButton.d.ts +1 -0
- package/dist/components/UploadButton/UploadButton.js +21 -22
- package/dist/components/UploadButton/UploadButton.js.map +1 -1
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.d.ts +1 -1
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js +76 -68
- package/dist/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/dist/components/UploadButton/UploadImages/UploadImages.d.ts +1 -1
- package/dist/components/UploadButton/UploadImages/UploadImages.js +5 -2
- package/dist/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/esm/components/ChatInputs/ChatInputs.js +6 -2
- package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
- package/esm/components/FilePreview/FilePreview.css +49 -0
- package/esm/components/FilePreview/FilePreview.d.ts +2 -1
- package/esm/components/FilePreview/FilePreview.js +11 -10
- package/esm/components/FilePreview/FilePreview.js.map +1 -1
- package/esm/components/UploadButton/UploadButton.d.ts +1 -0
- package/esm/components/UploadButton/UploadButton.js +21 -22
- package/esm/components/UploadButton/UploadButton.js.map +1 -1
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.d.ts +1 -1
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js +77 -69
- package/esm/components/UploadButton/UploadDocuments/UploadDocuments.js.map +1 -1
- package/esm/components/UploadButton/UploadImages/UploadImages.d.ts +1 -1
- package/esm/components/UploadButton/UploadImages/UploadImages.js +5 -2
- package/esm/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
- package/esm/version.d.ts +1 -1
- package/esm/version.js +1 -1
- package/package.json +1 -1
- package/src/components/ChatInputs/ChatInputs.tsx +11 -2
- package/src/components/FilePreview/FilePreview.css +49 -0
- package/src/components/FilePreview/FilePreview.tsx +18 -4
- package/src/components/UploadButton/UploadButton.tsx +33 -27
- package/src/components/UploadButton/UploadDocuments/UploadDocuments.tsx +102 -101
- package/src/components/UploadButton/UploadImages/UploadImages.tsx +6 -4
- package/src/version.ts +1 -1
|
@@ -255,6 +255,55 @@
|
|
|
255
255
|
line-height: 1.5;
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
/* Skeleton loading card */
|
|
259
|
+
.memori--preview-item--skeleton {
|
|
260
|
+
min-width: 140px;
|
|
261
|
+
cursor: default;
|
|
262
|
+
pointer-events: none;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.memori--preview-item--skeleton:hover {
|
|
266
|
+
background-color: #f8f9fa;
|
|
267
|
+
transform: none;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.memori--skeleton-icon {
|
|
271
|
+
width: 20px;
|
|
272
|
+
height: 20px;
|
|
273
|
+
flex-shrink: 0;
|
|
274
|
+
border-radius: 4px;
|
|
275
|
+
animation: memori-skeleton-pulse 1.5s ease-in-out infinite;
|
|
276
|
+
background: linear-gradient(90deg, #e9ecef 25%, #f1f3f5 50%, #e9ecef 75%);
|
|
277
|
+
background-size: 200% 100%;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.memori--skeleton-line {
|
|
281
|
+
border-radius: 4px;
|
|
282
|
+
animation: memori-skeleton-pulse 1.5s ease-in-out infinite;
|
|
283
|
+
background: linear-gradient(90deg, #e9ecef 25%, #f1f3f5 50%, #e9ecef 75%);
|
|
284
|
+
background-size: 200% 100%;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.memori--skeleton-line--name {
|
|
288
|
+
width: 80px;
|
|
289
|
+
height: 12px;
|
|
290
|
+
margin-bottom: 6px;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.memori--skeleton-line--type {
|
|
294
|
+
width: 40px;
|
|
295
|
+
height: 10px;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@keyframes memori-skeleton-pulse {
|
|
299
|
+
0% {
|
|
300
|
+
background-position: 200% 0;
|
|
301
|
+
}
|
|
302
|
+
100% {
|
|
303
|
+
background-position: -200% 0;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
258
307
|
@keyframes fadeIn {
|
|
259
308
|
from {
|
|
260
309
|
opacity: 0;
|
|
@@ -13,7 +13,7 @@ type FilePreviewProps = {
|
|
|
13
13
|
removeFile: (id: string, mediumID: string | undefined) => void;
|
|
14
14
|
allowRemove?: boolean;
|
|
15
15
|
showAnonymousRetentionNotice?: boolean;
|
|
16
|
-
|
|
16
|
+
uploadingCount?: number;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
const FilePreview = ({
|
|
@@ -21,8 +21,8 @@ const FilePreview = ({
|
|
|
21
21
|
removeFile,
|
|
22
22
|
allowRemove = true,
|
|
23
23
|
showAnonymousRetentionNotice = false,
|
|
24
|
-
|
|
25
|
-
FilePreviewProps) => {
|
|
24
|
+
uploadingCount = 0,
|
|
25
|
+
}: FilePreviewProps) => {
|
|
26
26
|
const { t } = useTranslation();
|
|
27
27
|
const [selectedFile, setSelectedFile] = useState<{
|
|
28
28
|
name: string;
|
|
@@ -139,7 +139,7 @@ FilePreviewProps) => {
|
|
|
139
139
|
|
|
140
140
|
return (
|
|
141
141
|
<>
|
|
142
|
-
{previewFiles.length > 0 && (
|
|
142
|
+
{(previewFiles.length > 0 || uploadingCount > 0) && (
|
|
143
143
|
<div className="memori--preview-container">
|
|
144
144
|
{showAnonymousRetentionNotice && (
|
|
145
145
|
<small
|
|
@@ -199,6 +199,20 @@ FilePreviewProps) => {
|
|
|
199
199
|
)}
|
|
200
200
|
</div>
|
|
201
201
|
))}
|
|
202
|
+
|
|
203
|
+
{uploadingCount > 0 &&
|
|
204
|
+
Array.from({ length: uploadingCount }, (_, i) => (
|
|
205
|
+
<div
|
|
206
|
+
key={`skeleton-${i}`}
|
|
207
|
+
className="memori--preview-item memori--preview-item--document memori--preview-item--skeleton"
|
|
208
|
+
>
|
|
209
|
+
<div className="memori--skeleton-icon" />
|
|
210
|
+
<div className="memori--preview-file-info">
|
|
211
|
+
<div className="memori--skeleton-line memori--skeleton-line--name" />
|
|
212
|
+
<div className="memori--skeleton-line memori--skeleton-line--type" />
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
))}
|
|
202
216
|
</div>
|
|
203
217
|
</div>
|
|
204
218
|
)}
|
|
@@ -31,6 +31,8 @@ interface UploadManagerProps {
|
|
|
31
31
|
maxDocumentsPerMessage?: number;
|
|
32
32
|
/** Per-document content character limit. */
|
|
33
33
|
maxDocumentContentLength?: number;
|
|
34
|
+
/** Called when the upload loading state changes. */
|
|
35
|
+
onUploadLoadingChange?: (loading: boolean, fileCount?: number) => void;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
const UploadButton: React.FC<UploadManagerProps> = ({
|
|
@@ -44,11 +46,17 @@ const UploadButton: React.FC<UploadManagerProps> = ({
|
|
|
44
46
|
maxTotalMessagePayload,
|
|
45
47
|
maxDocumentsPerMessage = 10,
|
|
46
48
|
maxDocumentContentLength = 300000,
|
|
49
|
+
onUploadLoadingChange,
|
|
47
50
|
}) => {
|
|
48
51
|
const effectivePerDocumentLimit =
|
|
49
52
|
maxTotalMessagePayload ?? maxDocumentContentLength ?? 300000;
|
|
50
53
|
// State
|
|
51
|
-
const [
|
|
54
|
+
const [isDocumentLoading, setIsDocumentLoading] = useState(false);
|
|
55
|
+
const [isImageLoading, setIsImageLoading] = useState(false);
|
|
56
|
+
const isLoading = isDocumentLoading || isImageLoading;
|
|
57
|
+
const [docUploadingCount, setDocUploadingCount] = useState(0);
|
|
58
|
+
const [imgUploadingCount, setImgUploadingCount] = useState(0);
|
|
59
|
+
const uploadingFileCount = docUploadingCount + imgUploadingCount;
|
|
52
60
|
const [errors, setErrors] = useState<
|
|
53
61
|
{ message: string; severity: 'error' | 'warning' | 'info' }[]
|
|
54
62
|
>([]);
|
|
@@ -189,9 +197,9 @@ const UploadButton: React.FC<UploadManagerProps> = ({
|
|
|
189
197
|
}
|
|
190
198
|
}
|
|
191
199
|
|
|
192
|
-
// Process documents
|
|
200
|
+
// Process documents – set loading early so skeleton shows for all entry points
|
|
193
201
|
if (documentFiles.length > 0) {
|
|
194
|
-
|
|
202
|
+
setIsDocumentLoading(true);
|
|
195
203
|
const documentInput = documentRef.current?.querySelector('input[type="file"]') as HTMLInputElement;
|
|
196
204
|
if (documentInput) {
|
|
197
205
|
const dataTransfer = new DataTransfer();
|
|
@@ -241,7 +249,6 @@ const UploadButton: React.FC<UploadManagerProps> = ({
|
|
|
241
249
|
const handlePaste = (e: ClipboardEvent) => {
|
|
242
250
|
const clipboardData = e.clipboardData;
|
|
243
251
|
if (!clipboardData) {
|
|
244
|
-
console.log('[UploadButton] handlePaste: No clipboardData available.');
|
|
245
252
|
return;
|
|
246
253
|
}
|
|
247
254
|
|
|
@@ -260,12 +267,9 @@ const UploadButton: React.FC<UploadManagerProps> = ({
|
|
|
260
267
|
// Only fall back to items if files is empty (some browsers only populate items)
|
|
261
268
|
if (clipboardData.files && clipboardData.files.length > 0) {
|
|
262
269
|
const clipboardFiles = Array.from(clipboardData.files);
|
|
263
|
-
console.log(`[UploadButton] handlePaste: clipboardData.files found`, clipboardFiles);
|
|
264
270
|
clipboardFiles.forEach(file => {
|
|
265
271
|
if (!isDuplicate(file)) {
|
|
266
272
|
files.push(file);
|
|
267
|
-
} else {
|
|
268
|
-
console.log(`[UploadButton] handlePaste: Duplicate file skipped from clipboardData.files:`, file);
|
|
269
273
|
}
|
|
270
274
|
});
|
|
271
275
|
} else {
|
|
@@ -278,10 +282,7 @@ const UploadButton: React.FC<UploadManagerProps> = ({
|
|
|
278
282
|
if (item.kind === 'file') {
|
|
279
283
|
const file = item.getAsFile();
|
|
280
284
|
if (file && !isDuplicate(file)) {
|
|
281
|
-
console.log(`[UploadButton] handlePaste: Adding file from items array:`, file);
|
|
282
285
|
files.push(file);
|
|
283
|
-
} else if (file) {
|
|
284
|
-
console.log(`[UploadButton] handlePaste: Duplicate file skipped from items array:`, file);
|
|
285
286
|
}
|
|
286
287
|
}
|
|
287
288
|
}
|
|
@@ -289,11 +290,8 @@ const UploadButton: React.FC<UploadManagerProps> = ({
|
|
|
289
290
|
}
|
|
290
291
|
|
|
291
292
|
if (files.length > 0) {
|
|
292
|
-
console.log(`[UploadButton] handlePaste: ${files.length} file(s) to process from paste`, files);
|
|
293
293
|
e.preventDefault();
|
|
294
294
|
handleUnifiedFileSelection(files);
|
|
295
|
-
} else {
|
|
296
|
-
console.log('[UploadButton] handlePaste: No files found in paste event.');
|
|
297
295
|
}
|
|
298
296
|
};
|
|
299
297
|
|
|
@@ -406,14 +404,8 @@ ${file.textAssetUrl || ''}
|
|
|
406
404
|
};
|
|
407
405
|
});
|
|
408
406
|
|
|
409
|
-
//
|
|
410
|
-
|
|
411
|
-
(file: any) => file.type === 'image'
|
|
412
|
-
);
|
|
413
|
-
|
|
414
|
-
setDocumentPreviewFiles([...processedDocuments, ...imageFiles]);
|
|
415
|
-
|
|
416
|
-
setIsLoading(false);
|
|
407
|
+
// Append new documents to existing files (images + previous documents)
|
|
408
|
+
setDocumentPreviewFiles((prev: any[]) => [...prev, ...processedDocuments]);
|
|
417
409
|
};
|
|
418
410
|
|
|
419
411
|
// Document validation and error handling
|
|
@@ -514,10 +506,24 @@ ${file.textAssetUrl || ''}
|
|
|
514
506
|
};
|
|
515
507
|
|
|
516
508
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
509
|
+
const handleDocumentLoadingChange = useCallback(
|
|
510
|
+
(loading: boolean, fileCount?: number) => {
|
|
511
|
+
setIsDocumentLoading(loading);
|
|
512
|
+
setDocUploadingCount(loading ? (fileCount ?? 1) : 0);
|
|
513
|
+
},
|
|
514
|
+
[]
|
|
515
|
+
);
|
|
516
|
+
const handleImageLoadingChange = useCallback(
|
|
517
|
+
(loading: boolean, fileCount?: number) => {
|
|
518
|
+
setIsImageLoading(loading);
|
|
519
|
+
setImgUploadingCount(loading ? (fileCount ?? 1) : 0);
|
|
520
|
+
},
|
|
521
|
+
[]
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
useEffect(() => {
|
|
525
|
+
onUploadLoadingChange?.(isLoading, isLoading ? uploadingFileCount : 0);
|
|
526
|
+
}, [isLoading, uploadingFileCount, onUploadLoadingChange]);
|
|
521
527
|
|
|
522
528
|
return (
|
|
523
529
|
<div
|
|
@@ -581,7 +587,7 @@ ${file.textAssetUrl || ''}
|
|
|
581
587
|
memoriID={memoriID}
|
|
582
588
|
maxDocuments={maxDocumentsPerMessage}
|
|
583
589
|
documentPreviewFiles={documentPreviewFiles}
|
|
584
|
-
onLoadingChange={
|
|
590
|
+
onLoadingChange={handleDocumentLoadingChange}
|
|
585
591
|
onDocumentError={handleDocumentError}
|
|
586
592
|
onValidateFile={validateDocumentFile}
|
|
587
593
|
onValidatePayloadSize={validatePayloadSize}
|
|
@@ -597,7 +603,7 @@ ${file.textAssetUrl || ''}
|
|
|
597
603
|
sessionID={sessionID}
|
|
598
604
|
documentPreviewFiles={documentPreviewFiles}
|
|
599
605
|
isMediaAccepted={isMediaAccepted}
|
|
600
|
-
onLoadingChange={
|
|
606
|
+
onLoadingChange={handleImageLoadingChange}
|
|
601
607
|
maxImages={maxDocumentsPerMessage}
|
|
602
608
|
memoriID={memoriID}
|
|
603
609
|
onImageError={handleImageError}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useRef
|
|
1
|
+
import React, { useState, useRef } from 'react';
|
|
2
2
|
import cx from 'classnames';
|
|
3
3
|
import Spin from '../../ui/Spin';
|
|
4
4
|
import { DocumentIcon } from '../../icons/Document';
|
|
@@ -49,7 +49,7 @@ interface UploadDocumentsProps {
|
|
|
49
49
|
memoriID?: string;
|
|
50
50
|
maxDocuments?: number;
|
|
51
51
|
documentPreviewFiles: any;
|
|
52
|
-
onLoadingChange?: (loading: boolean) => void;
|
|
52
|
+
onLoadingChange?: (loading: boolean, fileCount?: number) => void;
|
|
53
53
|
onDocumentError?: (error: {
|
|
54
54
|
message: string;
|
|
55
55
|
severity: 'error' | 'warning' | 'info';
|
|
@@ -93,12 +93,10 @@ const UploadDocuments: React.FC<UploadDocumentsProps> = ({
|
|
|
93
93
|
// Refs
|
|
94
94
|
const documentInputRef = useRef<HTMLInputElement>(null);
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
}, [isLoading, onLoadingChange]);
|
|
96
|
+
const setLoadingState = (loading: boolean, fileCount?: number) => {
|
|
97
|
+
setIsLoading(loading);
|
|
98
|
+
onLoadingChange?.(loading, fileCount);
|
|
99
|
+
};
|
|
102
100
|
|
|
103
101
|
// Document upload
|
|
104
102
|
const validateDocumentFile = (file: File): boolean => {
|
|
@@ -342,110 +340,113 @@ const UploadDocuments: React.FC<UploadDocumentsProps> = ({
|
|
|
342
340
|
return;
|
|
343
341
|
}
|
|
344
342
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
// Process each file
|
|
348
|
-
const processedFiles: {
|
|
349
|
-
name: string;
|
|
350
|
-
id: string;
|
|
351
|
-
content: string;
|
|
352
|
-
mimeType: string;
|
|
353
|
-
sourceUrl?: string;
|
|
354
|
-
textAssetUrl?: string;
|
|
355
|
-
}[] = [];
|
|
356
|
-
let hadTruncation = false;
|
|
357
|
-
|
|
358
|
-
for (const file of filesToProcess) {
|
|
359
|
-
if (!validateDocumentFile(file)) {
|
|
360
|
-
continue;
|
|
361
|
-
}
|
|
343
|
+
setLoadingState(true, filesToProcess.length);
|
|
362
344
|
|
|
363
|
-
|
|
345
|
+
try {
|
|
346
|
+
// Process each file
|
|
347
|
+
const processedFiles: {
|
|
348
|
+
name: string;
|
|
349
|
+
id: string;
|
|
350
|
+
content: string;
|
|
351
|
+
mimeType: string;
|
|
352
|
+
sourceUrl?: string;
|
|
353
|
+
textAssetUrl?: string;
|
|
354
|
+
}[] = [];
|
|
355
|
+
|
|
356
|
+
let activeCount = filesToProcess.length;
|
|
357
|
+
|
|
358
|
+
for (const file of filesToProcess) {
|
|
359
|
+
if (!validateDocumentFile(file)) {
|
|
360
|
+
activeCount--;
|
|
361
|
+
onLoadingChange?.(true, activeCount);
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
364
|
|
|
365
|
-
|
|
366
|
-
const { text } = await processDocumentFile(file);
|
|
365
|
+
const fileId = Math.random().toString(36).substr(2, 9);
|
|
367
366
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
// asset always contains the complete document content.
|
|
371
|
-
const baseName = file.name.replace(/\.[^/.]+$/, '') || file.name;
|
|
372
|
-
const textFile = new File([text], `${baseName}.txt`, {
|
|
373
|
-
type: 'text/plain',
|
|
374
|
-
});
|
|
367
|
+
try {
|
|
368
|
+
const { text } = await processDocumentFile(file);
|
|
375
369
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const sourceUrl =
|
|
382
|
-
uploadResults[0].status === 'fulfilled'
|
|
383
|
-
? uploadResults[0].value
|
|
384
|
-
: undefined;
|
|
385
|
-
const textAssetUrl =
|
|
386
|
-
uploadResults[1].status === 'fulfilled'
|
|
387
|
-
? uploadResults[1].value
|
|
388
|
-
: undefined;
|
|
389
|
-
|
|
390
|
-
// Keep the document even when one of the optional links fails to upload.
|
|
391
|
-
if (
|
|
392
|
-
uploadResults[0].status === 'rejected' ||
|
|
393
|
-
uploadResults[1].status === 'rejected'
|
|
394
|
-
) {
|
|
395
|
-
onDocumentError?.({
|
|
396
|
-
message: t('upload.partialAssetUploadWarning', {
|
|
397
|
-
fileName: file.name,
|
|
398
|
-
defaultValue:
|
|
399
|
-
'Some file links could not be uploaded, but the document was added anyway.',
|
|
400
|
-
}),
|
|
401
|
-
severity: 'warning',
|
|
370
|
+
if (text) {
|
|
371
|
+
const baseName = file.name.replace(/\.[^/.]+$/, '') || file.name;
|
|
372
|
+
const textFile = new File([text], `${baseName}.txt`, {
|
|
373
|
+
type: 'text/plain',
|
|
402
374
|
});
|
|
403
|
-
}
|
|
404
375
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
376
|
+
const uploadResults = await Promise.allSettled([
|
|
377
|
+
uploadAssetFile(file),
|
|
378
|
+
uploadAssetFile(textFile),
|
|
379
|
+
]);
|
|
380
|
+
|
|
381
|
+
const sourceUrl =
|
|
382
|
+
uploadResults[0].status === 'fulfilled'
|
|
383
|
+
? uploadResults[0].value
|
|
384
|
+
: undefined;
|
|
385
|
+
const textAssetUrl =
|
|
386
|
+
uploadResults[1].status === 'fulfilled'
|
|
387
|
+
? uploadResults[1].value
|
|
388
|
+
: undefined;
|
|
389
|
+
|
|
390
|
+
if (
|
|
391
|
+
uploadResults[0].status === 'rejected' ||
|
|
392
|
+
uploadResults[1].status === 'rejected'
|
|
393
|
+
) {
|
|
394
|
+
onDocumentError?.({
|
|
395
|
+
message: t('upload.partialAssetUploadWarning', {
|
|
396
|
+
fileName: file.name,
|
|
397
|
+
defaultValue:
|
|
398
|
+
'Some file links could not be uploaded, but the document was added anyway.',
|
|
399
|
+
}),
|
|
400
|
+
severity: 'warning',
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
let contentForMessage = text;
|
|
405
|
+
const perDocumentLimit = maxDocumentContentLength;
|
|
406
|
+
if (text.length > perDocumentLimit) {
|
|
407
|
+
contentForMessage =
|
|
408
|
+
text.substring(0, perDocumentLimit) +
|
|
409
|
+
'\n\n[Content truncated due to size limits]';
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
processedFiles.push({
|
|
413
|
+
name: file.name,
|
|
414
|
+
id: fileId,
|
|
415
|
+
content: contentForMessage,
|
|
416
|
+
mimeType: file.type,
|
|
417
|
+
sourceUrl,
|
|
418
|
+
textAssetUrl,
|
|
419
|
+
});
|
|
420
|
+
} else {
|
|
421
|
+
activeCount--;
|
|
422
|
+
onLoadingChange?.(true, activeCount);
|
|
415
423
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
+
} catch (error) {
|
|
425
|
+
activeCount--;
|
|
426
|
+
onLoadingChange?.(true, activeCount);
|
|
427
|
+
console.error('File processing error:', error);
|
|
428
|
+
onDocumentError?.({
|
|
429
|
+
message: `${
|
|
430
|
+
error instanceof Error ? error.message : 'Unknown error'
|
|
431
|
+
}`,
|
|
432
|
+
severity: 'warning',
|
|
424
433
|
});
|
|
425
434
|
}
|
|
426
|
-
} catch (error) {
|
|
427
|
-
console.error('File processing error:', error);
|
|
428
|
-
onDocumentError?.({
|
|
429
|
-
message: `${
|
|
430
|
-
error instanceof Error ? error.message : 'Unknown error'
|
|
431
|
-
}`,
|
|
432
|
-
severity: 'warning',
|
|
433
|
-
});
|
|
434
435
|
}
|
|
435
|
-
}
|
|
436
436
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
437
|
+
if (processedFiles.length > 0) {
|
|
438
|
+
setDocumentPreviewFiles(
|
|
439
|
+
processedFiles.map(file => ({
|
|
440
|
+
...file,
|
|
441
|
+
type: 'document',
|
|
442
|
+
}))
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
} finally {
|
|
446
|
+
setLoadingState(false);
|
|
447
|
+
if (documentInputRef.current) {
|
|
448
|
+
documentInputRef.current.value = '';
|
|
449
|
+
}
|
|
449
450
|
}
|
|
450
451
|
};
|
|
451
452
|
|
|
@@ -31,7 +31,7 @@ interface UploadImagesProps {
|
|
|
31
31
|
isMediaAccepted?: boolean;
|
|
32
32
|
setDocumentPreviewFiles: any;
|
|
33
33
|
documentPreviewFiles: any;
|
|
34
|
-
onLoadingChange?: (loading: boolean) => void;
|
|
34
|
+
onLoadingChange?: (loading: boolean, fileCount?: number) => void;
|
|
35
35
|
maxImages?: number;
|
|
36
36
|
memoriID?: string;
|
|
37
37
|
onImageError?: (error: { message: string; severity: 'error' | 'warning' | 'info' }) => void;
|
|
@@ -60,6 +60,7 @@ const UploadImages: React.FC<UploadImagesProps> = ({
|
|
|
60
60
|
|
|
61
61
|
// State
|
|
62
62
|
const [isLoading, setIsLoading] = useState(false);
|
|
63
|
+
const [loadingFileCount, setLoadingFileCount] = useState(0);
|
|
63
64
|
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
|
64
65
|
const [filePreview, setFilePreview] = useState<string | null>(null);
|
|
65
66
|
const [imageTitle, setImageTitle] = useState('');
|
|
@@ -68,12 +69,11 @@ const UploadImages: React.FC<UploadImagesProps> = ({
|
|
|
68
69
|
// Refs
|
|
69
70
|
const imageInputRef = useRef<HTMLInputElement>(null);
|
|
70
71
|
|
|
71
|
-
// Update loading state in parent component
|
|
72
72
|
useEffect(() => {
|
|
73
73
|
if (onLoadingChange) {
|
|
74
|
-
onLoadingChange(isLoading);
|
|
74
|
+
onLoadingChange(isLoading, isLoading ? loadingFileCount : 0);
|
|
75
75
|
}
|
|
76
|
-
}, [isLoading, onLoadingChange]);
|
|
76
|
+
}, [isLoading, loadingFileCount, onLoadingChange]);
|
|
77
77
|
|
|
78
78
|
// Check current total media count (images + documents)
|
|
79
79
|
const currentMediaCount = documentPreviewFiles.length;
|
|
@@ -151,6 +151,7 @@ const UploadImages: React.FC<UploadImagesProps> = ({
|
|
|
151
151
|
};
|
|
152
152
|
|
|
153
153
|
const uploadMultipleImages = async (files: File[]) => {
|
|
154
|
+
setLoadingFileCount(files.length);
|
|
154
155
|
setIsLoading(true);
|
|
155
156
|
|
|
156
157
|
try {
|
|
@@ -292,6 +293,7 @@ const UploadImages: React.FC<UploadImagesProps> = ({
|
|
|
292
293
|
const handleTitleSubmit = async () => {
|
|
293
294
|
if (!selectedFile || !imageTitle.trim()) return;
|
|
294
295
|
|
|
296
|
+
setLoadingFileCount(1);
|
|
295
297
|
setIsLoading(true);
|
|
296
298
|
setShowUploadModal(false);
|
|
297
299
|
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
|
-
export const version = '8.38.
|
|
2
|
+
export const version = '8.38.4';
|