diff --git a/lightrag_webui/src/components/graph/Settings.tsx b/lightrag_webui/src/components/graph/Settings.tsx index 758f6d58..37a36305 100644 --- a/lightrag_webui/src/components/graph/Settings.tsx +++ b/lightrag_webui/src/components/graph/Settings.tsx @@ -1,4 +1,4 @@ -import { useState, useCallback} from 'react' +import { useState, useCallback, useEffect} from 'react' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/Popover' import Checkbox from '@/components/ui/Checkbox' import Button from '@/components/ui/Button' @@ -62,6 +62,10 @@ const LabeledNumberInput = ({ // Create unique ID using the label text converted to lowercase with spaces removed const id = `input-${label.toLowerCase().replace(/\s+/g, '-')}`; + useEffect(() => { + setCurrentValue(value) + }, [value]) + const onValueChange = useCallback( (e: React.ChangeEvent) => { const text = e.target.value.trim() @@ -154,6 +158,7 @@ export default function Settings() { const maxEdgeSize = useSettingsStore.use.maxEdgeSize() const graphQueryMaxDepth = useSettingsStore.use.graphQueryMaxDepth() const graphMaxNodes = useSettingsStore.use.graphMaxNodes() + const backendMaxGraphNodes = useSettingsStore.use.backendMaxGraphNodes() const graphLayoutMaxIterations = useSettingsStore.use.graphLayoutMaxIterations() const enableHealthCheck = useSettingsStore.use.enableHealthCheck() @@ -213,14 +218,10 @@ export default function Settings() { }, []) const setGraphMaxNodes = useCallback((nodes: number) => { - if (nodes < 1 || nodes > 1000) return - useSettingsStore.setState({ graphMaxNodes: nodes }) - const currentLabel = useSettingsStore.getState().queryLabel - useSettingsStore.getState().setQueryLabel('') - setTimeout(() => { - useSettingsStore.getState().setQueryLabel(currentLabel) - }, 300) - }, []) + const maxLimit = backendMaxGraphNodes || 1000 + if (nodes < 1 || nodes > maxLimit) return + useSettingsStore.getState().setGraphMaxNodes(nodes, true) + }, [backendMaxGraphNodes]) const setGraphLayoutMaxIterations = useCallback((iterations: number) => { if (iterations < 1) return @@ -360,11 +361,11 @@ export default function Settings() { onEditFinished={setGraphQueryMaxDepth} /> void graphMaxNodes: number - setGraphMaxNodes: (nodes: number) => void + setGraphMaxNodes: (nodes: number, triggerRefresh?: boolean) => void + + backendMaxGraphNodes: number | null + setBackendMaxGraphNodes: (maxNodes: number | null) => void graphLayoutMaxIterations: number setGraphLayoutMaxIterations: (iterations: number) => void @@ -90,6 +93,7 @@ const useSettingsStoreBase = create()( graphQueryMaxDepth: 3, graphMaxNodes: 1000, + backendMaxGraphNodes: null, graphLayoutMaxIterations: 15, queryLabel: defaultQueryLabel, @@ -143,7 +147,27 @@ const useSettingsStoreBase = create()( setGraphQueryMaxDepth: (depth: number) => set({ graphQueryMaxDepth: depth }), - setGraphMaxNodes: (nodes: number) => set({ graphMaxNodes: nodes }), + setGraphMaxNodes: (nodes: number, triggerRefresh: boolean = false) => { + const state = useSettingsStore.getState(); + if (state.graphMaxNodes === nodes) { + return; + } + + if (triggerRefresh) { + const currentLabel = state.queryLabel; + // Atomically update both the node count and the query label to trigger a refresh. + set({ graphMaxNodes: nodes, queryLabel: '' }); + + // Restore the label after a short delay. + setTimeout(() => { + set({ queryLabel: currentLabel }); + }, 300); + } else { + set({ graphMaxNodes: nodes }); + } + }, + + setBackendMaxGraphNodes: (maxNodes: number | null) => set({ backendMaxGraphNodes: maxNodes }), setMinEdgeSize: (size: number) => set({ minEdgeSize: size }), @@ -168,7 +192,7 @@ const useSettingsStoreBase = create()( { name: 'settings-storage', storage: createJSONStorage(() => localStorage), - version: 13, + version: 14, migrate: (state: any, version: number) => { if (version < 2) { state.showEdgeLabel = false @@ -232,6 +256,10 @@ const useSettingsStoreBase = create()( state.querySettings.user_prompt = '' } } + if (version < 14) { + // Add backendMaxGraphNodes field for older versions + state.backendMaxGraphNodes = null + } return state } } diff --git a/lightrag_webui/src/stores/state.ts b/lightrag_webui/src/stores/state.ts index 3bc4560e..c73b3bcd 100644 --- a/lightrag_webui/src/stores/state.ts +++ b/lightrag_webui/src/stores/state.ts @@ -1,6 +1,7 @@ import { create } from 'zustand' import { createSelectors } from '@/lib/utils' import { checkHealth, LightragStatus } from '@/api/lightrag' +import { useSettingsStore } from './settings' interface BackendState { health: boolean @@ -58,6 +59,25 @@ const useBackendStateStoreBase = create()((set) => ({ ); } + // Extract and store backend max graph nodes limit + if (health.configuration?.max_graph_nodes) { + const maxNodes = parseInt(health.configuration.max_graph_nodes, 10) + if (!isNaN(maxNodes) && maxNodes > 0) { + const currentBackendMaxNodes = useSettingsStore.getState().backendMaxGraphNodes + + // Only update if the backend limit has actually changed + if (currentBackendMaxNodes !== maxNodes) { + useSettingsStore.getState().setBackendMaxGraphNodes(maxNodes) + + // Auto-adjust current graphMaxNodes if it exceeds the new backend limit + const currentMaxNodes = useSettingsStore.getState().graphMaxNodes + if (currentMaxNodes > maxNodes) { + useSettingsStore.getState().setGraphMaxNodes(maxNodes, true) + } + } + } + } + set({ health: true, message: null,