Merge pull request #1292 from danielaskdd/fix-promise-warning
Browse filesFix promise warning and add null checks in FileUploader to prevent split() on undefined
lightrag/api/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1 |
-
__api_version__ = "
|
|
|
1 |
+
__api_version__ = "0139"
|
lightrag/api/webui/assets/{index-Bz5MOBb9.js → index-sivPufd7.js}
RENAMED
Binary files a/lightrag/api/webui/assets/index-Bz5MOBb9.js and b/lightrag/api/webui/assets/index-sivPufd7.js differ
|
|
lightrag/api/webui/index.html
CHANGED
Binary files a/lightrag/api/webui/index.html and b/lightrag/api/webui/index.html differ
|
|
lightrag_webui/src/App.tsx
CHANGED
@@ -33,6 +33,26 @@ function App() {
|
|
33 |
}
|
34 |
}, [])
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
// Health check - can be disabled
|
37 |
useEffect(() => {
|
38 |
// Only execute if health check is enabled and ApiKeyAlert is closed
|
@@ -40,7 +60,14 @@ function App() {
|
|
40 |
|
41 |
// Health check function
|
42 |
const performHealthCheck = async () => {
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
};
|
45 |
|
46 |
// Set interval for periodic execution
|
|
|
33 |
}
|
34 |
}, [])
|
35 |
|
36 |
+
// Track component mount status with useRef
|
37 |
+
const isMountedRef = useRef(true);
|
38 |
+
|
39 |
+
// Set up mount/unmount status tracking
|
40 |
+
useEffect(() => {
|
41 |
+
isMountedRef.current = true;
|
42 |
+
|
43 |
+
// Handle page reload/unload
|
44 |
+
const handleBeforeUnload = () => {
|
45 |
+
isMountedRef.current = false;
|
46 |
+
};
|
47 |
+
|
48 |
+
window.addEventListener('beforeunload', handleBeforeUnload);
|
49 |
+
|
50 |
+
return () => {
|
51 |
+
isMountedRef.current = false;
|
52 |
+
window.removeEventListener('beforeunload', handleBeforeUnload);
|
53 |
+
};
|
54 |
+
}, []);
|
55 |
+
|
56 |
// Health check - can be disabled
|
57 |
useEffect(() => {
|
58 |
// Only execute if health check is enabled and ApiKeyAlert is closed
|
|
|
60 |
|
61 |
// Health check function
|
62 |
const performHealthCheck = async () => {
|
63 |
+
try {
|
64 |
+
// Only perform health check if component is still mounted
|
65 |
+
if (isMountedRef.current) {
|
66 |
+
await useBackendState.getState().check();
|
67 |
+
}
|
68 |
+
} catch (error) {
|
69 |
+
console.error('Health check error:', error);
|
70 |
+
}
|
71 |
};
|
72 |
|
73 |
// Set interval for periodic execution
|
lightrag_webui/src/components/ui/FileUploader.tsx
CHANGED
@@ -206,10 +206,15 @@ function FileUploader(props: FileUploaderProps) {
|
|
206 |
if (onUpload && acceptedFiles.length > 0) {
|
207 |
// Filter out any files that might have been rejected by our custom validator
|
208 |
const validFiles = acceptedFiles.filter(file => {
|
|
|
|
|
|
|
|
|
|
|
209 |
// Check if file type is accepted
|
210 |
const fileExt = `.${file.name.split('.').pop()?.toLowerCase() || ''}`;
|
211 |
const isAccepted = Object.entries(accept || {}).some(([mimeType, extensions]) => {
|
212 |
-
return file.type === mimeType || extensions.includes(fileExt);
|
213 |
});
|
214 |
|
215 |
// Check file size
|
@@ -260,10 +265,22 @@ function FileUploader(props: FileUploaderProps) {
|
|
260 |
multiple={maxFileCount > 1 || multiple}
|
261 |
disabled={isDisabled}
|
262 |
validator={(file) => {
|
263 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
264 |
const fileExt = `.${file.name.split('.').pop()?.toLowerCase() || ''}`;
|
|
|
|
|
265 |
const isAccepted = Object.entries(accept || {}).some(([mimeType, extensions]) => {
|
266 |
-
|
|
|
267 |
});
|
268 |
|
269 |
if (!isAccepted) {
|
|
|
206 |
if (onUpload && acceptedFiles.length > 0) {
|
207 |
// Filter out any files that might have been rejected by our custom validator
|
208 |
const validFiles = acceptedFiles.filter(file => {
|
209 |
+
// Skip files without a name
|
210 |
+
if (!file.name) {
|
211 |
+
return false;
|
212 |
+
}
|
213 |
+
|
214 |
// Check if file type is accepted
|
215 |
const fileExt = `.${file.name.split('.').pop()?.toLowerCase() || ''}`;
|
216 |
const isAccepted = Object.entries(accept || {}).some(([mimeType, extensions]) => {
|
217 |
+
return file.type === mimeType || (Array.isArray(extensions) && extensions.includes(fileExt));
|
218 |
});
|
219 |
|
220 |
// Check file size
|
|
|
265 |
multiple={maxFileCount > 1 || multiple}
|
266 |
disabled={isDisabled}
|
267 |
validator={(file) => {
|
268 |
+
// Ensure file name exists
|
269 |
+
if (!file.name) {
|
270 |
+
return {
|
271 |
+
code: 'invalid-file-name',
|
272 |
+
message: t('documentPanel.uploadDocuments.fileUploader.invalidFileName',
|
273 |
+
{ fallback: 'Invalid file name' })
|
274 |
+
};
|
275 |
+
}
|
276 |
+
|
277 |
+
// Safely extract file extension
|
278 |
const fileExt = `.${file.name.split('.').pop()?.toLowerCase() || ''}`;
|
279 |
+
|
280 |
+
// Ensure accept object exists and has correct format
|
281 |
const isAccepted = Object.entries(accept || {}).some(([mimeType, extensions]) => {
|
282 |
+
// Ensure extensions is an array before calling includes
|
283 |
+
return file.type === mimeType || (Array.isArray(extensions) && extensions.includes(fileExt));
|
284 |
});
|
285 |
|
286 |
if (!isAccepted) {
|
lightrag_webui/src/features/DocumentManager.tsx
CHANGED
@@ -137,6 +137,26 @@ type SortField = 'created_at' | 'updated_at' | 'id';
|
|
137 |
type SortDirection = 'asc' | 'desc';
|
138 |
|
139 |
export default function DocumentManager() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
const [showPipelineStatus, setShowPipelineStatus] = useState(false)
|
141 |
const { t } = useTranslation()
|
142 |
const health = useBackendState.use.health()
|
@@ -324,7 +344,13 @@ export default function DocumentManager() {
|
|
324 |
|
325 |
const fetchDocuments = useCallback(async () => {
|
326 |
try {
|
327 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
|
329 |
// Get new status counts (treat null as all zeros)
|
330 |
const newStatusCounts = {
|
@@ -339,30 +365,36 @@ export default function DocumentManager() {
|
|
339 |
status => newStatusCounts[status] !== prevStatusCounts.current[status]
|
340 |
)
|
341 |
|
342 |
-
// Trigger health check if changes detected
|
343 |
-
if (hasStatusCountChange) {
|
344 |
useBackendState.getState().check()
|
345 |
}
|
346 |
|
347 |
-
//
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
|
|
|
|
|
|
|
|
|
|
358 |
} else {
|
359 |
setDocs(null)
|
360 |
}
|
361 |
-
} else {
|
362 |
-
setDocs(null)
|
363 |
}
|
364 |
} catch (err) {
|
365 |
-
|
|
|
|
|
|
|
366 |
}
|
367 |
}, [setDocs, t])
|
368 |
|
@@ -375,10 +407,20 @@ export default function DocumentManager() {
|
|
375 |
|
376 |
const scanDocuments = useCallback(async () => {
|
377 |
try {
|
378 |
-
|
379 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
380 |
} catch (err) {
|
381 |
-
|
|
|
|
|
|
|
382 |
}
|
383 |
}, [t])
|
384 |
|
@@ -390,13 +432,21 @@ export default function DocumentManager() {
|
|
390 |
|
391 |
const interval = setInterval(async () => {
|
392 |
try {
|
393 |
-
|
|
|
|
|
|
|
394 |
} catch (err) {
|
395 |
-
|
|
|
|
|
|
|
396 |
}
|
397 |
}, 5000)
|
398 |
|
399 |
-
return () =>
|
|
|
|
|
400 |
}, [health, fetchDocuments, t, currentTab])
|
401 |
|
402 |
// Add dependency on sort state to re-render when sort changes
|
|
|
137 |
type SortDirection = 'asc' | 'desc';
|
138 |
|
139 |
export default function DocumentManager() {
|
140 |
+
// Track component mount status
|
141 |
+
const isMountedRef = useRef(true);
|
142 |
+
|
143 |
+
// Set up mount/unmount status tracking
|
144 |
+
useEffect(() => {
|
145 |
+
isMountedRef.current = true;
|
146 |
+
|
147 |
+
// Handle page reload/unload
|
148 |
+
const handleBeforeUnload = () => {
|
149 |
+
isMountedRef.current = false;
|
150 |
+
};
|
151 |
+
|
152 |
+
window.addEventListener('beforeunload', handleBeforeUnload);
|
153 |
+
|
154 |
+
return () => {
|
155 |
+
isMountedRef.current = false;
|
156 |
+
window.removeEventListener('beforeunload', handleBeforeUnload);
|
157 |
+
};
|
158 |
+
}, []);
|
159 |
+
|
160 |
const [showPipelineStatus, setShowPipelineStatus] = useState(false)
|
161 |
const { t } = useTranslation()
|
162 |
const health = useBackendState.use.health()
|
|
|
344 |
|
345 |
const fetchDocuments = useCallback(async () => {
|
346 |
try {
|
347 |
+
// Check if component is still mounted before starting the request
|
348 |
+
if (!isMountedRef.current) return;
|
349 |
+
|
350 |
+
const docs = await getDocuments();
|
351 |
+
|
352 |
+
// Check again if component is still mounted after the request completes
|
353 |
+
if (!isMountedRef.current) return;
|
354 |
|
355 |
// Get new status counts (treat null as all zeros)
|
356 |
const newStatusCounts = {
|
|
|
365 |
status => newStatusCounts[status] !== prevStatusCounts.current[status]
|
366 |
)
|
367 |
|
368 |
+
// Trigger health check if changes detected and component is still mounted
|
369 |
+
if (hasStatusCountChange && isMountedRef.current) {
|
370 |
useBackendState.getState().check()
|
371 |
}
|
372 |
|
373 |
+
// Only update state if component is still mounted
|
374 |
+
if (isMountedRef.current) {
|
375 |
+
// Update previous status counts
|
376 |
+
prevStatusCounts.current = newStatusCounts
|
377 |
+
|
378 |
+
// Update docs state
|
379 |
+
if (docs && docs.statuses) {
|
380 |
+
const numDocuments = Object.values(docs.statuses).reduce(
|
381 |
+
(acc, status) => acc + status.length,
|
382 |
+
0
|
383 |
+
)
|
384 |
+
if (numDocuments > 0) {
|
385 |
+
setDocs(docs)
|
386 |
+
} else {
|
387 |
+
setDocs(null)
|
388 |
+
}
|
389 |
} else {
|
390 |
setDocs(null)
|
391 |
}
|
|
|
|
|
392 |
}
|
393 |
} catch (err) {
|
394 |
+
// Only show error if component is still mounted
|
395 |
+
if (isMountedRef.current) {
|
396 |
+
toast.error(t('documentPanel.documentManager.errors.loadFailed', { error: errorMessage(err) }))
|
397 |
+
}
|
398 |
}
|
399 |
}, [setDocs, t])
|
400 |
|
|
|
407 |
|
408 |
const scanDocuments = useCallback(async () => {
|
409 |
try {
|
410 |
+
// Check if component is still mounted before starting the request
|
411 |
+
if (!isMountedRef.current) return;
|
412 |
+
|
413 |
+
const { status } = await scanNewDocuments();
|
414 |
+
|
415 |
+
// Check again if component is still mounted after the request completes
|
416 |
+
if (!isMountedRef.current) return;
|
417 |
+
|
418 |
+
toast.message(status);
|
419 |
} catch (err) {
|
420 |
+
// Only show error if component is still mounted
|
421 |
+
if (isMountedRef.current) {
|
422 |
+
toast.error(t('documentPanel.documentManager.errors.scanFailed', { error: errorMessage(err) }));
|
423 |
+
}
|
424 |
}
|
425 |
}, [t])
|
426 |
|
|
|
432 |
|
433 |
const interval = setInterval(async () => {
|
434 |
try {
|
435 |
+
// Only perform fetch if component is still mounted
|
436 |
+
if (isMountedRef.current) {
|
437 |
+
await fetchDocuments()
|
438 |
+
}
|
439 |
} catch (err) {
|
440 |
+
// Only show error if component is still mounted
|
441 |
+
if (isMountedRef.current) {
|
442 |
+
toast.error(t('documentPanel.documentManager.errors.scanProgressFailed', { error: errorMessage(err) }))
|
443 |
+
}
|
444 |
}
|
445 |
}, 5000)
|
446 |
|
447 |
+
return () => {
|
448 |
+
clearInterval(interval)
|
449 |
+
}
|
450 |
}, [health, fetchDocuments, t, currentTab])
|
451 |
|
452 |
// Add dependency on sort state to re-render when sort changes
|