integrate checkbox filters

This commit is contained in:
overcuriousity
2025-09-14 23:54:27 +02:00
parent 2658bd148b
commit 62470673fe
5 changed files with 146 additions and 111 deletions

View File

@@ -14,6 +14,7 @@ class GraphManager {
this.nodeInfoPopup = null;
this.contextMenu = null;
this.history = [];
this.filterPanel = null;
this.options = {
nodes: {
@@ -177,6 +178,8 @@ class GraphManager {
// Add graph controls
this.addGraphControls();
this.addFilterPanel();
console.log('Graph initialized successfully');
} catch (error) {
@@ -208,6 +211,12 @@ class GraphManager {
document.getElementById('graph-unhide').addEventListener('click', () => this.unhideAll());
document.getElementById('graph-revert').addEventListener('click', () => this.revertLastAction());
}
addFilterPanel() {
this.filterPanel = document.createElement('div');
this.filterPanel.className = 'graph-filter-panel';
this.container.appendChild(this.filterPanel);
}
/**
* Setup network event handlers
@@ -354,6 +363,10 @@ class GraphManager {
this.nodes.update(processedNodes);
this.edges.update(processedEdges);
this.updateFilterControls();
this.applyAllFilters();
// Highlight new additions briefly
if (newNodes.length > 0 || newEdges.length > 0) {
setTimeout(() => this.highlightNewElements(newNodes, newEdges), 100);
@@ -921,49 +934,74 @@ class GraphManager {
//isStabilized: this.network ? this.network.isStabilized() : false
};
}
updateFilterControls() {
if (!this.filterPanel) return;
/**
* Apply filters to the graph
* @param {string} nodeType - The type of node to show ('all' for no filter)
* @param {number} minConfidence - The minimum confidence score for edges to be visible
*/
applyFilters(nodeType, minConfidence) {
console.log(`Applying filters: nodeType=${nodeType}, minConfidence=${minConfidence}`);
const nodeTypes = new Set(this.nodes.get().map(n => n.type));
const edgeTypes = new Set(this.edges.get().map(e => e.metadata.relationship_type));
let nodeCheckboxes = '<div class="filter-column"><h4>Nodes</h4><div class="checkbox-group">';
nodeTypes.forEach(type => {
const label = type === 'correlation_object' ? 'latent correlations' : type;
const isChecked = type !== 'correlation_object';
nodeCheckboxes += `<label><input type="checkbox" data-filter-type="node" value="${type}" ${isChecked ? 'checked' : ''}> ${label}</label>`;
});
nodeCheckboxes += '</div></div>';
let edgeCheckboxes = '<div class="filter-column"><h4>Edges</h4><div class="checkbox-group">';
edgeTypes.forEach(type => {
edgeCheckboxes += `<label><input type="checkbox" data-filter-type="edge" value="${type}" checked> ${type}</label>`;
});
edgeCheckboxes += '</div></div>';
this.filterPanel.innerHTML = nodeCheckboxes + edgeCheckboxes;
this.filterPanel.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
checkbox.addEventListener('change', () => this.applyAllFilters());
});
}
applyAllFilters() {
const hiddenNodeTypes = new Set();
this.filterPanel.querySelectorAll('input[data-filter-type="node"]:not(:checked)').forEach(cb => {
hiddenNodeTypes.add(cb.value);
});
const hiddenEdgeTypes = new Set();
this.filterPanel.querySelectorAll('input[data-filter-type="edge"]:not(:checked)').forEach(cb => {
hiddenEdgeTypes.add(cb.value);
});
const nodeUpdates = [];
const edgeUpdates = [];
const visibleEdges = new Set();
const allNodes = this.nodes.get({ returnType: 'Object' });
const allEdges = this.edges.get();
// Determine which nodes are visible based on the nodeType filter
for (const nodeId in allNodes) {
const node = allNodes[nodeId];
const isVisible = (nodeType === 'all' || node.type === nodeType);
nodeUpdates.push({ id: nodeId, hidden: !isVisible });
}
// Update nodes first to determine edge visibility
this.nodes.update(nodeUpdates);
// Determine which edges are visible based on confidence and connected nodes
for (const edge of allEdges) {
const sourceNode = this.nodes.get(edge.from);
const targetNode = this.nodes.get(edge.to);
const confidence = edge.metadata ? edge.metadata.confidence_score : 0;
const isVisible = confidence >= minConfidence &&
sourceNode && !sourceNode.hidden &&
targetNode && !targetNode.hidden;
this.edges.get().forEach(edge => {
const isVisible = !hiddenEdgeTypes.has(edge.metadata.relationship_type);
edgeUpdates.push({ id: edge.id, hidden: !isVisible });
}
if (isVisible) {
visibleEdges.add(edge.id);
}
});
this.nodes.get().forEach(node => {
let isVisible = !hiddenNodeTypes.has(node.type);
if (isVisible) {
const connectedEdges = this.network.getConnectedEdges(node.id);
const hasVisibleConnection = connectedEdges.some(edgeId => visibleEdges.has(edgeId));
if (!hasVisibleConnection && connectedEdges.length > 0) {
isVisible = false;
}
}
nodeUpdates.push({ id: node.id, hidden: !isVisible });
});
this.edges.update(edgeUpdates);
console.log('Filters applied.');
this.nodes.update(nodeUpdates);
}
/**
* Show context menu for a node
* @param {string} nodeId - The ID of the node

View File

@@ -83,11 +83,6 @@ class DNSReconApp {
// Other elements
sessionId: document.getElementById('session-id'),
connectionStatus: document.getElementById('connection-status'),
// Filter elements
nodeTypeFilter: document.getElementById('node-type-filter'),
confidenceFilter: document.getElementById('confidence-filter'),
confidenceValue: document.getElementById('confidence-value')
};
// Verify critical elements exist
@@ -211,13 +206,6 @@ class DNSReconApp {
}
});
// Filter events
this.elements.nodeTypeFilter.addEventListener('change', () => this.applyFilters());
this.elements.confidenceFilter.addEventListener('input', () => {
this.elements.confidenceValue.textContent = this.elements.confidenceFilter.value;
this.applyFilters();
});
console.log('Event handlers set up successfully');
} catch (error) {
@@ -1043,18 +1031,6 @@ class DNSReconApp {
});
}
/**
* Apply graph filters
*/
applyFilters() {
if (this.graphManager) {
const nodeType = this.elements.nodeTypeFilter.value;
const minConfidence = parseFloat(this.elements.confidenceFilter.value);
this.graphManager.applyFilters(nodeType, minConfidence);
}
}
/**
* Check if graph data has changed
* @param {Object} graphData - New graph data