38c5bcb606
## New features - Configurable bottom connection points per node (1–4 handles) - Fit view on load - LiveView improvements - Node modal: inline Type/Icon picker, default icon in trigger - Remove redundant Save button from ScanConfigModal ## Scanner fixes - Phase 1: replace nmap ARP sweep with concurrent asyncio ping sweep (50 parallel pings, 1s timeout). Zero false positives, works in any Docker network mode. Supplements with /proc/net/arp for ICMP-blocked devices. - Phase 2: explicit -sS (root) / -sT (non-root) scan type; bump host-timeout to 60s; gather(return_exceptions=True) so one failing host doesn't abort the batch - Fix 404 on missing device in hide/ignore - Validate CIDR ranges to prevent nmap injection - Thread-safe cancel set, pre-fetch canvas/hidden IPs (no N+1 queries) - Logging: attach StreamHandler to root logger so app.* logs are visible ## Tests - 21 backend scanner tests (ping sweep, ARP cache, Phase 2 tolerance) - Full NodeModal coverage (53 tests) - LiveView, store, edge label tests
46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
/**
|
|
* Bottom handle configuration for multi-handle nodes.
|
|
*
|
|
* Handle IDs: index 0 = 'bottom' (always the default, backward-compatible)
|
|
* index 1 = 'bottom-2', index 2 = 'bottom-3', index 3 = 'bottom-4'
|
|
*
|
|
* Invisible target handles follow the same pattern with a '-t' suffix:
|
|
* 'bottom-t', 'bottom-2-t', 'bottom-3-t', 'bottom-4-t'
|
|
*/
|
|
|
|
export const BOTTOM_HANDLE_IDS = ['bottom', 'bottom-2', 'bottom-3', 'bottom-4'] as const
|
|
|
|
/** Left % position for each handle slot, per count. */
|
|
export const BOTTOM_HANDLE_POSITIONS: Record<number, number[]> = {
|
|
1: [50],
|
|
2: [25, 75],
|
|
3: [20, 50, 80],
|
|
4: [15, 38, 62, 85],
|
|
}
|
|
|
|
/**
|
|
* Normalize a raw handle ID coming from a React Flow connection event.
|
|
* Invisible target handles (e.g. 'bottom-2-t') are mapped to their source
|
|
* counterpart ('bottom-2') so the stored edge ID is stable and consistent.
|
|
*/
|
|
export function normalizeHandle(h: string | null | undefined): string | null {
|
|
if (!h) return null
|
|
if (h === 'top-t') return 'top'
|
|
// 'bottom-t' → 'bottom', 'bottom-2-t' → 'bottom-2', etc.
|
|
const m = h.match(/^(bottom(?:-\d+)?)-t$/)
|
|
if (m) return m[1]
|
|
return h
|
|
}
|
|
|
|
/**
|
|
* Returns the set of handle IDs that are removed when bottom_handles
|
|
* is reduced from `oldCount` to `newCount`.
|
|
*/
|
|
export function removedBottomHandleIds(oldCount: number, newCount: number): Set<string> {
|
|
const removed = new Set<string>()
|
|
for (let i = newCount; i < oldCount; i++) {
|
|
removed.add(BOTTOM_HANDLE_IDS[i])
|
|
}
|
|
return removed
|
|
}
|