From 727b1375063ad843d7f7acfce77891382324807f Mon Sep 17 00:00:00 2001 From: yangdx Date: Thu, 13 Mar 2025 00:20:53 +0800 Subject: [PATCH] Limit the search scope to labels in the current subgraph - Decouple datasource label selection from the search input field - Improve label selection handling logic --- .../src/components/graph/GraphLabels.tsx | 42 +++++++++---------- lightrag_webui/src/hooks/useLightragGraph.tsx | 10 ++++- lightrag_webui/src/stores/graph.ts | 17 ++++++++ 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/lightrag_webui/src/components/graph/GraphLabels.tsx b/lightrag_webui/src/components/graph/GraphLabels.tsx index 7fd37848..f8401238 100644 --- a/lightrag_webui/src/components/graph/GraphLabels.tsx +++ b/lightrag_webui/src/components/graph/GraphLabels.tsx @@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next' const GraphLabels = () => { const { t } = useTranslation() const label = useSettingsStore.use.queryLabel() - const graphLabels = useGraphStore.use.graphLabels() + const allDatabaseLabels = useGraphStore.use.allDatabaseLabels() const getSearchEngine = useCallback(() => { // Create search engine @@ -26,14 +26,14 @@ const GraphLabels = () => { }) // Add documents - const documents = graphLabels.map((str, index) => ({ id: index, value: str })) + const documents = allDatabaseLabels.map((str, index) => ({ id: index, value: str })) searchEngine.addAll(documents) return { - labels: graphLabels, + labels: allDatabaseLabels, searchEngine } - }, [graphLabels]) + }, [allDatabaseLabels]) const fetchData = useCallback( async (query?: string): Promise => { @@ -47,27 +47,11 @@ const GraphLabels = () => { return result.length <= labelListLimit ? result - : [...result.slice(0, labelListLimit), t('graphLabels.andOthers', { count: result.length - labelListLimit })] + : [...result.slice(0, labelListLimit), '...'] }, [getSearchEngine, t] ) - const setQueryLabel = useCallback((newLabel: string) => { - if (newLabel.startsWith('And ') && newLabel.endsWith(' others')) return - - const currentLabel = useSettingsStore.getState().queryLabel - - if (newLabel === '*' && currentLabel === '*') { - // When reselecting '*', just set it again to trigger a new fetch - useSettingsStore.getState().setQueryLabel('*') - } else if (newLabel === currentLabel && newLabel !== '*') { - // When selecting the same label (except '*'), switch to '*' - useSettingsStore.getState().setQueryLabel('*') - } else { - useSettingsStore.getState().setQueryLabel(newLabel) - } - }, []) - return ( className="ml-2" @@ -81,8 +65,20 @@ const GraphLabels = () => { notFound={
No labels found
} label={t('graphPanel.graphLabels.label')} placeholder={t('graphPanel.graphLabels.placeholder')} - value={label !== null ? label : ''} - onChange={setQueryLabel} + value={label !== null ? label : '*'} + onChange={(newLabel) => { + const currentLabel = useSettingsStore.getState().queryLabel + + if (newLabel === '...') { + newLabel = '*' + } + if (newLabel === currentLabel && newLabel !== '*') { + // 选择相同标签时切换到'*' + useSettingsStore.getState().setQueryLabel('*') + } else { + useSettingsStore.getState().setQueryLabel(newLabel) + } + }} clearable={false} // Prevent clearing value on reselect /> ) diff --git a/lightrag_webui/src/hooks/useLightragGraph.tsx b/lightrag_webui/src/hooks/useLightragGraph.tsx index adac1d10..969b6dfe 100644 --- a/lightrag_webui/src/hooks/useLightragGraph.tsx +++ b/lightrag_webui/src/hooks/useLightragGraph.tsx @@ -169,6 +169,11 @@ const useLightrangeGraph = () => { const minDegree = useSettingsStore.use.graphMinDegree() const isFetching = useGraphStore.use.isFetching() + // Fetch all database labels on mount + useEffect(() => { + useGraphStore.getState().fetchAllDatabaseLabels() + }, []) + // Use ref to track fetch status const fetchStatusRef = useRef>({}); @@ -222,7 +227,7 @@ const useLightrangeGraph = () => { state.setSigmaGraph(newSigmaGraph) state.setRawGraph(data) - // Extract labels from graph data + // Extract labels from current graph data if (data) { const labelSet = new Set(); for (const node of data.nodes) { @@ -241,6 +246,9 @@ const useLightrangeGraph = () => { // Ensure * is there eventhough there is no graph data state.setGraphLabels(['*']); } + + // Fetch all database labels after graph update + state.fetchAllDatabaseLabels(); if (!data) { // If data is invalid, remove the fetch flag to allow retry delete fetchStatusRef.current[fetchKey]; diff --git a/lightrag_webui/src/stores/graph.ts b/lightrag_webui/src/stores/graph.ts index b47d6445..3c4fe37e 100644 --- a/lightrag_webui/src/stores/graph.ts +++ b/lightrag_webui/src/stores/graph.ts @@ -1,6 +1,7 @@ import { create } from 'zustand' import { createSelectors } from '@/lib/utils' import { DirectedGraph } from 'graphology' +import { getGraphLabels } from '@/api/lightrag' export type RawNodeType = { id: string @@ -66,6 +67,7 @@ interface GraphState { rawGraph: RawGraph | null sigmaGraph: DirectedGraph | null graphLabels: string[] + allDatabaseLabels: string[] moveToSelectedNode: boolean isFetching: boolean @@ -82,6 +84,8 @@ interface GraphState { setRawGraph: (rawGraph: RawGraph | null) => void setSigmaGraph: (sigmaGraph: DirectedGraph | null) => void setGraphLabels: (labels: string[]) => void + setAllDatabaseLabels: (labels: string[]) => void + fetchAllDatabaseLabels: () => Promise setIsFetching: (isFetching: boolean) => void } @@ -97,6 +101,7 @@ const useGraphStoreBase = create()((set) => ({ rawGraph: null, sigmaGraph: null, graphLabels: ['*'], + allDatabaseLabels: ['*'], setIsFetching: (isFetching: boolean) => set({ isFetching }), setSelectedNode: (nodeId: string | null, moveToSelectedNode?: boolean) => @@ -132,6 +137,18 @@ const useGraphStoreBase = create()((set) => ({ setGraphLabels: (labels: string[]) => set({ graphLabels: labels }), + setAllDatabaseLabels: (labels: string[]) => set({ allDatabaseLabels: labels }), + + fetchAllDatabaseLabels: async () => { + try { + const labels = await getGraphLabels(); + set({ allDatabaseLabels: ['*', ...labels] }); + } catch (error) { + console.error('Failed to fetch all database labels:', error); + set({ allDatabaseLabels: ['*'] }); + } + }, + setMoveToSelectedNode: (moveToSelectedNode?: boolean) => set({ moveToSelectedNode }) }))