diff --git a/.gitignore b/.gitignore index 76e2610..1918beb 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ Thumbs.db # Editor .vscode/ *.swp + +# Logs +*.log diff --git a/backend/app/routers/formboard.py b/backend/app/routers/formboard.py index 9398945..db42978 100644 --- a/backend/app/routers/formboard.py +++ b/backend/app/routers/formboard.py @@ -54,41 +54,87 @@ def get_layout(diagram_id: int, db: Session = Depends(get_db)): @router.post("/{diagram_id}/sync") def sync_from_diagram(diagram_id: int, db: Session = Depends(get_db)): - """Import all devices from the main diagram as connector nodes. - Existing nodes (matched by device_id) are label-synced but not moved.""" + """Sync devices as connector nodes and build segments from wire connections. + + Layout strategy: + - Connectors alternate above/below a central trunk line (y=100 / y=300) + - Segments are auto-created for each unique device-pair connected by wires, + with wire_ids populated so thickness reflects the bundle size. + Existing nodes are label-synced but not moved; existing segments are not duplicated. + """ diagram = db.query(models.Diagram).filter_by(id=diagram_id).first() if not diagram: raise HTTPException(404, "Diagram not found") layout = _get_or_create(diagram_id, db) existing_dev_ids = {n.device_id for n in layout.nodes if n.device_id is not None} + dev_to_node: dict = {n.device_id: n for n in layout.nodes if n.device_id is not None} added = 0 - x = 80 - for dev in diagram.devices: + new_x = 80 + len([n for n in layout.nodes if n.device_id is not None]) * 200 + + for i, dev in enumerate(diagram.devices): + label = dev.reference or dev.label or f"Dev {dev.id}" if dev.id in existing_dev_ids: - # Keep label in sync if the node label is still the default - node = next((n for n in layout.nodes if n.device_id == dev.id), None) - if node: - new_label = dev.reference or dev.label or f"Dev {dev.id}" - if not node.label or node.label == f"Dev {dev.id}": - node.label = new_label + node = dev_to_node[dev.id] + if not node.label or node.label == f"Dev {dev.id}": + node.label = label + else: + # Alternate connectors above (y=80) and below (y=320) the trunk + row_y = 80 if added % 2 == 0 else 320 + node = models.FormboardNode( + layout_id=layout.id, + node_type="connector", + device_id=dev.id, + x=new_x, y=row_y, + label=label, + ) + db.add(node) + db.flush() # get node.id + dev_to_node[dev.id] = node + new_x += 200 + added += 1 + + # Build segments from wire connections + # Group wires by (min_dev_id, max_dev_id) pair to avoid direction duplicates + from collections import defaultdict + pair_wires: dict = defaultdict(list) + for wire in diagram.wires: + a, b = wire.from_device_id, wire.to_device_id + if a and b and a != b: + pair_wires[(min(a, b), max(a, b))].append(wire.id) + + # Find existing segments by node-pair to avoid duplicates + existing_seg_pairs = set() + for seg in layout.segments: + existing_seg_pairs.add((min(seg.from_node_id, seg.to_node_id), + max(seg.from_node_id, seg.to_node_id))) + + segs_added = 0 + for (dev_a, dev_b), wire_ids in pair_wires.items(): + node_a = dev_to_node.get(dev_a) + node_b = dev_to_node.get(dev_b) + if not node_a or not node_b: continue - node = models.FormboardNode( + pair = (min(node_a.id, node_b.id), max(node_a.id, node_b.id)) + if pair in existing_seg_pairs: + continue + seg = models.FormboardSegment( layout_id=layout.id, - node_type="connector", - device_id=dev.id, - x=x, y=180, - label=dev.reference or dev.label or f"Dev {dev.id}", + from_node_id=node_a.id, + to_node_id=node_b.id, + wire_ids=wire_ids, + fitting_type="open", ) - db.add(node) - x += 200 - added += 1 + db.add(seg) + existing_seg_pairs.add(pair) + segs_added += 1 db.commit() db.refresh(layout) return { "added": added, + "segs_added": segs_added, "nodes": [_nd(n) for n in layout.nodes], "segments": [_sd(s) for s in layout.segments], } diff --git a/frontend/css/main.css b/frontend/css/main.css index 3757172..f96c9de 100644 --- a/frontend/css/main.css +++ b/frontend/css/main.css @@ -280,7 +280,7 @@ button:active { background: #1a1a3a; } .conn-edit-btn:hover { background: #2a2a5a; border-color: #6666aa; } /* ── Modal ───────────────────────────────────────────────────────────────── */ -#connector-modal, #drc-modal, #git-modal { +#connector-modal, #drc-modal, #git-modal, #pinout-modal { position: fixed; inset: 0; background: rgba(0,0,0,0.65); z-index: 1000; align-items: center; justify-content: center; } diff --git a/frontend/index.html b/frontend/index.html index f6823eb..ee586c3 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -230,6 +230,9 @@ +