Files
ThreatHunt/_edit_networkmap_hit.py
mblanke 5a2ad8ec1c feat: Add Playbook Manager, Saved Searches, and Timeline View components
- Implemented PlaybookManager for creating and managing investigation playbooks with templates.
- Added SavedSearches component for managing bookmarked queries and recurring scans.
- Introduced TimelineView for visualizing forensic event timelines with zoomable charts.
- Enhanced backend processing with auto-queued jobs for dataset uploads and improved database concurrency.
- Updated frontend components for better user experience and performance optimizations.
- Documented changes in update log for future reference.
2026-02-23 14:23:07 -05:00

60 lines
2.1 KiB
Python

from pathlib import Path
p=Path(r'd:/Projects/Dev/ThreatHunt/frontend/src/components/NetworkMap.tsx')
t=p.read_text(encoding='utf-8')
insert='''
function isPointOnNodeLabel(node: GNode, wx: number, wy: number, vp: Viewport): boolean {
const fontSize = Math.max(9, Math.round(12 / vp.scale));
const approxCharW = Math.max(5, fontSize * 0.58);
const line1 = node.label || '';
const line2 = node.meta.ips.length > 0 ? node.meta.ips[0] : '';
const tw = Math.max(line1.length * approxCharW, line2 ? line2.length * approxCharW : 0);
const px = 5, py = 2;
const totalH = line2 ? fontSize * 2 + py * 2 : fontSize + py * 2;
const lx = node.x, ly = node.y - node.radius - 6;
const rx = lx - tw / 2 - px;
const ry = ly - totalH;
const rw = tw + px * 2;
const rh = totalH;
return wx >= rx && wx <= (rx + rw) && wy >= ry && wy <= (ry + rh);
}
'''
if 'function isPointOnNodeLabel' not in t:
t=t.replace('// == Hit-test =============================================================\n', '// == Hit-test =============================================================\n'+insert)
old='''function hitTest(
graph: Graph, canvas: HTMLCanvasElement, clientX: number, clientY: number, vp: Viewport,
): GNode | null {
const { wx, wy } = screenToWorld(canvas, clientX, clientY, vp);
for (const n of graph.nodes) {
const dx = n.x - wx, dy = n.y - wy;
if (dx * dx + dy * dy < (n.radius + 5) ** 2) return n;
}
return null;
}
'''
new='''function hitTest(
graph: Graph, canvas: HTMLCanvasElement, clientX: number, clientY: number, vp: Viewport,
): GNode | null {
const { wx, wy } = screenToWorld(canvas, clientX, clientY, vp);
// Node-circle hit has priority
for (const n of graph.nodes) {
const dx = n.x - wx, dy = n.y - wy;
if (dx * dx + dy * dy < (n.radius + 5) ** 2) return n;
}
// Then label hit (so clicking text works too)
for (const n of graph.nodes) {
if (isPointOnNodeLabel(n, wx, wy, vp)) return n;
}
return null;
}
'''
if old not in t:
raise SystemExit('hitTest block not found')
t=t.replace(old,new)
p.write_text(t,encoding='utf-8')
print('updated NetworkMap hit-test for labels')