extract from node feature
This commit is contained in:
@@ -389,8 +389,8 @@ class GraphManager {
|
||||
});
|
||||
|
||||
const filteredNodes = graphData.nodes.filter(node => {
|
||||
// Only include nodes that are NOT members of large entities
|
||||
return !this.largeEntityMembers.has(node.id);
|
||||
// Only include nodes that are NOT members of large entities, but always include the container itself
|
||||
return !this.largeEntityMembers.has(node.id) || node.type === 'large_entity';
|
||||
});
|
||||
|
||||
console.log(`Filtered ${graphData.nodes.length - filteredNodes.length} large entity member nodes from visualization`);
|
||||
|
||||
@@ -189,7 +189,7 @@ class DNSReconApp {
|
||||
this.elements.resetApiKeys.addEventListener('click', () => this.resetApiKeys());
|
||||
}
|
||||
|
||||
// ** FIX: Listen for the custom event from the graph **
|
||||
// Listen for the custom event from the graph
|
||||
document.addEventListener('nodeSelected', (e) => {
|
||||
this.showNodeModal(e.detail.node);
|
||||
});
|
||||
@@ -1092,8 +1092,6 @@ class DNSReconApp {
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
|
||||
generateLargeEntityDetails(node) {
|
||||
const attributes = node.attributes || {};
|
||||
const nodes = attributes.nodes || [];
|
||||
@@ -1123,16 +1121,23 @@ class DNSReconApp {
|
||||
</div>
|
||||
|
||||
<div class="modal-section">
|
||||
<details>
|
||||
<details open>
|
||||
<summary>📋 Contained ${nodeType}s (${nodes.length})</summary>
|
||||
<div class="modal-section-content">
|
||||
<div class="relationship-compact">
|
||||
`;
|
||||
|
||||
// Use node.id for the large_entity_id
|
||||
const largeEntityId = node.id;
|
||||
|
||||
nodes.forEach(innerNodeId => {
|
||||
html += `
|
||||
<div class="relationship-compact-item">
|
||||
<span class="node-link-compact" data-node-id="${innerNodeId}">${innerNodeId}</span>
|
||||
<button class="btn-icon-small extract-node-btn"
|
||||
title="Extract to graph"
|
||||
data-large-entity-id="${largeEntityId}"
|
||||
data-node-id="${innerNodeId}">[+]</button>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
@@ -1731,6 +1736,20 @@ class DNSReconApp {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle the new extract button
|
||||
this.elements.modalDetails.querySelectorAll('.extract-node-btn').forEach(button => {
|
||||
button.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const largeEntityId = e.target.dataset.largeEntityId;
|
||||
const nodeId = e.target.dataset.nodeId;
|
||||
|
||||
console.log(`Extract button clicked for node ${nodeId} from entity ${largeEntityId}`);
|
||||
this.extractNode(largeEntityId, nodeId);
|
||||
});
|
||||
});
|
||||
|
||||
// Handle legacy node links
|
||||
this.elements.modalDetails.querySelectorAll('.node-link').forEach(link => {
|
||||
@@ -1749,17 +1768,56 @@ class DNSReconApp {
|
||||
});
|
||||
}
|
||||
|
||||
async extractNode(largeEntityId, nodeId) {
|
||||
try {
|
||||
this.showInfo(`Extraction initiated for ${nodeId}. It will be processed by the scanner.`);
|
||||
const response = await this.apiCall('/api/graph/large-entity/extract', 'POST', {
|
||||
large_entity_id: largeEntityId,
|
||||
node_id: nodeId,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
this.showSuccess(response.message);
|
||||
|
||||
// The node is now in the queue. We don't need to force a graph update.
|
||||
// Instead, we just need to update the modal view to show one less item.
|
||||
const graphResponse = await this.apiCall('/api/graph');
|
||||
if (graphResponse.success) {
|
||||
const updatedLargeEntity = graphResponse.graph.nodes.find(n => n.id === largeEntityId);
|
||||
if (updatedLargeEntity) {
|
||||
this.showNodeModal(updatedLargeEntity);
|
||||
} else {
|
||||
// The entity might have been dismantled completely if it was the last node
|
||||
this.hideModal();
|
||||
}
|
||||
}
|
||||
|
||||
// If the scanner was idle, it's now running. Start polling.
|
||||
if (this.scanStatus === 'idle') {
|
||||
this.startPolling(1000);
|
||||
}
|
||||
|
||||
} 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}`);
|
||||
}
|
||||
}
|
||||
|
||||
initializeModalFunctionality() {
|
||||
// Make sure the graph manager has node access
|
||||
console.log('Initializing modal functionality...');
|
||||
|
||||
// Set up event delegation for dynamic content
|
||||
document.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('node-link-compact') || e.target.classList.contains('node-link')) {
|
||||
const target = e.target.closest('.node-link-compact, .node-link');
|
||||
if (target) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const nodeId = e.target.dataset.nodeId || e.target.getAttribute('data-node-id');
|
||||
const nodeId = target.dataset.nodeId || target.getAttribute('data-node-id');
|
||||
if (nodeId && this.graphManager && this.graphManager.nodes) {
|
||||
const nextNode = this.graphManager.nodes.get(nodeId);
|
||||
if (nextNode) {
|
||||
|
||||
Reference in New Issue
Block a user