import { useState, useCallback, useEffect, useRef } from 'react' import Button from '@/components/ui/Button' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from '@/components/ui/Dialog' import Input from '@/components/ui/Input' import Checkbox from '@/components/ui/Checkbox' import { toast } from 'sonner' import { errorMessage } from '@/lib/utils' import { clearDocuments, clearCache } from '@/api/lightrag' import { EraserIcon, AlertTriangleIcon, Loader2Icon } from 'lucide-react' import { useTranslation } from 'react-i18next' // Simple Label component const Label = ({ htmlFor, className, children, ...props }: React.LabelHTMLAttributes) => ( ) interface ClearDocumentsDialogProps { onDocumentsCleared?: () => Promise } export default function ClearDocumentsDialog({ onDocumentsCleared }: ClearDocumentsDialogProps) { const { t } = useTranslation() const [open, setOpen] = useState(false) const [confirmText, setConfirmText] = useState('') const [clearCacheOption, setClearCacheOption] = useState(false) const [isClearing, setIsClearing] = useState(false) const timeoutRef = useRef | null>(null) const isConfirmEnabled = confirmText.toLowerCase() === 'yes' // Timeout constant (30 seconds) const CLEAR_TIMEOUT = 30000 // Reset state when dialog closes useEffect(() => { if (!open) { setConfirmText('') setClearCacheOption(false) setIsClearing(false) // Clear timeout timer if (timeoutRef.current) { clearTimeout(timeoutRef.current) timeoutRef.current = null } } }, [open]) // Cleanup when component unmounts useEffect(() => { return () => { // Clear timeout timer when component unmounts if (timeoutRef.current) { clearTimeout(timeoutRef.current) } } }, []) const handleClear = useCallback(async () => { if (!isConfirmEnabled || isClearing) return setIsClearing(true) // Set timeout protection timeoutRef.current = setTimeout(() => { if (isClearing) { toast.error(t('documentPanel.clearDocuments.timeout')) setIsClearing(false) setConfirmText('') // Reset confirmation text after timeout } }, CLEAR_TIMEOUT) try { const result = await clearDocuments() if (result.status !== 'success') { toast.error(t('documentPanel.clearDocuments.failed', { message: result.message })) setConfirmText('') return } toast.success(t('documentPanel.clearDocuments.success')) if (clearCacheOption) { try { await clearCache() toast.success(t('documentPanel.clearDocuments.cacheCleared')) } catch (cacheErr) { toast.error(t('documentPanel.clearDocuments.cacheClearFailed', { error: errorMessage(cacheErr) })) } } // Refresh document list if provided if (onDocumentsCleared) { onDocumentsCleared().catch(console.error) } // Close dialog after all operations succeed setOpen(false) } catch (err) { toast.error(t('documentPanel.clearDocuments.error', { error: errorMessage(err) })) setConfirmText('') } finally { // Clear timeout timer if (timeoutRef.current) { clearTimeout(timeoutRef.current) timeoutRef.current = null } setIsClearing(false) } }, [isConfirmEnabled, isClearing, clearCacheOption, setOpen, t, onDocumentsCleared, CLEAR_TIMEOUT]) return ( e.preventDefault()}> {t('documentPanel.clearDocuments.title')} {t('documentPanel.clearDocuments.description')}
{t('documentPanel.clearDocuments.warning')}
{t('documentPanel.clearDocuments.confirm')}
) => setConfirmText(e.target.value)} placeholder={t('documentPanel.clearDocuments.confirmPlaceholder')} className="w-full" disabled={isClearing} />
setClearCacheOption(checked === true)} disabled={isClearing} />
) }