fix(ui): improve pipeline status dialog layout and styling
- Switch from AlertDialog to Dialog component for better modal behavior - Adjust dialog positioning and alignment controls - Remove custom close button to avoid duplication - Add proper spacing between alignment buttons and close button - Simplify history container height with min/max height - Reduce overlay opacity for better visibility
This commit is contained in:
@@ -1,16 +1,15 @@
|
|||||||
import { useState, useEffect, useRef, useCallback } from 'react'
|
import { useState, useEffect, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
import { X, AlignLeft, AlignCenter, AlignRight } from 'lucide-react'
|
import { AlignLeft, AlignCenter, AlignRight } from 'lucide-react'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
Dialog,
|
||||||
AlertDialogContent,
|
DialogContent,
|
||||||
AlertDialogHeader,
|
DialogHeader,
|
||||||
AlertDialogTitle,
|
DialogTitle,
|
||||||
AlertDialogDescription,
|
DialogDescription
|
||||||
AlertDialogOverlay,
|
} from '@/components/ui/Dialog'
|
||||||
} from '@/components/ui/AlertDialog'
|
|
||||||
import Button from '@/components/ui/Button'
|
import Button from '@/components/ui/Button'
|
||||||
import { getPipelineStatus, PipelineStatusResponse } from '@/api/lightrag'
|
import { getPipelineStatus, PipelineStatusResponse } from '@/api/lightrag'
|
||||||
import { errorMessage } from '@/lib/utils'
|
import { errorMessage } from '@/lib/utils'
|
||||||
@@ -31,44 +30,15 @@ export default function PipelineStatusDialog({
|
|||||||
const [status, setStatus] = useState<PipelineStatusResponse | null>(null)
|
const [status, setStatus] = useState<PipelineStatusResponse | null>(null)
|
||||||
const [position, setPosition] = useState<DialogPosition>('center')
|
const [position, setPosition] = useState<DialogPosition>('center')
|
||||||
const [isUserScrolled, setIsUserScrolled] = useState(false)
|
const [isUserScrolled, setIsUserScrolled] = useState(false)
|
||||||
const [historyHeight, setHistoryHeight] = useState('20em')
|
|
||||||
const historyRef = useRef<HTMLDivElement>(null)
|
const historyRef = useRef<HTMLDivElement>(null)
|
||||||
const resizeObserverRef = useRef<ResizeObserver | null>(null)
|
|
||||||
|
|
||||||
// Calculate history height based on window height
|
|
||||||
const updateHistoryHeight = useCallback(() => {
|
|
||||||
const minHeight = 7.5 // 5 lines * 1.5em line height
|
|
||||||
const windowHeight = window.innerHeight
|
|
||||||
const pixelsPerEm = parseFloat(getComputedStyle(document.documentElement).fontSize)
|
|
||||||
const maxHeightInEm = Math.max(Math.floor((windowHeight * 0.4) / pixelsPerEm), minHeight)
|
|
||||||
setHistoryHeight(`${maxHeightInEm}em`)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
// Reset position when dialog opens
|
// Reset position when dialog opens
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
setPosition('center')
|
setPosition('center')
|
||||||
setIsUserScrolled(false)
|
setIsUserScrolled(false)
|
||||||
updateHistoryHeight()
|
|
||||||
}
|
}
|
||||||
}, [open, updateHistoryHeight])
|
}, [open])
|
||||||
|
|
||||||
// Setup resize observer
|
|
||||||
useEffect(() => {
|
|
||||||
if (!open) return
|
|
||||||
|
|
||||||
resizeObserverRef.current = new ResizeObserver((entries) => {
|
|
||||||
if (entries[0]) {
|
|
||||||
updateHistoryHeight()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
resizeObserverRef.current.observe(document.body)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
resizeObserverRef.current?.disconnect()
|
|
||||||
}
|
|
||||||
}, [open, updateHistoryHeight])
|
|
||||||
|
|
||||||
// Handle scroll position
|
// Handle scroll position
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -112,74 +82,63 @@ export default function PipelineStatusDialog({
|
|||||||
}, [open, t])
|
}, [open, t])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<AlertDialogOverlay className="bg-black/30" />
|
<DialogContent
|
||||||
<AlertDialogContent
|
|
||||||
className={cn(
|
className={cn(
|
||||||
'sm:max-w-[600px] transition-all duration-200',
|
'sm:max-w-[600px] transition-all duration-200 fixed',
|
||||||
position === 'left' && '!left-4 !translate-x-0',
|
position === 'left' && '!left-[25%] !translate-x-[-50%] !mx-4',
|
||||||
position === 'center' && '!left-1/2 !-translate-x-1/2',
|
position === 'center' && '!left-1/2 !-translate-x-1/2',
|
||||||
position === 'right' && '!right-4 !left-auto !translate-x-0'
|
position === 'right' && '!left-[75%] !translate-x-[-50%] !mx-4'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<AlertDialogDescription className="sr-only">
|
<DialogDescription className="sr-only">
|
||||||
{status?.job_name
|
{status?.job_name
|
||||||
? `${t('documentPanel.pipelineStatus.jobName')}: ${status.job_name}, ${t('documentPanel.pipelineStatus.progress')}: ${status.cur_batch}/${status.batchs}`
|
? `${t('documentPanel.pipelineStatus.jobName')}: ${status.job_name}, ${t('documentPanel.pipelineStatus.progress')}: ${status.cur_batch}/${status.batchs}`
|
||||||
: t('documentPanel.pipelineStatus.noActiveJob')
|
: t('documentPanel.pipelineStatus.noActiveJob')
|
||||||
}
|
}
|
||||||
</AlertDialogDescription>
|
</DialogDescription>
|
||||||
<AlertDialogHeader className="flex flex-row items-center justify-between">
|
<DialogHeader className="flex flex-row items-center">
|
||||||
<AlertDialogTitle>
|
<DialogTitle className="flex-1">
|
||||||
{t('documentPanel.pipelineStatus.title')}
|
{t('documentPanel.pipelineStatus.title')}
|
||||||
</AlertDialogTitle>
|
</DialogTitle>
|
||||||
|
|
||||||
{/* Position control buttons and close button */}
|
{/* Position control buttons */}
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2 mr-8">
|
||||||
<div className="flex items-center gap-1">
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
className={cn(
|
|
||||||
'h-6 w-6',
|
|
||||||
position === 'left' && 'bg-zinc-200 text-zinc-800 hover:bg-zinc-300 dark:bg-zinc-700 dark:text-zinc-200 dark:hover:bg-zinc-600'
|
|
||||||
)}
|
|
||||||
onClick={() => setPosition('left')}
|
|
||||||
>
|
|
||||||
<AlignLeft className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
className={cn(
|
|
||||||
'h-6 w-6',
|
|
||||||
position === 'center' && 'bg-zinc-200 text-zinc-800 hover:bg-zinc-300 dark:bg-zinc-700 dark:text-zinc-200 dark:hover:bg-zinc-600'
|
|
||||||
)}
|
|
||||||
onClick={() => setPosition('center')}
|
|
||||||
>
|
|
||||||
<AlignCenter className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
className={cn(
|
|
||||||
'h-6 w-6',
|
|
||||||
position === 'right' && 'bg-zinc-200 text-zinc-800 hover:bg-zinc-300 dark:bg-zinc-700 dark:text-zinc-200 dark:hover:bg-zinc-600'
|
|
||||||
)}
|
|
||||||
onClick={() => setPosition('right')}
|
|
||||||
>
|
|
||||||
<AlignRight className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="h-6 w-6"
|
className={cn(
|
||||||
onClick={() => onOpenChange(false)}
|
'h-6 w-6',
|
||||||
|
position === 'left' && 'bg-zinc-200 text-zinc-800 hover:bg-zinc-300 dark:bg-zinc-700 dark:text-zinc-200 dark:hover:bg-zinc-600'
|
||||||
|
)}
|
||||||
|
onClick={() => setPosition('left')}
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<AlignLeft className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className={cn(
|
||||||
|
'h-6 w-6',
|
||||||
|
position === 'center' && 'bg-zinc-200 text-zinc-800 hover:bg-zinc-300 dark:bg-zinc-700 dark:text-zinc-200 dark:hover:bg-zinc-600'
|
||||||
|
)}
|
||||||
|
onClick={() => setPosition('center')}
|
||||||
|
>
|
||||||
|
<AlignCenter className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className={cn(
|
||||||
|
'h-6 w-6',
|
||||||
|
position === 'right' && 'bg-zinc-200 text-zinc-800 hover:bg-zinc-300 dark:bg-zinc-700 dark:text-zinc-200 dark:hover:bg-zinc-600'
|
||||||
|
)}
|
||||||
|
onClick={() => setPosition('right')}
|
||||||
|
>
|
||||||
|
<AlignRight className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</AlertDialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
{/* Status Content */}
|
{/* Status Content */}
|
||||||
<div className="space-y-4 pt-4">
|
<div className="space-y-4 pt-4">
|
||||||
@@ -218,8 +177,7 @@ export default function PipelineStatusDialog({
|
|||||||
<div
|
<div
|
||||||
ref={historyRef}
|
ref={historyRef}
|
||||||
onScroll={handleScroll}
|
onScroll={handleScroll}
|
||||||
className="font-mono text-sm rounded-md bg-zinc-800 text-zinc-100 p-3 overflow-y-auto"
|
className="font-mono text-sm rounded-md bg-zinc-800 text-zinc-100 p-3 overflow-y-auto min-h-[7.5em] max-h-[40vh]"
|
||||||
style={{ height: historyHeight }}
|
|
||||||
>
|
>
|
||||||
{status?.history_messages?.map((msg, idx) => (
|
{status?.history_messages?.map((msg, idx) => (
|
||||||
<div key={idx}>{msg}</div>
|
<div key={idx}>{msg}</div>
|
||||||
@@ -227,7 +185,7 @@ export default function PipelineStatusDialog({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AlertDialogContent>
|
</DialogContent>
|
||||||
</AlertDialog>
|
</Dialog>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,7 @@ const DialogOverlay = React.forwardRef<
|
|||||||
<DialogPrimitive.Overlay
|
<DialogPrimitive.Overlay
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
|
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/30',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
Reference in New Issue
Block a user