integrate checkbox filters
This commit is contained in:
parent
2658bd148b
commit
62470673fe
1
cache/crtsh/raptor_cc24_dev.json
vendored
Normal file
1
cache/crtsh/raptor_cc24_dev.json
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -328,41 +328,6 @@ input[type="text"]:focus, select:focus {
|
|||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-controls {
|
|
||||||
display: flex;
|
|
||||||
gap: 1.5rem;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-group {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-group label {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-group select,
|
|
||||||
.filter-group input[type="range"] {
|
|
||||||
background-color: #1a1a1a;
|
|
||||||
border: 1px solid #555;
|
|
||||||
color: #c7c7c7;
|
|
||||||
padding: 0.25rem 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-group select {
|
|
||||||
max-width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#confidence-value {
|
|
||||||
min-width: 30px;
|
|
||||||
text-align: center;
|
|
||||||
color: #00ff41;
|
|
||||||
}
|
|
||||||
|
|
||||||
.graph-container {
|
.graph-container {
|
||||||
height: 800px;
|
height: 800px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -397,6 +362,79 @@ input[type="text"]:focus, select:focus {
|
|||||||
background: rgba(42, 42, 42, 1);
|
background: rgba(42, 42, 42, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.graph-filter-panel {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 10px;
|
||||||
|
z-index: 10;
|
||||||
|
background: rgba(42, 42, 42, 0.9);
|
||||||
|
border: 1px solid #555;
|
||||||
|
color: #c7c7c7;
|
||||||
|
padding: 0.75rem;
|
||||||
|
font-family: 'Roboto Mono', monospace;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
max-height: 40%;
|
||||||
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-column {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-column h4 {
|
||||||
|
color: #00ff41;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
border-bottom: 1px solid #444;
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-column .checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-column label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-column label:hover {
|
||||||
|
color: #00ff41;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-column input[type="checkbox"] {
|
||||||
|
appearance: none;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border: 1px solid #555;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-column input[type="checkbox"]:checked {
|
||||||
|
background-color: #00ff41;
|
||||||
|
border-color: #00ff41;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-column input[type="checkbox"]:checked::after {
|
||||||
|
content: '✓';
|
||||||
|
position: absolute;
|
||||||
|
top: -3px;
|
||||||
|
left: 1px;
|
||||||
|
color: #1a1a1a;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.graph-context-menu {
|
.graph-context-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
@ -14,6 +14,7 @@ class GraphManager {
|
|||||||
this.nodeInfoPopup = null;
|
this.nodeInfoPopup = null;
|
||||||
this.contextMenu = null;
|
this.contextMenu = null;
|
||||||
this.history = [];
|
this.history = [];
|
||||||
|
this.filterPanel = null;
|
||||||
|
|
||||||
this.options = {
|
this.options = {
|
||||||
nodes: {
|
nodes: {
|
||||||
@ -177,6 +178,8 @@ class GraphManager {
|
|||||||
|
|
||||||
// Add graph controls
|
// Add graph controls
|
||||||
this.addGraphControls();
|
this.addGraphControls();
|
||||||
|
this.addFilterPanel();
|
||||||
|
|
||||||
|
|
||||||
console.log('Graph initialized successfully');
|
console.log('Graph initialized successfully');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -209,6 +212,12 @@ class GraphManager {
|
|||||||
document.getElementById('graph-revert').addEventListener('click', () => this.revertLastAction());
|
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
|
* Setup network event handlers
|
||||||
*/
|
*/
|
||||||
@ -354,6 +363,10 @@ class GraphManager {
|
|||||||
this.nodes.update(processedNodes);
|
this.nodes.update(processedNodes);
|
||||||
this.edges.update(processedEdges);
|
this.edges.update(processedEdges);
|
||||||
|
|
||||||
|
this.updateFilterControls();
|
||||||
|
this.applyAllFilters();
|
||||||
|
|
||||||
|
|
||||||
// Highlight new additions briefly
|
// Highlight new additions briefly
|
||||||
if (newNodes.length > 0 || newEdges.length > 0) {
|
if (newNodes.length > 0 || newEdges.length > 0) {
|
||||||
setTimeout(() => this.highlightNewElements(newNodes, newEdges), 100);
|
setTimeout(() => this.highlightNewElements(newNodes, newEdges), 100);
|
||||||
@ -922,48 +935,73 @@ class GraphManager {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
updateFilterControls() {
|
||||||
* Apply filters to the graph
|
if (!this.filterPanel) return;
|
||||||
* @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
|
const nodeTypes = new Set(this.nodes.get().map(n => n.type));
|
||||||
*/
|
const edgeTypes = new Set(this.edges.get().map(e => e.metadata.relationship_type));
|
||||||
applyFilters(nodeType, minConfidence) {
|
|
||||||
console.log(`Applying filters: nodeType=${nodeType}, minConfidence=${minConfidence}`);
|
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 nodeUpdates = [];
|
||||||
const edgeUpdates = [];
|
const edgeUpdates = [];
|
||||||
|
const visibleEdges = new Set();
|
||||||
|
|
||||||
const allNodes = this.nodes.get({ returnType: 'Object' });
|
this.edges.get().forEach(edge => {
|
||||||
const allEdges = this.edges.get();
|
const isVisible = !hiddenEdgeTypes.has(edge.metadata.relationship_type);
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
edgeUpdates.push({ id: edge.id, hidden: !isVisible });
|
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);
|
this.edges.update(edgeUpdates);
|
||||||
|
this.nodes.update(nodeUpdates);
|
||||||
console.log('Filters applied.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show context menu for a node
|
* Show context menu for a node
|
||||||
* @param {string} nodeId - The ID of the node
|
* @param {string} nodeId - The ID of the node
|
||||||
|
@ -83,11 +83,6 @@ class DNSReconApp {
|
|||||||
// Other elements
|
// Other elements
|
||||||
sessionId: document.getElementById('session-id'),
|
sessionId: document.getElementById('session-id'),
|
||||||
connectionStatus: document.getElementById('connection-status'),
|
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
|
// 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');
|
console.log('Event handlers set up successfully');
|
||||||
|
|
||||||
} catch (error) {
|
} 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
|
* Check if graph data has changed
|
||||||
* @param {Object} graphData - New graph data
|
* @param {Object} graphData - New graph data
|
||||||
|
@ -110,24 +110,6 @@
|
|||||||
<section class="visualization-panel">
|
<section class="visualization-panel">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>Infrastructure Map</h2>
|
<h2>Infrastructure Map</h2>
|
||||||
<div class="view-controls">
|
|
||||||
<div class="filter-group">
|
|
||||||
<label for="node-type-filter">Node Type:</label>
|
|
||||||
<select id="node-type-filter">
|
|
||||||
<option value="all">All</option>
|
|
||||||
<option value="domain">Domain</option>
|
|
||||||
<option value="ip">IP</option>
|
|
||||||
<option value="asn">ASN</option>
|
|
||||||
<option value="correlation_object">Correlation Object</option>
|
|
||||||
<option value="large_entity">Large Entity</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="filter-group">
|
|
||||||
<label for="confidence-filter">Min Confidence:</label>
|
|
||||||
<input type="range" id="confidence-filter" min="0" max="1" step="0.1" value="0">
|
|
||||||
<span id="confidence-value">0</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="network-graph" class="graph-container">
|
<div id="network-graph" class="graph-container">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user