Merge pull request #1126 from danielaskdd/improve-graph-reload
Improve graph reload
This commit is contained in:
File diff suppressed because one or more lines are too long
1
lightrag/api/webui/assets/index-BMVv3U43.css
Normal file
1
lightrag/api/webui/assets/index-BMVv3U43.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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-C56SCRGK.js"></script>
|
<script type="module" crossorigin src="/webui/assets/index-BxHTAgSP.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/webui/assets/index-BE_O4IWQ.css">
|
<link rel="stylesheet" crossorigin href="/webui/assets/index-BMVv3U43.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@@ -18,7 +18,7 @@ const GraphLabels = () => {
|
|||||||
// Track if a fetch is in progress to prevent multiple simultaneous fetches
|
// Track if a fetch is in progress to prevent multiple simultaneous fetches
|
||||||
const fetchInProgressRef = useRef(false)
|
const fetchInProgressRef = useRef(false)
|
||||||
|
|
||||||
// Fetch labels once on component mount, using global flag to prevent duplicates
|
// Fetch labels and trigger initial data load
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Check if we've already attempted to fetch labels in this session
|
// Check if we've already attempted to fetch labels in this session
|
||||||
const labelsFetchAttempted = useGraphStore.getState().labelsFetchAttempted
|
const labelsFetchAttempted = useGraphStore.getState().labelsFetchAttempted
|
||||||
@@ -43,6 +43,14 @@ const GraphLabels = () => {
|
|||||||
}
|
}
|
||||||
}, []) // Empty dependency array ensures this only runs once on mount
|
}, []) // Empty dependency array ensures this only runs once on mount
|
||||||
|
|
||||||
|
// Trigger data load when labels are loaded
|
||||||
|
useEffect(() => {
|
||||||
|
if (labelsLoadedRef.current) {
|
||||||
|
// Reset the fetch attempted flag to force a new data fetch
|
||||||
|
useGraphStore.getState().setGraphDataFetchAttempted(false)
|
||||||
|
}
|
||||||
|
}, [label])
|
||||||
|
|
||||||
const getSearchEngine = useCallback(() => {
|
const getSearchEngine = useCallback(() => {
|
||||||
// Create search engine
|
// Create search engine
|
||||||
const searchEngine = new MiniSearch({
|
const searchEngine = new MiniSearch({
|
||||||
@@ -85,13 +93,25 @@ const GraphLabels = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const handleRefresh = useCallback(() => {
|
const handleRefresh = useCallback(() => {
|
||||||
const currentLabel = useSettingsStore.getState().queryLabel
|
// Reset labels fetch status to allow fetching labels again
|
||||||
|
useGraphStore.getState().setLabelsFetchAttempted(false)
|
||||||
|
|
||||||
|
// Reset graph data fetch status directly, not depending on allDatabaseLabels changes
|
||||||
useGraphStore.getState().setGraphDataFetchAttempted(false)
|
useGraphStore.getState().setGraphDataFetchAttempted(false)
|
||||||
|
|
||||||
useGraphStore.getState().reset()
|
// Fetch all labels again
|
||||||
|
useGraphStore.getState().fetchAllDatabaseLabels()
|
||||||
|
.then(() => {
|
||||||
|
// Trigger a graph data reload by changing the query label back and forth
|
||||||
|
const currentLabel = useSettingsStore.getState().queryLabel
|
||||||
|
useSettingsStore.getState().setQueryLabel('')
|
||||||
|
setTimeout(() => {
|
||||||
useSettingsStore.getState().setQueryLabel(currentLabel)
|
useSettingsStore.getState().setQueryLabel(currentLabel)
|
||||||
|
}, 0)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to refresh labels:', error)
|
||||||
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -128,22 +148,13 @@ const GraphLabels = () => {
|
|||||||
newLabel = '*'
|
newLabel = '*'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the fetch attempted flag to force a new data fetch
|
// Handle reselecting the same label
|
||||||
useGraphStore.getState().setGraphDataFetchAttempted(false)
|
|
||||||
|
|
||||||
// Clear current graph data to ensure complete reload when label changes
|
|
||||||
if (newLabel !== currentLabel) {
|
|
||||||
const graphStore = useGraphStore.getState();
|
|
||||||
// Reset the all graph objects and status
|
|
||||||
graphStore.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newLabel === currentLabel && newLabel !== '*') {
|
if (newLabel === currentLabel && newLabel !== '*') {
|
||||||
// reselect the same itme means qery all
|
newLabel = '*'
|
||||||
useSettingsStore.getState().setQueryLabel('*')
|
|
||||||
} else {
|
|
||||||
useSettingsStore.getState().setQueryLabel(newLabel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the label, which will trigger the useEffect to handle data loading
|
||||||
|
useSettingsStore.getState().setQueryLabel(newLabel)
|
||||||
}}
|
}}
|
||||||
clearable={false} // Prevent clearing value on reselect
|
clearable={false} // Prevent clearing value on reselect
|
||||||
/>
|
/>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useCallback, useEffect } from 'react'
|
import { useState, useCallback} from 'react'
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/Popover'
|
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/Popover'
|
||||||
import Checkbox from '@/components/ui/Checkbox'
|
import Checkbox from '@/components/ui/Checkbox'
|
||||||
import Button from '@/components/ui/Button'
|
import Button from '@/components/ui/Button'
|
||||||
@@ -7,7 +7,6 @@ import Input from '@/components/ui/Input'
|
|||||||
|
|
||||||
import { controlButtonVariant } from '@/lib/constants'
|
import { controlButtonVariant } from '@/lib/constants'
|
||||||
import { useSettingsStore } from '@/stores/settings'
|
import { useSettingsStore } from '@/stores/settings'
|
||||||
import { useBackendState } from '@/stores/state'
|
|
||||||
|
|
||||||
import { SettingsIcon } from 'lucide-react'
|
import { SettingsIcon } from 'lucide-react'
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -113,7 +112,6 @@ const LabeledNumberInput = ({
|
|||||||
*/
|
*/
|
||||||
export default function Settings() {
|
export default function Settings() {
|
||||||
const [opened, setOpened] = useState<boolean>(false)
|
const [opened, setOpened] = useState<boolean>(false)
|
||||||
const [tempApiKey, setTempApiKey] = useState<string>('')
|
|
||||||
|
|
||||||
const showPropertyPanel = useSettingsStore.use.showPropertyPanel()
|
const showPropertyPanel = useSettingsStore.use.showPropertyPanel()
|
||||||
const showNodeSearchBar = useSettingsStore.use.showNodeSearchBar()
|
const showNodeSearchBar = useSettingsStore.use.showNodeSearchBar()
|
||||||
@@ -127,11 +125,6 @@ export default function Settings() {
|
|||||||
const graphLayoutMaxIterations = useSettingsStore.use.graphLayoutMaxIterations()
|
const graphLayoutMaxIterations = useSettingsStore.use.graphLayoutMaxIterations()
|
||||||
|
|
||||||
const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
|
const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
|
||||||
const apiKey = useSettingsStore.use.apiKey()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setTempApiKey(apiKey || '')
|
|
||||||
}, [apiKey, opened])
|
|
||||||
|
|
||||||
const setEnableNodeDrag = useCallback(
|
const setEnableNodeDrag = useCallback(
|
||||||
() => useSettingsStore.setState((pre) => ({ enableNodeDrag: !pre.enableNodeDrag })),
|
() => useSettingsStore.setState((pre) => ({ enableNodeDrag: !pre.enableNodeDrag })),
|
||||||
@@ -180,11 +173,22 @@ export default function Settings() {
|
|||||||
const setGraphQueryMaxDepth = useCallback((depth: number) => {
|
const setGraphQueryMaxDepth = useCallback((depth: number) => {
|
||||||
if (depth < 1) return
|
if (depth < 1) return
|
||||||
useSettingsStore.setState({ graphQueryMaxDepth: depth })
|
useSettingsStore.setState({ graphQueryMaxDepth: depth })
|
||||||
|
const currentLabel = useSettingsStore.getState().queryLabel
|
||||||
|
useSettingsStore.getState().setQueryLabel('')
|
||||||
|
setTimeout(() => {
|
||||||
|
useSettingsStore.getState().setQueryLabel(currentLabel)
|
||||||
|
}, 300)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const setGraphMinDegree = useCallback((degree: number) => {
|
const setGraphMinDegree = useCallback((degree: number) => {
|
||||||
if (degree < 0) return
|
if (degree < 0) return
|
||||||
useSettingsStore.setState({ graphMinDegree: degree })
|
useSettingsStore.setState({ graphMinDegree: degree })
|
||||||
|
const currentLabel = useSettingsStore.getState().queryLabel
|
||||||
|
useSettingsStore.getState().setQueryLabel('')
|
||||||
|
setTimeout(() => {
|
||||||
|
useSettingsStore.getState().setQueryLabel(currentLabel)
|
||||||
|
}, 300)
|
||||||
|
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const setGraphLayoutMaxIterations = useCallback((iterations: number) => {
|
const setGraphLayoutMaxIterations = useCallback((iterations: number) => {
|
||||||
@@ -192,26 +196,21 @@ export default function Settings() {
|
|||||||
useSettingsStore.setState({ graphLayoutMaxIterations: iterations })
|
useSettingsStore.setState({ graphLayoutMaxIterations: iterations })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const setApiKey = useCallback(async () => {
|
|
||||||
useSettingsStore.setState({ apiKey: tempApiKey || null })
|
|
||||||
await useBackendState.getState().check()
|
|
||||||
setOpened(false)
|
|
||||||
}, [tempApiKey])
|
|
||||||
|
|
||||||
const handleTempApiKeyChange = useCallback(
|
|
||||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setTempApiKey(e.target.value)
|
|
||||||
},
|
|
||||||
[setTempApiKey]
|
|
||||||
)
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const saveSettings = () => setOpened(false);
|
||||||
|
const toggleSettings = () => setOpened(!opened);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Popover open={opened} onOpenChange={setOpened}>
|
<Popover open={opened}>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button variant={controlButtonVariant} tooltip={t('graphPanel.sideBar.settings.settings')} size="icon">
|
<Button
|
||||||
|
variant={controlButtonVariant}
|
||||||
|
tooltip={t('graphPanel.sideBar.settings.settings')}
|
||||||
|
size="icon"
|
||||||
|
onClick={toggleSettings}
|
||||||
|
>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
@@ -293,30 +292,15 @@ export default function Settings() {
|
|||||||
onEditFinished={setGraphLayoutMaxIterations}
|
onEditFinished={setGraphLayoutMaxIterations}
|
||||||
/>
|
/>
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<label className="text-sm font-medium">{t('graphPanel.sideBar.settings.apiKey')}</label>
|
|
||||||
<form className="flex h-6 gap-2" onSubmit={(e) => e.preventDefault()}>
|
|
||||||
<div className="w-0 flex-1">
|
|
||||||
<Input
|
|
||||||
type="password"
|
|
||||||
value={tempApiKey}
|
|
||||||
onChange={handleTempApiKeyChange}
|
|
||||||
placeholder={t('graphPanel.sideBar.settings.enterYourAPIkey')}
|
|
||||||
className="max-h-full w-full min-w-0"
|
|
||||||
autoComplete="off"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
onClick={setApiKey}
|
onClick={saveSettings}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="max-h-full shrink-0"
|
className="ml-auto px-4"
|
||||||
>
|
>
|
||||||
{t('graphPanel.sideBar.settings.save')}
|
{t('graphPanel.sideBar.settings.save')}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
@@ -11,7 +11,7 @@ const SettingsDisplay = () => {
|
|||||||
const graphMinDegree = useSettingsStore.use.graphMinDegree()
|
const graphMinDegree = useSettingsStore.use.graphMinDegree()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute bottom-2 left-[calc(2rem+2.5rem)] flex items-center gap-2 text-xs text-gray-400">
|
<div className="absolute bottom-4 left-[calc(1rem+2.5rem)] flex items-center gap-2 text-xs text-gray-400">
|
||||||
<div>{t('graphPanel.sideBar.settings.depth')}: {graphQueryMaxDepth}</div>
|
<div>{t('graphPanel.sideBar.settings.depth')}: {graphQueryMaxDepth}</div>
|
||||||
<div>{t('graphPanel.sideBar.settings.degree')}: {graphMinDegree}</div>
|
<div>{t('graphPanel.sideBar.settings.degree')}: {graphMinDegree}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -189,19 +189,10 @@ const useLightrangeGraph = () => {
|
|||||||
const nodeToExpand = useGraphStore.use.nodeToExpand()
|
const nodeToExpand = useGraphStore.use.nodeToExpand()
|
||||||
const nodeToPrune = useGraphStore.use.nodeToPrune()
|
const nodeToPrune = useGraphStore.use.nodeToPrune()
|
||||||
|
|
||||||
// Track previous parameters to detect actual changes
|
|
||||||
const prevParamsRef = useRef({ queryLabel, maxQueryDepth, minDegree })
|
|
||||||
|
|
||||||
// Use ref to track if data has been loaded and initial load
|
// Use ref to track if data has been loaded and initial load
|
||||||
const dataLoadedRef = useRef(false)
|
const dataLoadedRef = useRef(false)
|
||||||
const initialLoadRef = useRef(false)
|
const initialLoadRef = useRef(false)
|
||||||
|
|
||||||
// Check if parameters have changed
|
|
||||||
const paramsChanged =
|
|
||||||
prevParamsRef.current.queryLabel !== queryLabel ||
|
|
||||||
prevParamsRef.current.maxQueryDepth !== maxQueryDepth ||
|
|
||||||
prevParamsRef.current.minDegree !== minDegree
|
|
||||||
|
|
||||||
const getNode = useCallback(
|
const getNode = useCallback(
|
||||||
(nodeId: string) => {
|
(nodeId: string) => {
|
||||||
return rawGraph?.getNode(nodeId) || null
|
return rawGraph?.getNode(nodeId) || null
|
||||||
@@ -219,30 +210,27 @@ const useLightrangeGraph = () => {
|
|||||||
// Track if a fetch is in progress to prevent multiple simultaneous fetches
|
// Track if a fetch is in progress to prevent multiple simultaneous fetches
|
||||||
const fetchInProgressRef = useRef(false)
|
const fetchInProgressRef = useRef(false)
|
||||||
|
|
||||||
// Data fetching logic - simplified but preserving TAB visibility check
|
// Reset graph when query label is cleared
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Skip if fetch is already in progress
|
if (!queryLabel && (rawGraph !== null || sigmaGraph !== null)) {
|
||||||
if (fetchInProgressRef.current) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's no query label, reset the graph
|
|
||||||
if (!queryLabel) {
|
|
||||||
if (rawGraph !== null || sigmaGraph !== null) {
|
|
||||||
const state = useGraphStore.getState()
|
const state = useGraphStore.getState()
|
||||||
state.reset()
|
state.reset()
|
||||||
state.setGraphDataFetchAttempted(false)
|
state.setGraphDataFetchAttempted(false)
|
||||||
state.setLabelsFetchAttempted(false)
|
state.setLabelsFetchAttempted(false)
|
||||||
}
|
|
||||||
dataLoadedRef.current = false
|
dataLoadedRef.current = false
|
||||||
initialLoadRef.current = false
|
initialLoadRef.current = false
|
||||||
|
}
|
||||||
|
}, [queryLabel, rawGraph, sigmaGraph])
|
||||||
|
|
||||||
|
// Data fetching logic
|
||||||
|
useEffect(() => {
|
||||||
|
// Skip if fetch is already in progress or no query label
|
||||||
|
if (fetchInProgressRef.current || !queryLabel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if parameters have changed
|
// Only fetch data when graphDataFetchAttempted is false (avoids re-fetching on vite dev mode)
|
||||||
if (!isFetching && !fetchInProgressRef.current &&
|
if (!isFetching && !useGraphStore.getState().graphDataFetchAttempted) {
|
||||||
(paramsChanged || !useGraphStore.getState().graphDataFetchAttempted)) {
|
|
||||||
|
|
||||||
// Set flags
|
// Set flags
|
||||||
fetchInProgressRef.current = true
|
fetchInProgressRef.current = true
|
||||||
useGraphStore.getState().setGraphDataFetchAttempted(true)
|
useGraphStore.getState().setGraphDataFetchAttempted(true)
|
||||||
@@ -258,9 +246,6 @@ const useLightrangeGraph = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update parameter reference
|
|
||||||
prevParamsRef.current = { queryLabel, maxQueryDepth, minDegree }
|
|
||||||
|
|
||||||
console.log('Fetching graph data...')
|
console.log('Fetching graph data...')
|
||||||
|
|
||||||
// Use a local copy of the parameters
|
// Use a local copy of the parameters
|
||||||
@@ -283,8 +268,6 @@ const useLightrangeGraph = () => {
|
|||||||
state.setSigmaGraph(newSigmaGraph)
|
state.setSigmaGraph(newSigmaGraph)
|
||||||
state.setRawGraph(data)
|
state.setRawGraph(data)
|
||||||
|
|
||||||
// No longer need to extract labels from graph data
|
|
||||||
|
|
||||||
// Update flags
|
// Update flags
|
||||||
dataLoadedRef.current = true
|
dataLoadedRef.current = true
|
||||||
initialLoadRef.current = true
|
initialLoadRef.current = true
|
||||||
@@ -305,7 +288,7 @@ const useLightrangeGraph = () => {
|
|||||||
state.setGraphDataFetchAttempted(false)
|
state.setGraphDataFetchAttempted(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [queryLabel, maxQueryDepth, minDegree, isFetching, paramsChanged, rawGraph, sigmaGraph])
|
}, [queryLabel, maxQueryDepth, minDegree, isFetching])
|
||||||
|
|
||||||
// Handle node expansion
|
// Handle node expansion
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@@ -99,7 +99,7 @@
|
|||||||
"hideUnselectedEdges": "隐藏未选中的边",
|
"hideUnselectedEdges": "隐藏未选中的边",
|
||||||
"edgeEvents": "边事件",
|
"edgeEvents": "边事件",
|
||||||
"maxQueryDepth": "最大查询深度",
|
"maxQueryDepth": "最大查询深度",
|
||||||
"minDegree": "最小度数",
|
"minDegree": "最小邻边数",
|
||||||
"maxLayoutIterations": "最大布局迭代次数",
|
"maxLayoutIterations": "最大布局迭代次数",
|
||||||
"depth": "深度",
|
"depth": "深度",
|
||||||
"degree": "邻边",
|
"degree": "邻边",
|
||||||
|
Reference in New Issue
Block a user