revert graph.js refactor
This commit is contained in:
parent
2496ca26a5
commit
30ee21f087
@ -1290,114 +1290,115 @@ class GraphManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enhanced hide operation using true root detection
|
* Hide a node and recursively hide any neighbors that become disconnected.
|
||||||
* @param {string} nodeId - The ID of the node to start hiding from
|
* @param {string} nodeId - The ID of the node to start hiding from.
|
||||||
*/
|
*/
|
||||||
hideNodeAndOrphans(nodeId) {
|
hideNodeAndOrphans(nodeId) {
|
||||||
const historyData = { nodeIds: [] };
|
const historyData = { nodeIds: [] };
|
||||||
|
const queue = [nodeId];
|
||||||
|
const visited = new Set([nodeId]);
|
||||||
|
|
||||||
// Step 1: Hide the target node
|
while (queue.length > 0) {
|
||||||
this.nodes.update({ id: nodeId, hidden: true });
|
const currentId = queue.shift();
|
||||||
historyData.nodeIds.push(nodeId);
|
const node = this.nodes.get(currentId);
|
||||||
|
if (!node || node.hidden) continue;
|
||||||
|
|
||||||
// Step 2: Recompute what should remain visible using true root detection
|
// 1. Hide the current node and add to history
|
||||||
const remainingVisible = this.computeReachableFromRoots();
|
this.nodes.update({ id: currentId, hidden: true });
|
||||||
|
historyData.nodeIds.push(currentId);
|
||||||
|
|
||||||
// Step 3: Hide any nodes that are no longer reachable
|
// 2. Check its neighbors
|
||||||
const allNodes = this.nodes.get();
|
const neighbors = this.network.getConnectedNodes(currentId);
|
||||||
allNodes.forEach(node => {
|
for (const neighborId of neighbors) {
|
||||||
if (!node.hidden && !remainingVisible.has(node.id) && node.id !== nodeId) {
|
if (visited.has(neighborId)) continue;
|
||||||
this.nodes.update({ id: node.id, hidden: true });
|
|
||||||
historyData.nodeIds.push(node.id);
|
const connectedEdges = this.network.getConnectedEdges(neighborId);
|
||||||
|
let hasVisibleEdge = false;
|
||||||
|
// 3. See if the neighbor still has any visible connections
|
||||||
|
for (const edgeId of connectedEdges) {
|
||||||
|
const edge = this.edges.get(edgeId);
|
||||||
|
const sourceNode = this.nodes.get(edge.from);
|
||||||
|
const targetNode = this.nodes.get(edge.to);
|
||||||
|
if ((sourceNode && !sourceNode.hidden) && (targetNode && !targetNode.hidden)) {
|
||||||
|
hasVisibleEdge = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. If no visible connections, add to queue to be hidden
|
||||||
|
if (!hasVisibleEdge) {
|
||||||
|
queue.push(neighborId);
|
||||||
|
visited.add(neighborId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (historyData.nodeIds.length > 0) {
|
if (historyData.nodeIds.length > 0) {
|
||||||
this.addToHistory('hide', historyData);
|
this.addToHistory('hide', historyData);
|
||||||
console.log(`Hidden ${historyData.nodeIds.length} nodes using true root detection`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enhanced delete operation using true root detection
|
* Delete a node and recursively delete any neighbors that become disconnected.
|
||||||
* @param {string} nodeId - The ID of the node to start deleting from
|
* @param {string} nodeId - The ID of the node to start deleting from.
|
||||||
*/
|
*/
|
||||||
async deleteNodeAndOrphans(nodeId) {
|
async deleteNodeAndOrphans(nodeId) {
|
||||||
|
const deletionQueue = [nodeId];
|
||||||
|
const processedForDeletion = new Set([nodeId]);
|
||||||
const historyData = { nodes: [], edges: [] };
|
const historyData = { nodes: [], edges: [] };
|
||||||
let operationFailed = false;
|
let operationFailed = false;
|
||||||
|
|
||||||
// Step 1: Store current state and delete target node
|
while (deletionQueue.length > 0) {
|
||||||
const targetNode = this.nodes.get(nodeId);
|
const currentId = deletionQueue.shift();
|
||||||
const connectedEdgeIds = this.network.getConnectedEdges(nodeId);
|
const node = this.nodes.get(currentId);
|
||||||
const connectedEdges = this.edges.get(connectedEdgeIds);
|
if (!node) continue;
|
||||||
|
|
||||||
if (targetNode) {
|
const neighbors = this.network.getConnectedNodes(currentId);
|
||||||
historyData.nodes.push(targetNode);
|
const connectedEdgeIds = this.network.getConnectedEdges(currentId);
|
||||||
historyData.edges.push(...connectedEdges);
|
const edges = this.edges.get(connectedEdgeIds);
|
||||||
}
|
|
||||||
|
// Store state for potential revert
|
||||||
|
historyData.nodes.push(node);
|
||||||
|
historyData.edges.push(...edges);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Delete from backend first
|
const response = await fetch(`/api/graph/node/${currentId}`, { method: 'DELETE' });
|
||||||
const response = await fetch(`/api/graph/node/${nodeId}`, { method: 'DELETE' });
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.error || 'Failed to delete node from backend');
|
console.error(`Failed to delete node ${currentId} from backend:`, result.error);
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from frontend
|
|
||||||
this.nodes.remove({ id: nodeId });
|
|
||||||
console.log(`Node ${nodeId} deleted from backend and frontend`);
|
|
||||||
|
|
||||||
// Step 2: Identify orphaned nodes using true root detection
|
|
||||||
const reachableNodes = this.computeReachableFromRoots();
|
|
||||||
const allRemainingNodes = this.nodes.get().filter(node => node.id !== nodeId);
|
|
||||||
|
|
||||||
// Step 3: Delete orphaned nodes
|
|
||||||
const orphanedNodes = allRemainingNodes.filter(node => !reachableNodes.has(node.id));
|
|
||||||
|
|
||||||
for (const orphanNode of orphanedNodes) {
|
|
||||||
try {
|
|
||||||
const orphanEdgeIds = this.network.getConnectedEdges(orphanNode.id);
|
|
||||||
const orphanEdges = this.edges.get(orphanEdgeIds);
|
|
||||||
|
|
||||||
// Store for history
|
|
||||||
historyData.nodes.push(orphanNode);
|
|
||||||
historyData.edges.push(...orphanEdges);
|
|
||||||
|
|
||||||
// Delete from backend
|
|
||||||
const orphanResponse = await fetch(`/api/graph/node/${orphanNode.id}`, { method: 'DELETE' });
|
|
||||||
const orphanResult = await orphanResponse.json();
|
|
||||||
|
|
||||||
if (!orphanResult.success) {
|
|
||||||
console.warn(`Failed to delete orphaned node ${orphanNode.id}:`, orphanResult.error);
|
|
||||||
// Continue with other orphans rather than failing entirely
|
|
||||||
} else {
|
|
||||||
// Remove from frontend
|
|
||||||
this.nodes.remove({ id: orphanNode.id });
|
|
||||||
console.log(`Orphaned node ${orphanNode.id} deleted`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error deleting orphaned node ${orphanNode.id}:`, error);
|
|
||||||
// Continue with other orphans
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Deleted ${orphanedNodes.length + 1} nodes using true root detection`);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error during node deletion:', error);
|
|
||||||
operationFailed = true;
|
operationFailed = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to history only if primary deletion succeeded
|
console.log(`Node ${currentId} deleted from backend.`);
|
||||||
|
this.nodes.remove({ id: currentId }); // Remove from view
|
||||||
|
|
||||||
|
// Check if former neighbors are now orphans
|
||||||
|
neighbors.forEach(neighborId => {
|
||||||
|
if (!processedForDeletion.has(neighborId) && this.nodes.get(neighborId)) {
|
||||||
|
if (this.network.getConnectedEdges(neighborId).length === 0) {
|
||||||
|
deletionQueue.push(neighborId);
|
||||||
|
processedForDeletion.add(neighborId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during node deletion API call:', error);
|
||||||
|
operationFailed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to history only if the entire operation was successful
|
||||||
if (!operationFailed && historyData.nodes.length > 0) {
|
if (!operationFailed && historyData.nodes.length > 0) {
|
||||||
// Ensure edges in history are unique
|
// Ensure edges in history are unique
|
||||||
historyData.edges = Array.from(new Map(historyData.edges.map(e => [e.id, e])).values());
|
historyData.edges = Array.from(new Map(historyData.edges.map(e => [e.id, e])).values());
|
||||||
this.addToHistory('delete', historyData);
|
this.addToHistory('delete', historyData);
|
||||||
} else if (operationFailed) {
|
} else if (operationFailed) {
|
||||||
console.log("Reverting UI changes due to failed delete operation");
|
console.log("Reverting UI changes due to failed delete operation.");
|
||||||
// Restore the UI to original state
|
// If any part of the chain failed, restore the UI to its original state
|
||||||
this.nodes.add(historyData.nodes);
|
this.nodes.add(historyData.nodes);
|
||||||
this.edges.add(historyData.edges);
|
this.edges.add(historyData.edges);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user