import { create } from 'zustand' import { createSelectors } from '@/lib/utils' import { DirectedGraph } from 'graphology' import { getGraphLabels } from '@/api/lightrag' export type RawNodeType = { id: string labels: string[] properties: Record size: number x: number y: number color: string degree: number } export type RawEdgeType = { id: string source: string target: string type?: string properties: Record dynamicId: string } export class RawGraph { nodes: RawNodeType[] = [] edges: RawEdgeType[] = [] nodeIdMap: Record = {} edgeIdMap: Record = {} edgeDynamicIdMap: Record = {} getNode = (nodeId: string) => { const nodeIndex = this.nodeIdMap[nodeId] if (nodeIndex !== undefined) { return this.nodes[nodeIndex] } return undefined } getEdge = (edgeId: string, dynamicId: boolean = true) => { const edgeIndex = dynamicId ? this.edgeDynamicIdMap[edgeId] : this.edgeIdMap[edgeId] if (edgeIndex !== undefined) { return this.edges[edgeIndex] } return undefined } buildDynamicMap = () => { this.edgeDynamicIdMap = {} for (let i = 0; i < this.edges.length; i++) { const edge = this.edges[i] this.edgeDynamicIdMap[edge.dynamicId] = i } } } interface GraphState { selectedNode: string | null focusedNode: string | null selectedEdge: string | null focusedEdge: string | null rawGraph: RawGraph | null sigmaGraph: DirectedGraph | null graphLabels: string[] allDatabaseLabels: string[] moveToSelectedNode: boolean isFetching: boolean setSelectedNode: (nodeId: string | null, moveToSelectedNode?: boolean) => void setFocusedNode: (nodeId: string | null) => void setSelectedEdge: (edgeId: string | null) => void setFocusedEdge: (edgeId: string | null) => void clearSelection: () => void reset: () => void setMoveToSelectedNode: (moveToSelectedNode: boolean) => void setRawGraph: (rawGraph: RawGraph | null) => void setSigmaGraph: (sigmaGraph: DirectedGraph | null) => void setGraphLabels: (labels: string[]) => void setAllDatabaseLabels: (labels: string[]) => void fetchAllDatabaseLabels: () => Promise setIsFetching: (isFetching: boolean) => void } const useGraphStoreBase = create()((set) => ({ selectedNode: null, focusedNode: null, selectedEdge: null, focusedEdge: null, moveToSelectedNode: false, isFetching: false, rawGraph: null, sigmaGraph: null, graphLabels: ['*'], allDatabaseLabels: ['*'], setIsFetching: (isFetching: boolean) => set({ isFetching }), setSelectedNode: (nodeId: string | null, moveToSelectedNode?: boolean) => set({ selectedNode: nodeId, moveToSelectedNode }), setFocusedNode: (nodeId: string | null) => set({ focusedNode: nodeId }), setSelectedEdge: (edgeId: string | null) => set({ selectedEdge: edgeId }), setFocusedEdge: (edgeId: string | null) => set({ focusedEdge: edgeId }), clearSelection: () => set({ selectedNode: null, focusedNode: null, selectedEdge: null, focusedEdge: null }), reset: () => set({ selectedNode: null, focusedNode: null, selectedEdge: null, focusedEdge: null, rawGraph: null, sigmaGraph: null, graphLabels: ['*'], moveToSelectedNode: false }), setRawGraph: (rawGraph: RawGraph | null) => set({ rawGraph }), setSigmaGraph: (sigmaGraph: DirectedGraph | null) => set({ sigmaGraph }), 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 }) })) const useGraphStore = createSelectors(useGraphStoreBase) export { useGraphStore }