choizhang commited on
Commit
7843329
·
1 Parent(s): fa48cea

fix(graph): Fixed the issue of incorrect handling of edges and nodes during node ID updates

Browse files
lightrag_webui/src/components/graph/EditablePropertyRow.tsx CHANGED
@@ -119,41 +119,63 @@ const EditablePropertyRow = ({
119
  if (sigmaInstance && sigmaGraph && rawGraph) {
120
  // Update the node in sigma graph
121
  if (sigmaGraph.hasNode(String(value))) {
122
- // Update the node label in the sigma graph
123
- sigmaGraph.setNodeAttribute(String(value), 'label', editValue)
124
-
125
- // Also update the node in the raw graph
126
- const nodeIndex = rawGraph.nodeIdMap[String(value)]
127
- if (nodeIndex !== undefined) {
128
- rawGraph.nodes[nodeIndex].id = editValue
129
- // Update the node ID map
130
- delete rawGraph.nodeIdMap[String(value)]
131
- rawGraph.nodeIdMap[editValue] = nodeIndex
132
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
- // Refresh the sigma instance to reflect changes
135
- sigmaInstance.refresh()
136
 
137
- // Update selected node ID if it was the edited node
138
- const selectedNode = useGraphStore.getState().selectedNode
139
- if (selectedNode === String(value)) {
140
- useGraphStore.getState().setSelectedNode(editValue)
 
 
 
 
 
 
 
 
 
 
141
  }
142
  }
143
- } else {
144
- // Fallback to full graph reload if direct update is not possible
145
- useGraphStore.getState().setGraphDataFetchAttempted(false)
146
- useGraphStore.getState().setLabelsFetchAttempted(false)
147
-
148
- // Get current label to trigger reload
149
- const currentLabel = useSettingsStore.getState().queryLabel
150
- if (currentLabel) {
151
- // Trigger data reload by temporarily clearing and resetting the label
152
- useSettingsStore.getState().setQueryLabel('')
153
- setTimeout(() => {
154
- useSettingsStore.getState().setQueryLabel(currentLabel)
155
- }, 0)
156
- }
157
  }
158
  } else if (name === 'description') {
159
  // For description updates
@@ -178,22 +200,45 @@ const EditablePropertyRow = ({
178
  if (onValueChange) {
179
  onValueChange(editValue)
180
  }
181
- } catch (error: any) { // Keep type as any to access potential response properties
182
  console.error('Error updating property:', error);
183
 
184
- // Attempt to extract a more specific error message
185
- let detailMessage = t('graphPanel.propertiesView.errors.updateFailed'); // Default message
 
186
  if (error.response?.data?.detail) {
187
- // Use the detailed message from the backend response if available
188
- detailMessage = error.response.data.detail;
 
189
  } else if (error.message) {
190
- // Use the error object's message if no backend detail
191
- detailMessage = error.message;
192
  }
193
 
194
- toast.error(detailMessage); // Show the determined error message
 
 
 
 
 
 
 
 
 
 
 
195
 
196
  } finally {
 
 
 
 
 
 
 
 
 
 
 
197
  setIsSubmitting(false)
198
  setIsEditing(false)
199
  }
 
119
  if (sigmaInstance && sigmaGraph && rawGraph) {
120
  // Update the node in sigma graph
121
  if (sigmaGraph.hasNode(String(value))) {
122
+ try {
123
+ // Create a new node with the updated ID
124
+ const oldNodeAttributes = sigmaGraph.getNodeAttributes(String(value))
125
+
126
+ // Add a new node with the new ID but keep all other attributes
127
+ sigmaGraph.addNode(editValue, {
128
+ ...oldNodeAttributes,
129
+ label: editValue
130
+ })
131
+
132
+ // Copy all edges from the old node to the new node
133
+ sigmaGraph.forEachEdge(String(value), (edge, attributes, source, target) => {
134
+ const otherNode = source === String(value) ? target : source
135
+ const isOutgoing = source === String(value)
136
+
137
+ // Create a new edge with the same attributes but connected to the new node ID
138
+ if (isOutgoing) {
139
+ sigmaGraph.addEdge(editValue, otherNode, attributes)
140
+ } else {
141
+ sigmaGraph.addEdge(otherNode, editValue, attributes)
142
+ }
143
+
144
+ // Remove the old edge
145
+ sigmaGraph.dropEdge(edge)
146
+ })
147
+
148
+ // Remove the old node after all edges have been transferred
149
+ sigmaGraph.dropNode(String(value))
150
+
151
+ // Also update the node in the raw graph
152
+ const nodeIndex = rawGraph.nodeIdMap[String(value)]
153
+ if (nodeIndex !== undefined) {
154
+ rawGraph.nodes[nodeIndex].id = editValue
155
+ // Update the node ID map
156
+ delete rawGraph.nodeIdMap[String(value)]
157
+ rawGraph.nodeIdMap[editValue] = nodeIndex
158
+ }
159
 
160
+ // Refresh the sigma instance to reflect changes
161
+ sigmaInstance.refresh()
162
 
163
+ // Update selected node ID if it was the edited node
164
+ const selectedNode = useGraphStore.getState().selectedNode
165
+ if (selectedNode === String(value)) {
166
+ useGraphStore.getState().setSelectedNode(editValue)
167
+ }
168
+
169
+ // Update focused node ID if it was the edited node
170
+ const focusedNode = useGraphStore.getState().focusedNode
171
+ if (focusedNode === String(value)) {
172
+ useGraphStore.getState().setFocusedNode(editValue)
173
+ }
174
+ } catch (error) {
175
+ console.error('Error updating node ID in graph:', error)
176
+ throw new Error('Failed to update node ID in graph')
177
  }
178
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  }
180
  } else if (name === 'description') {
181
  // For description updates
 
200
  if (onValueChange) {
201
  onValueChange(editValue)
202
  }
203
+ } catch (error: any) {
204
  console.error('Error updating property:', error);
205
 
206
+ // 尝试提取更具体的错误信息
207
+ let detailMessage = t('graphPanel.propertiesView.errors.updateFailed');
208
+
209
  if (error.response?.data?.detail) {
210
+ detailMessage = error.response.data.detail;
211
+ } else if (error.response?.data?.message) {
212
+ detailMessage = error.response.data.message;
213
  } else if (error.message) {
214
+ detailMessage = error.message;
 
215
  }
216
 
217
+ // 记录详细的错误信息以便调试
218
+ console.error('Update failed:', {
219
+ entityType,
220
+ entityId,
221
+ propertyName: name,
222
+ newValue: editValue,
223
+ error: error.response?.data || error.message
224
+ });
225
+
226
+ toast.error(detailMessage, {
227
+ description: t('graphPanel.propertiesView.errors.tryAgainLater')
228
+ });
229
 
230
  } finally {
231
+ // Update the value immediately in the UI
232
+ if (onValueChange) {
233
+ onValueChange(editValue);
234
+ }
235
+ // Trigger graph data refresh
236
+ useGraphStore.getState().setGraphDataFetchAttempted(false);
237
+ useGraphStore.getState().setLabelsFetchAttempted(false);
238
+ // Re-select the node to refresh properties panel
239
+ const currentNodeId = name === 'entity_id' ? editValue : (entityId || '');
240
+ useGraphStore.getState().setSelectedNode(null);
241
+ useGraphStore.getState().setSelectedNode(currentNodeId);
242
  setIsSubmitting(false)
243
  setIsEditing(false)
244
  }
lightrag_webui/src/components/graph/GraphControl.tsx CHANGED
@@ -99,7 +99,10 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean })
99
  const events: Record<string, any> = {
100
  enterNode: (event: NodeEvent) => {
101
  if (!isButtonPressed(event.event.original)) {
102
- setFocusedNode(event.node)
 
 
 
103
  }
104
  },
105
  leaveNode: (event: NodeEvent) => {
@@ -108,8 +111,11 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean })
108
  }
109
  },
110
  clickNode: (event: NodeEvent) => {
111
- setSelectedNode(event.node)
112
- setSelectedEdge(null)
 
 
 
113
  },
114
  clickStage: () => clearSelection()
115
  }
 
99
  const events: Record<string, any> = {
100
  enterNode: (event: NodeEvent) => {
101
  if (!isButtonPressed(event.event.original)) {
102
+ const graph = sigma.getGraph()
103
+ if (graph.hasNode(event.node)) {
104
+ setFocusedNode(event.node)
105
+ }
106
  }
107
  },
108
  leaveNode: (event: NodeEvent) => {
 
111
  }
112
  },
113
  clickNode: (event: NodeEvent) => {
114
+ const graph = sigma.getGraph()
115
+ if (graph.hasNode(event.node)) {
116
+ setSelectedNode(event.node)
117
+ setSelectedEdge(null)
118
+ }
119
  },
120
  clickStage: () => clearSelection()
121
  }
lightrag_webui/src/locales/ar.json CHANGED
@@ -35,6 +35,32 @@
35
  "common": {
36
  "cancel": "إلغاء"
37
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  "documentPanel": {
39
  "clearDocuments": {
40
  "button": "مسح",
 
35
  "common": {
36
  "cancel": "إلغاء"
37
  },
38
+ "graphPanel": {
39
+ "propertiesView": {
40
+ "errors": {
41
+ "duplicateName": "اسم العقدة موجود بالفعل",
42
+ "updateFailed": "فشل تحديث العقدة",
43
+ "tryAgainLater": "يرجى المحاولة مرة أخرى لاحقاً"
44
+ },
45
+ "success": {
46
+ "entityUpdated": "تم تحديث العقدة بنجاح",
47
+ "relationUpdated": "تم تحديث العلاقة بنجاح"
48
+ },
49
+ "node": {
50
+ "title": "عقدة",
51
+ "id": "المعرف",
52
+ "labels": "التسميات",
53
+ "degree": "الدرجة",
54
+ "properties": "الخصائص",
55
+ "relationships": "العلاقات (ضمن الرسم البياني الفرعي)",
56
+ "expandNode": "توسيع العقدة",
57
+ "pruneNode": "تقليم العقدة",
58
+ "deleteAllNodesError": "رفض حذف جميع العقد في الرسم البياني",
59
+ "nodesRemoved": "تم حذف {{count}} عقدة، بما في ذلك العقد اليتيمة",
60
+ "noNewNodes": "لم يتم العثور على عقد قابلة للتوسيع"
61
+ }
62
+ }
63
+ },
64
  "documentPanel": {
65
  "clearDocuments": {
66
  "button": "مسح",
lightrag_webui/src/locales/en.json CHANGED
@@ -235,6 +235,15 @@
235
  "vectorStorage": "Vector Storage"
236
  },
237
  "propertiesView": {
 
 
 
 
 
 
 
 
 
238
  "node": {
239
  "title": "Node",
240
  "id": "ID",
 
235
  "vectorStorage": "Vector Storage"
236
  },
237
  "propertiesView": {
238
+ "errors": {
239
+ "duplicateName": "Node name already exists",
240
+ "updateFailed": "Failed to update node",
241
+ "tryAgainLater": "Please try again later"
242
+ },
243
+ "success": {
244
+ "entityUpdated": "Node updated successfully",
245
+ "relationUpdated": "Relation updated successfully"
246
+ },
247
  "node": {
248
  "title": "Node",
249
  "id": "ID",
lightrag_webui/src/locales/fr.json CHANGED
@@ -35,6 +35,32 @@
35
  "common": {
36
  "cancel": "Annuler"
37
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  "documentPanel": {
39
  "clearDocuments": {
40
  "button": "Effacer",
 
35
  "common": {
36
  "cancel": "Annuler"
37
  },
38
+ "graphPanel": {
39
+ "propertiesView": {
40
+ "errors": {
41
+ "duplicateName": "Le nom du nœud existe déjà",
42
+ "updateFailed": "Échec de la mise à jour du nœud",
43
+ "tryAgainLater": "Veuillez réessayer plus tard"
44
+ },
45
+ "success": {
46
+ "entityUpdated": "Nœud mis à jour avec succès",
47
+ "relationUpdated": "Relation mise à jour avec succès"
48
+ },
49
+ "node": {
50
+ "title": "Nœud",
51
+ "id": "ID",
52
+ "labels": "Étiquettes",
53
+ "degree": "Degré",
54
+ "properties": "Propriétés",
55
+ "relationships": "Relations(dans le sous-graphe)",
56
+ "expandNode": "Développer le nœud",
57
+ "pruneNode": "Élaguer le nœud",
58
+ "deleteAllNodesError": "Refus de supprimer tous les nœuds du graphe",
59
+ "nodesRemoved": "{{count}} nœuds supprimés, y compris les nœuds orphelins",
60
+ "noNewNodes": "Aucun nœud extensible trouvé"
61
+ }
62
+ }
63
+ },
64
  "documentPanel": {
65
  "clearDocuments": {
66
  "button": "Effacer",
lightrag_webui/src/locales/zh.json CHANGED
@@ -236,6 +236,15 @@
236
  "vectorStorage": "向量存储"
237
  },
238
  "propertiesView": {
 
 
 
 
 
 
 
 
 
239
  "node": {
240
  "title": "节点",
241
  "id": "ID",
 
236
  "vectorStorage": "向量存储"
237
  },
238
  "propertiesView": {
239
+ "errors": {
240
+ "duplicateName": "节点名称已存在",
241
+ "updateFailed": "更新节点失败",
242
+ "tryAgainLater": "请稍后重试"
243
+ },
244
+ "success": {
245
+ "entityUpdated": "节点更新成功",
246
+ "relationUpdated": "关系更新成功"
247
+ },
248
  "node": {
249
  "title": "节点",
250
  "id": "ID",