work on large entity extraction
This commit is contained in:
@@ -353,9 +353,6 @@ class GraphManager {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} graphData - Graph data from backend
|
||||
*/
|
||||
updateGraph(graphData) {
|
||||
if (!graphData || !graphData.nodes || !graphData.edges) {
|
||||
console.warn('Invalid graph data received');
|
||||
@@ -382,16 +379,18 @@ class GraphManager {
|
||||
|
||||
const nodeMap = new Map(graphData.nodes.map(node => [node.id, node]));
|
||||
|
||||
// Filter out hidden nodes before processing for rendering
|
||||
const filteredNodes = graphData.nodes.filter(node =>
|
||||
!(node.metadata && node.metadata.large_entity_id)
|
||||
);
|
||||
|
||||
// FIXED: Process all nodes first, then apply hiding logic correctly
|
||||
const processedNodes = graphData.nodes.map(node => {
|
||||
const processed = this.processNode(node);
|
||||
|
||||
// FIXED: Only hide if node is still a large entity member
|
||||
if (node.metadata && node.metadata.large_entity_id) {
|
||||
processed.hidden = true;
|
||||
} else {
|
||||
// FIXED: Ensure extracted nodes are visible
|
||||
processed.hidden = false;
|
||||
}
|
||||
|
||||
return processed;
|
||||
});
|
||||
|
||||
@@ -401,6 +400,7 @@ class GraphManager {
|
||||
let fromId = edge.from;
|
||||
let toId = edge.to;
|
||||
|
||||
// FIXED: Only re-route if nodes are STILL in large entities
|
||||
if (fromNode && fromNode.metadata && fromNode.metadata.large_entity_id) {
|
||||
fromId = fromNode.metadata.large_entity_id;
|
||||
}
|
||||
@@ -423,6 +423,7 @@ class GraphManager {
|
||||
const newNodes = processedNodes.filter(node => !existingNodeIds.includes(node.id));
|
||||
const newEdges = processedEdges.filter(edge => !existingEdgeIds.includes(edge.id));
|
||||
|
||||
// FIXED: Update all nodes to ensure extracted nodes become visible
|
||||
this.nodes.update(processedNodes);
|
||||
this.edges.update(processedEdges);
|
||||
|
||||
|
||||
@@ -2023,6 +2023,16 @@ class DNSReconApp {
|
||||
|
||||
async extractNode(largeEntityId, nodeId) {
|
||||
try {
|
||||
console.log(`Extracting node ${nodeId} from large entity ${largeEntityId}`);
|
||||
|
||||
// Show immediate feedback
|
||||
const button = document.querySelector(`[data-node-id="${nodeId}"][data-large-entity-id="${largeEntityId}"]`);
|
||||
if (button) {
|
||||
const originalContent = button.innerHTML;
|
||||
button.innerHTML = '[...]';
|
||||
button.disabled = true;
|
||||
}
|
||||
|
||||
const response = await this.apiCall('/api/graph/large-entity/extract', 'POST', {
|
||||
large_entity_id: largeEntityId,
|
||||
node_id: nodeId,
|
||||
@@ -2031,41 +2041,46 @@ class DNSReconApp {
|
||||
if (response.success) {
|
||||
this.showSuccess(response.message);
|
||||
|
||||
// If the scanner was idle, it's now running. Start polling to see the new node appear.
|
||||
if (this.scanStatus === 'idle') {
|
||||
this.startPolling(1000);
|
||||
} else {
|
||||
// If already scanning, force a quick graph update to see the change sooner.
|
||||
setTimeout(() => this.updateGraph(), 500);
|
||||
}
|
||||
|
||||
// Immediately update the modal view
|
||||
if (this.graphManager) {
|
||||
const largeEntityNode = this.graphManager.nodes.get(largeEntityId);
|
||||
if (largeEntityNode && largeEntityNode.attributes) {
|
||||
|
||||
// Find and update the 'nodes' attribute
|
||||
const nodesAttribute = largeEntityNode.attributes.find(attr => attr.name === 'nodes');
|
||||
if (nodesAttribute && Array.isArray(nodesAttribute.value)) {
|
||||
nodesAttribute.value = nodesAttribute.value.filter(id => id !== nodeId);
|
||||
// FIXED: Don't update local modal data - let backend be source of truth
|
||||
// Force immediate graph update to get fresh backend data
|
||||
console.log('Extraction successful, updating graph with fresh backend data');
|
||||
await this.updateGraph();
|
||||
|
||||
// FIXED: Re-fetch graph data instead of manipulating local state
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const graphResponse = await this.apiCall('/api/graph');
|
||||
if (graphResponse.success) {
|
||||
this.graphManager.updateGraph(graphResponse.graph);
|
||||
|
||||
// Update modal with fresh data if still open
|
||||
if (this.elements.nodeModal && this.elements.nodeModal.style.display === 'block') {
|
||||
if (this.graphManager.nodes) {
|
||||
const updatedLargeEntity = this.graphManager.nodes.get(largeEntityId);
|
||||
if (updatedLargeEntity) {
|
||||
this.showNodeModal(updatedLargeEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find and update the 'count' attribute
|
||||
const countAttribute = largeEntityNode.attributes.find(attr => attr.name === 'count');
|
||||
if (countAttribute) {
|
||||
countAttribute.value = (countAttribute.value || 0) - 1;
|
||||
}
|
||||
|
||||
// Re-render the modal with the updated data
|
||||
this.showNodeModal(largeEntityNode);
|
||||
} catch (error) {
|
||||
console.error('Error refreshing graph after extraction:', error);
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
|
||||
} else {
|
||||
throw new Error(response.error || 'Extraction failed on the server.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to extract node:', error);
|
||||
this.showError(`Extraction failed: ${error.message}`);
|
||||
|
||||
// Restore button state on error
|
||||
const button = document.querySelector(`[data-node-id="${nodeId}"][data-large-entity-id="${largeEntityId}"]`);
|
||||
if (button) {
|
||||
button.innerHTML = '[+]';
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user