4310a5cc2d
Frontend: - Vite + React 18 + TypeScript + Tailwind v4 + Shadcn/ui - React Flow v12 canvas with all 11 node types and 5 edge types - Dark theme with project design system (cyan, green, orange, purple accents) - Collapsible sidebar, toolbar, detail panel - Zustand store for canvas state - Demo data with 10 nodes and 10 edges Backend: - FastAPI + SQLAlchemy async + SQLite (Python 3.13) - DB models: Node, Edge, CanvasState, PendingDevice, ScanRun - REST API routes: auth, nodes, edges, canvas, scan, status (WebSocket) - JWT auth + bcrypt via config.yml - Pydantic v2 schemas Infra: - GitHub Actions quality + security workflows - .gitignore, .env.example, verify-tooling.sh, security-check.sh
43 lines
1.5 KiB
Python
43 lines
1.5 KiB
Python
from datetime import datetime, timezone
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.api.deps import get_current_user
|
|
from app.db.database import get_db
|
|
from app.db.models import CanvasState, Edge, Node
|
|
from app.schemas.canvas import CanvasSaveRequest, CanvasStateResponse
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/", response_model=CanvasStateResponse)
|
|
async def load_canvas(db: AsyncSession = Depends(get_db), _: str = Depends(get_current_user)):
|
|
nodes = (await db.execute(select(Node))).scalars().all()
|
|
edges = (await db.execute(select(Edge))).scalars().all()
|
|
state = await db.get(CanvasState, 1)
|
|
viewport = state.viewport if state else {"x": 0, "y": 0, "zoom": 1}
|
|
return CanvasStateResponse(nodes=list(nodes), edges=list(edges), viewport=viewport)
|
|
|
|
|
|
@router.post("/save")
|
|
async def save_canvas(body: CanvasSaveRequest, db: AsyncSession = Depends(get_db), _: str = Depends(get_current_user)):
|
|
# Update node positions from canvas
|
|
for node_pos in body.node_positions:
|
|
node = await db.get(Node, node_pos.id)
|
|
if node:
|
|
node.pos_x = node_pos.x
|
|
node.pos_y = node_pos.y
|
|
|
|
# Upsert viewport
|
|
state = await db.get(CanvasState, 1)
|
|
if state:
|
|
state.viewport = body.viewport
|
|
state.saved_at = datetime.now(timezone.utc)
|
|
else:
|
|
db.add(CanvasState(id=1, viewport=body.viewport))
|
|
|
|
await db.commit()
|
|
return {"saved": True}
|