e4a80dc0e6
- Roadmap #22: File→Import JSON to restore a diagram (drag-drop or file picker) - Roadmap #23: Duplicate diagram from diagram list - Roadmap #24: DRC panel with collapsible categories (unconnected pins, dup refs, no length, no P/N) - Multi-view tabs: named views per diagram with independent device/wire layouts; snapshot-on-entry prevents bleed - Keyboard arrow nudge for selected device(s) - Undo for move, duplicate, label/property changes - Wire jump arcs toggle (⌒ Jumps button in toolbar) - Shift+click multi-wire selection; right-click bulk clear waypoints or auto-route - Auto-route: obstacle-avoiding ortho routing for single or bulk selected wires - Delete view tab with × button; right-click context menu for rename/delete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
78 lines
2.9 KiB
Python
78 lines
2.9 KiB
Python
from typing import List
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
from .. import models, schemas
|
|
from ..database import get_db
|
|
|
|
router = APIRouter(tags=["views"])
|
|
|
|
|
|
@router.get("/diagram/{diagram_id}", response_model=List[schemas.DiagramViewOut])
|
|
def list_views(diagram_id: int, db: Session = Depends(get_db)):
|
|
return db.query(models.DiagramView).filter(models.DiagramView.diagram_id == diagram_id).order_by(models.DiagramView.created_at).all()
|
|
|
|
|
|
@router.post("/", response_model=schemas.DiagramViewOut, status_code=201)
|
|
def create_view(payload: schemas.DiagramViewCreate, db: Session = Depends(get_db)):
|
|
view = models.DiagramView(**payload.model_dump())
|
|
db.add(view)
|
|
db.commit()
|
|
db.refresh(view)
|
|
return view
|
|
|
|
|
|
@router.patch("/{view_id}", response_model=schemas.DiagramViewOut)
|
|
def update_view(view_id: int, payload: schemas.DiagramViewUpdate, db: Session = Depends(get_db)):
|
|
view = db.get(models.DiagramView, view_id)
|
|
if not view:
|
|
raise HTTPException(404, "View not found")
|
|
for k, v in payload.model_dump(exclude_unset=True).items():
|
|
setattr(view, k, v)
|
|
db.commit()
|
|
db.refresh(view)
|
|
return view
|
|
|
|
|
|
@router.delete("/{view_id}", status_code=204)
|
|
def delete_view(view_id: int, db: Session = Depends(get_db)):
|
|
view = db.get(models.DiagramView, view_id)
|
|
if not view:
|
|
raise HTTPException(404, "View not found")
|
|
db.delete(view)
|
|
db.commit()
|
|
|
|
|
|
@router.get("/{view_id}/layout", response_model=schemas.ViewLayout)
|
|
def get_view_layout(view_id: int, db: Session = Depends(get_db)):
|
|
view = db.get(models.DiagramView, view_id)
|
|
if not view:
|
|
raise HTTPException(404, "View not found")
|
|
pos = {p.device_id: {"x": p.x, "y": p.y} for p in view.device_positions}
|
|
waypts = {w.wire_id: (w.waypoints or []) for w in view.wire_waypoints}
|
|
return {"device_positions": pos, "wire_waypoints": waypts}
|
|
|
|
|
|
@router.patch("/{view_id}/devices/{device_id}")
|
|
def update_view_device_position(view_id: int, device_id: int, payload: schemas.ViewDevicePositionUpdate, db: Session = Depends(get_db)):
|
|
pos = db.query(models.ViewDevicePosition).filter_by(view_id=view_id, device_id=device_id).first()
|
|
if pos:
|
|
pos.x = payload.x
|
|
pos.y = payload.y
|
|
else:
|
|
pos = models.ViewDevicePosition(view_id=view_id, device_id=device_id, x=payload.x, y=payload.y)
|
|
db.add(pos)
|
|
db.commit()
|
|
return {"ok": True}
|
|
|
|
|
|
@router.patch("/{view_id}/wires/{wire_id}")
|
|
def update_view_wire_waypoints(view_id: int, wire_id: int, payload: schemas.ViewWireWaypointsUpdate, db: Session = Depends(get_db)):
|
|
ww = db.query(models.ViewWireWaypoints).filter_by(view_id=view_id, wire_id=wire_id).first()
|
|
if ww:
|
|
ww.waypoints = payload.waypoints
|
|
else:
|
|
ww = models.ViewWireWaypoints(view_id=view_id, wire_id=wire_id, waypoints=payload.waypoints)
|
|
db.add(ww)
|
|
db.commit()
|
|
return {"ok": True}
|