import { useState, useEffect, useRef } from 'react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' import { AlignLeft, AlignCenter, AlignRight } from 'lucide-react' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/Dialog' import Button from '@/components/ui/Button' import { getPipelineStatus, cancelPipeline, PipelineStatusResponse } from '@/api/lightrag' import { errorMessage } from '@/lib/utils' import { cn } from '@/lib/utils' type DialogPosition = 'left' | 'center' | 'right' interface PipelineStatusDialogProps { open: boolean onOpenChange: (open: boolean) => void } export default function PipelineStatusDialog({ open, onOpenChange }: PipelineStatusDialogProps) { const { t } = useTranslation() const [status, setStatus] = useState(null) const [position, setPosition] = useState('center') const [isUserScrolled, setIsUserScrolled] = useState(false) const [showCancelConfirm, setShowCancelConfirm] = useState(false) const historyRef = useRef(null) // Reset position when dialog opens useEffect(() => { if (open) { setPosition('center') setIsUserScrolled(false) } else { // Reset confirmation dialog state when main dialog closes setShowCancelConfirm(false) } }, [open]) // Handle scroll position useEffect(() => { const container = historyRef.current if (!container || isUserScrolled) return container.scrollTop = container.scrollHeight }, [status?.history_messages, isUserScrolled]) const handleScroll = () => { const container = historyRef.current if (!container) return const isAtBottom = Math.abs( (container.scrollHeight - container.scrollTop) - container.clientHeight ) < 1 if (isAtBottom) { setIsUserScrolled(false) } else { setIsUserScrolled(true) } } // Refresh status every 2 seconds useEffect(() => { if (!open) return const fetchStatus = async () => { try { const data = await getPipelineStatus() setStatus(data) } catch (err) { toast.error(t('documentPanel.pipelineStatus.errors.fetchFailed', { error: errorMessage(err) })) } } fetchStatus() const interval = setInterval(fetchStatus, 2000) return () => clearInterval(interval) }, [open, t]) // Handle cancel pipeline confirmation const handleConfirmCancel = async () => { setShowCancelConfirm(false) try { const result = await cancelPipeline() if (result.status === 'cancellation_requested') { toast.success(t('documentPanel.pipelineStatus.cancelSuccess')) } else if (result.status === 'not_busy') { toast.info(t('documentPanel.pipelineStatus.cancelNotBusy')) } } catch (err) { toast.error(t('documentPanel.pipelineStatus.cancelFailed', { error: errorMessage(err) })) } } // Determine if cancel button should be enabled const canCancel = status?.busy === true && !status?.cancellation_requested return ( {status?.job_name ? `${t('documentPanel.pipelineStatus.jobName')}: ${status.job_name}, ${t('documentPanel.pipelineStatus.progress')}: ${status.cur_batch}/${status.batchs}` : t('documentPanel.pipelineStatus.noActiveJob') } {t('documentPanel.pipelineStatus.title')} {/* Position control buttons */}
{/* Status Content */}
{/* Pipeline Status - with cancel button */}
{/* Left side: Status indicators */}
{t('documentPanel.pipelineStatus.busy')}:
{t('documentPanel.pipelineStatus.requestPending')}:
{/* Only show cancellation status when it's requested */} {status?.cancellation_requested && (
{t('documentPanel.pipelineStatus.cancellationRequested')}:
)}
{/* Right side: Cancel button - only show when pipeline is busy */} {status?.busy && ( )}
{/* Job Information */}
{t('documentPanel.pipelineStatus.jobName')}: {status?.job_name || '-'}
{t('documentPanel.pipelineStatus.startTime')}: {status?.job_start ? new Date(status.job_start).toLocaleString(undefined, { year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' }) : '-'} {t('documentPanel.pipelineStatus.progress')}: {status ? `${status.cur_batch}/${status.batchs} ${t('documentPanel.pipelineStatus.unit')}` : '-'}
{/* History Messages */}
{t('documentPanel.pipelineStatus.pipelineMessages')}:
{status?.history_messages?.length ? ( status.history_messages.map((msg, idx) => (
{msg}
)) ) : '-'}
{/* Cancel Confirmation Dialog */} {t('documentPanel.pipelineStatus.cancelConfirmTitle')} {t('documentPanel.pipelineStatus.cancelConfirmDescription')}
) }