work on large entity extraction

This commit is contained in:
overcuriousity
2025-09-20 20:56:31 +02:00
parent 602739246f
commit b2c5d2331c
4 changed files with 241 additions and 61 deletions

View File

@@ -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);

View File

@@ -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;
}
}
}