Merge pull request #1198 from danielaskdd/main
Improve document TAB layout and tooltips handling logic
This commit is contained in:
1
lightrag/api/webui/assets/index-CP4Boz-Y.css
generated
Normal file
1
lightrag/api/webui/assets/index-CP4Boz-Y.css
generated
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
lightrag/api/webui/assets/index-CbzkrOyx.css
generated
1
lightrag/api/webui/assets/index-CbzkrOyx.css
generated
File diff suppressed because one or more lines are too long
4
lightrag/api/webui/index.html
generated
4
lightrag/api/webui/index.html
generated
@@ -8,8 +8,8 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="logo.png" />
|
<link rel="icon" type="image/svg+xml" href="logo.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Lightrag</title>
|
<title>Lightrag</title>
|
||||||
<script type="module" crossorigin src="/webui/assets/index-DTDDxtXc.js"></script>
|
<script type="module" crossorigin src="/webui/assets/index-CZkfsko8.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/webui/assets/index-CbzkrOyx.css">
|
<link rel="stylesheet" crossorigin href="/webui/assets/index-CP4Boz-Y.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@@ -47,6 +47,18 @@ const getDisplayFileName = (doc: DocStatusResponse, maxLength: number = 20): str
|
|||||||
};
|
};
|
||||||
|
|
||||||
const pulseStyle = `
|
const pulseStyle = `
|
||||||
|
/* Fixed tooltip styles for small tables */
|
||||||
|
.tooltip-fixed {
|
||||||
|
position: fixed !important;
|
||||||
|
z-index: 9999 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parent container for tooltips */
|
||||||
|
.tooltip-container {
|
||||||
|
position: relative;
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
0% {
|
0% {
|
||||||
background-color: rgb(255 0 0 / 0.1);
|
background-color: rgb(255 0 0 / 0.1);
|
||||||
@@ -115,6 +127,70 @@ export default function DocumentManager() {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Reference to the card content element
|
||||||
|
const cardContentRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// Add tooltip position adjustment based on mouse position
|
||||||
|
useEffect(() => {
|
||||||
|
if (!docs) return;
|
||||||
|
|
||||||
|
// Function to handle mouse movement - throttled to reduce layout calculations
|
||||||
|
let lastExecution = 0;
|
||||||
|
const throttleInterval = 50; // ms
|
||||||
|
|
||||||
|
const handleMouseMove = () => {
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - lastExecution < throttleInterval) return;
|
||||||
|
lastExecution = now;
|
||||||
|
|
||||||
|
const cardContent = cardContentRef.current;
|
||||||
|
if (!cardContent) return;
|
||||||
|
|
||||||
|
// Get all visible tooltips
|
||||||
|
const visibleTooltips = document.querySelectorAll<HTMLElement>('.group:hover > div[class*="invisible group-hover:visible absolute"]');
|
||||||
|
if (visibleTooltips.length === 0) return;
|
||||||
|
|
||||||
|
visibleTooltips.forEach(tooltip => {
|
||||||
|
// Get the parent element that triggered the tooltip
|
||||||
|
const triggerElement = tooltip.parentElement;
|
||||||
|
if (!triggerElement) return;
|
||||||
|
|
||||||
|
const triggerRect = triggerElement.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Use fixed positioning for all tooltips
|
||||||
|
tooltip.classList.add('tooltip-fixed');
|
||||||
|
|
||||||
|
// Calculate position based on trigger element
|
||||||
|
const tooltipHeight = tooltip.offsetHeight;
|
||||||
|
const viewportHeight = window.innerHeight;
|
||||||
|
|
||||||
|
// Check if tooltip would go off the bottom of the viewport
|
||||||
|
const wouldOverflowBottom = triggerRect.bottom + tooltipHeight + 5 > viewportHeight;
|
||||||
|
|
||||||
|
if (wouldOverflowBottom) {
|
||||||
|
// Position above the trigger
|
||||||
|
tooltip.style.top = `${triggerRect.top - tooltipHeight - 5}px`;
|
||||||
|
tooltip.style.bottom = 'auto';
|
||||||
|
} else {
|
||||||
|
// Position below the trigger
|
||||||
|
tooltip.style.top = `${triggerRect.bottom + 5}px`;
|
||||||
|
tooltip.style.bottom = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal positioning
|
||||||
|
tooltip.style.left = `${triggerRect.left}px`;
|
||||||
|
tooltip.style.maxWidth = '600px';
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add mouse move listener to the document
|
||||||
|
document.addEventListener('mousemove', handleMouseMove);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('mousemove', handleMouseMove);
|
||||||
|
};
|
||||||
|
}, [docs]);
|
||||||
|
|
||||||
const fetchDocuments = useCallback(async () => {
|
const fetchDocuments = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const docs = await getDocuments()
|
const docs = await getDocuments()
|
||||||
@@ -193,12 +269,12 @@ export default function DocumentManager() {
|
|||||||
}, [health, fetchDocuments, t, currentTab])
|
}, [health, fetchDocuments, t, currentTab])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="!size-full !rounded-none !border-none">
|
<Card className="!rounded-none !overflow-hidden flex flex-col h-full min-h-0">
|
||||||
<CardHeader>
|
<CardHeader className="py-2 px-6">
|
||||||
<CardTitle className="text-lg">{t('documentPanel.documentManager.title')}</CardTitle>
|
<CardTitle className="text-lg">{t('documentPanel.documentManager.title')}</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="flex-1 flex flex-col min-h-0 overflow-auto">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2 mb-2">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -231,8 +307,8 @@ export default function DocumentManager() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Card>
|
<Card className="flex-1 flex flex-col border rounded-md min-h-0 mb-0">
|
||||||
<CardHeader>
|
<CardHeader className="flex-none py-2 px-4">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<CardTitle>{t('documentPanel.documentManager.uploadedTitle')}</CardTitle>
|
<CardTitle>{t('documentPanel.documentManager.uploadedTitle')}</CardTitle>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@@ -250,20 +326,24 @@ export default function DocumentManager() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CardDescription>{t('documentPanel.documentManager.uploadedDescription')}</CardDescription>
|
<CardDescription aria-hidden="true" className="hidden">{t('documentPanel.documentManager.uploadedDescription')}</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
<CardContent>
|
<CardContent className="flex-1 relative p-0" ref={cardContentRef}>
|
||||||
{!docs && (
|
{!docs && (
|
||||||
|
<div className="absolute inset-0 p-0">
|
||||||
<EmptyCard
|
<EmptyCard
|
||||||
title={t('documentPanel.documentManager.emptyTitle')}
|
title={t('documentPanel.documentManager.emptyTitle')}
|
||||||
description={t('documentPanel.documentManager.emptyDescription')}
|
description={t('documentPanel.documentManager.emptyDescription')}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{docs && (
|
{docs && (
|
||||||
<Table>
|
<div className="absolute inset-0 flex flex-col p-0">
|
||||||
<TableHeader>
|
<div className="w-full h-full flex flex-col rounded-lg border border-gray-200 dark:border-gray-700 overflow-auto">
|
||||||
<TableRow>
|
<Table className="w-full">
|
||||||
|
<TableHeader className="sticky top-0 bg-background z-10 shadow-sm">
|
||||||
|
<TableRow className="border-b bg-card/95 backdrop-blur supports-[backdrop-filter]:bg-card/75 shadow-[inset_0_-1px_0_rgba(0,0,0,0.1)]">
|
||||||
<TableHead>{t('documentPanel.documentManager.columns.id')}</TableHead>
|
<TableHead>{t('documentPanel.documentManager.columns.id')}</TableHead>
|
||||||
<TableHead>{t('documentPanel.documentManager.columns.summary')}</TableHead>
|
<TableHead>{t('documentPanel.documentManager.columns.summary')}</TableHead>
|
||||||
<TableHead>{t('documentPanel.documentManager.columns.status')}</TableHead>
|
<TableHead>{t('documentPanel.documentManager.columns.status')}</TableHead>
|
||||||
@@ -273,40 +353,40 @@ export default function DocumentManager() {
|
|||||||
<TableHead>{t('documentPanel.documentManager.columns.updated')}</TableHead>
|
<TableHead>{t('documentPanel.documentManager.columns.updated')}</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody className="text-sm">
|
<TableBody className="text-sm overflow-auto">
|
||||||
{Object.entries(docs.statuses).map(([status, documents]) =>
|
{Object.entries(docs.statuses).map(([status, documents]) =>
|
||||||
documents.map((doc) => (
|
documents.map((doc) => (
|
||||||
<TableRow key={doc.id}>
|
<TableRow key={doc.id}>
|
||||||
<TableCell className="truncate font-mono overflow-visible">
|
<TableCell className="truncate font-mono overflow-visible max-w-[250px]">
|
||||||
{showFileName ? (
|
{showFileName ? (
|
||||||
<>
|
<>
|
||||||
<div className="group relative overflow-visible">
|
<div className="group relative overflow-visible tooltip-container">
|
||||||
<div className="truncate">
|
<div className="truncate">
|
||||||
{getDisplayFileName(doc, 35)}
|
{getDisplayFileName(doc, 30)}
|
||||||
</div>
|
</div>
|
||||||
<div className="invisible group-hover:visible absolute z-[9999] mt-1 max-w-[800px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
|
<div className="invisible group-hover:visible absolute z-[9999] mt-1 max-w-[600px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
|
||||||
{doc.file_path}
|
{doc.file_path}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-gray-500">{doc.id}</div>
|
<div className="text-xs text-gray-500">{doc.id}</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="group relative overflow-visible">
|
<div className="group relative overflow-visible tooltip-container">
|
||||||
<div className="truncate">
|
<div className="truncate">
|
||||||
{doc.id}
|
{doc.id}
|
||||||
</div>
|
</div>
|
||||||
<div className="invisible group-hover:visible absolute z-[9999] mt-1 max-w-[800px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
|
<div className="invisible group-hover:visible absolute z-[9999] mt-1 max-w-[600px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
|
||||||
{doc.file_path}
|
{doc.file_path}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="max-w-xs min-w-24 truncate overflow-visible">
|
<TableCell className="max-w-xs min-w-45 truncate overflow-visible">
|
||||||
<div className="group relative overflow-visible">
|
<div className="group relative overflow-visible tooltip-container">
|
||||||
<div className="truncate">
|
<div className="truncate">
|
||||||
{doc.content_summary}
|
{doc.content_summary}
|
||||||
</div>
|
</div>
|
||||||
<div className="invisible group-hover:visible absolute z-[9999] mt-1 max-w-[800px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
|
<div className="invisible group-hover:visible absolute z-[9999] mt-1 max-w-[600px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
|
||||||
{doc.content_summary}
|
{doc.content_summary}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -339,6 +419,8 @@ export default function DocumentManager() {
|
|||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
Reference in New Issue
Block a user