Merge branch 'feat-node-expand' into webui-node-expansion

This commit is contained in:
yangdx
2025-03-17 21:16:42 +08:00
6 changed files with 176 additions and 139 deletions

File diff suppressed because one or more lines are too long

View File

@@ -8,7 +8,7 @@
<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="./assets/index-BpDMZCmZ.js"></script> <script type="module" crossorigin src="./assets/index-DuxTk-ly.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-BEGlBF11.css"> <link rel="stylesheet" crossorigin href="./assets/index-BEGlBF11.css">
</head> </head>
<body> <body>

View File

@@ -2,14 +2,17 @@ import { useCallback, useEffect, useRef } from 'react'
import { AsyncSelect } from '@/components/ui/AsyncSelect' import { AsyncSelect } from '@/components/ui/AsyncSelect'
import { useSettingsStore } from '@/stores/settings' import { useSettingsStore } from '@/stores/settings'
import { useGraphStore } from '@/stores/graph' import { useGraphStore } from '@/stores/graph'
import { labelListLimit } from '@/lib/constants' import { labelListLimit, controlButtonVariant } from '@/lib/constants'
import MiniSearch from 'minisearch' import MiniSearch from 'minisearch'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { RefreshCw } from 'lucide-react'
import Button from '@/components/ui/Button'
const GraphLabels = () => { const GraphLabels = () => {
const { t } = useTranslation() const { t } = useTranslation()
const label = useSettingsStore.use.queryLabel() const label = useSettingsStore.use.queryLabel()
const allDatabaseLabels = useGraphStore.use.allDatabaseLabels() const allDatabaseLabels = useGraphStore.use.allDatabaseLabels()
const rawGraph = useGraphStore.use.rawGraph()
const labelsLoadedRef = useRef(false) const labelsLoadedRef = useRef(false)
// Track if a fetch is in progress to prevent multiple simultaneous fetches // Track if a fetch is in progress to prevent multiple simultaneous fetches
@@ -83,47 +86,70 @@ const GraphLabels = () => {
[getSearchEngine] [getSearchEngine]
) )
const handleRefresh = useCallback(() => {
const currentLabel = useSettingsStore.getState().queryLabel
useGraphStore.getState().setGraphDataFetchAttempted(false)
useGraphStore.getState().reset()
useSettingsStore.getState().setQueryLabel(currentLabel)
}, [])
return ( return (
<AsyncSelect<string> <div className="flex items-center">
className="ml-2" {rawGraph && (
triggerClassName="max-h-8" <Button
searchInputClassName="max-h-8" size="icon"
triggerTooltip={t('graphPanel.graphLabels.selectTooltip')} variant={controlButtonVariant}
fetcher={fetchData} onClick={handleRefresh}
renderOption={(item) => <div>{item}</div>} tooltip={t('graphPanel.graphLabels.refreshTooltip')}
getOptionValue={(item) => item} className="mr-1"
getDisplayValue={(item) => <div>{item}</div>} >
notFound={<div className="py-6 text-center text-sm">No labels found</div>} <RefreshCw className="h-4 w-4" />
label={t('graphPanel.graphLabels.label')} </Button>
placeholder={t('graphPanel.graphLabels.placeholder')} )}
value={label !== null ? label : '*'} <AsyncSelect<string>
onChange={(newLabel) => { className="ml-2"
const currentLabel = useSettingsStore.getState().queryLabel triggerClassName="max-h-8"
searchInputClassName="max-h-8"
triggerTooltip={t('graphPanel.graphLabels.selectTooltip')}
fetcher={fetchData}
renderOption={(item) => <div>{item}</div>}
getOptionValue={(item) => item}
getDisplayValue={(item) => <div>{item}</div>}
notFound={<div className="py-6 text-center text-sm">No labels found</div>}
label={t('graphPanel.graphLabels.label')}
placeholder={t('graphPanel.graphLabels.placeholder')}
value={label !== null ? label : '*'}
onChange={(newLabel) => {
const currentLabel = useSettingsStore.getState().queryLabel
// select the last item means query all // select the last item means query all
if (newLabel === '...') { if (newLabel === '...') {
newLabel = '*' newLabel = '*'
} }
// Reset the fetch attempted flag to force a new data fetch // Reset the fetch attempted flag to force a new data fetch
useGraphStore.getState().setGraphDataFetchAttempted(false) useGraphStore.getState().setGraphDataFetchAttempted(false)
// Clear current graph data to ensure complete reload when label changes // Clear current graph data to ensure complete reload when label changes
if (newLabel !== currentLabel) { if (newLabel !== currentLabel) {
const graphStore = useGraphStore.getState(); const graphStore = useGraphStore.getState();
// Reset the all graph objects and status // Reset the all graph objects and status
graphStore.reset(); graphStore.reset();
} }
if (newLabel === currentLabel && newLabel !== '*') { if (newLabel === currentLabel && newLabel !== '*') {
// reselect the same itme means qery all // reselect the same itme means qery all
useSettingsStore.getState().setQueryLabel('*') useSettingsStore.getState().setQueryLabel('*')
} else { } else {
useSettingsStore.getState().setQueryLabel(newLabel) useSettingsStore.getState().setQueryLabel(newLabel)
} }
}} }}
clearable={false} // Prevent clearing value on reselect clearable={false} // Prevent clearing value on reselect
/> />
</div>
) )
} }

View File

@@ -203,10 +203,19 @@ const LayoutsControl = () => {
const layoutCircular = useLayoutCircular() const layoutCircular = useLayoutCircular()
const layoutCirclepack = useLayoutCirclepack() const layoutCirclepack = useLayoutCirclepack()
const layoutRandom = useLayoutRandom() const layoutRandom = useLayoutRandom()
const layoutNoverlap = useLayoutNoverlap({ settings: { margin: 1 } }) const layoutNoverlap = useLayoutNoverlap({
maxIterations: maxIterations,
settings: {
margin: 2,
expansion: 1.1,
gridSize: 5,
ratio: 1,
speed: 3,
}
})
// Add parameters for Force Directed layout to improve convergence // Add parameters for Force Directed layout to improve convergence
const layoutForce = useLayoutForce({ const layoutForce = useLayoutForce({
maxIterations: maxIterations * 3, // Triple the iterations for better convergence maxIterations: maxIterations,
settings: { settings: {
attraction: 0.0003, // Lower attraction force to reduce oscillation attraction: 0.0003, // Lower attraction force to reduce oscillation
repulsion: 0.05, // Lower repulsion force to reduce oscillation repulsion: 0.05, // Lower repulsion force to reduce oscillation

View File

@@ -182,7 +182,8 @@
"noLabels": "No labels found", "noLabels": "No labels found",
"label": "Label", "label": "Label",
"placeholder": "Search labels...", "placeholder": "Search labels...",
"andOthers": "And {count} others" "andOthers": "And {count} others",
"refreshTooltip": "Reload graph data"
} }
}, },
"retrievePanel": { "retrievePanel": {

View File

@@ -179,7 +179,8 @@
"noLabels": "未找到标签", "noLabels": "未找到标签",
"label": "标签", "label": "标签",
"placeholder": "搜索标签...", "placeholder": "搜索标签...",
"andOthers": "还有 {count} 个" "andOthers": "还有 {count} 个",
"refreshTooltip": "重新加载图形数据"
} }
}, },
"retrievePanel": { "retrievePanel": {