46435605eb
Backend: New Design model + designs table; design_id FK on nodes, edges, canvas_state; migration seeds default 'Network Topology' design; full CRUD API for designs; canvas load/save accept design_id. Frontend: designStore (Zustand), design switcher in Sidebar, design-aware canvas load/save, auto-save on design switch. Electrical node types (14): grid, ups, battery, generator, solar_panel, inverter, circuit_breaker, contactor, electrical_switch, socket, light, meter, transformer, load — icons, registrations, accent colors in all 6 themes. Electrical edge type: registered in edgeTypes, BASE_STYLES, edgeColors, all theme edgeColors, EDGE_DEFAULT_COLORS. Bug fixes: data corruption on design switch (stale closure), race condition on save-then-load, missing Zap import, missing Electrical group in NodeModal, missing electrical entries in custom theme edgeColors, inline imports hoisted.
74 lines
1.9 KiB
Python
74 lines
1.9 KiB
Python
from typing import Any
|
|
|
|
from pydantic import BaseModel, field_validator
|
|
|
|
from app.schemas.edges import EdgeResponse
|
|
from app.schemas.nodes import NodeResponse
|
|
from app.schemas.utils import normalize_animated
|
|
|
|
|
|
class NodeSave(BaseModel):
|
|
id: str
|
|
type: str
|
|
label: str
|
|
hostname: str | None = None
|
|
ip: str | None = None
|
|
mac: str | None = None
|
|
os: str | None = None
|
|
status: str = "unknown"
|
|
check_method: str | None = None
|
|
check_target: str | None = None
|
|
services: list[Any] = []
|
|
notes: str | None = None
|
|
parent_id: str | None = None
|
|
container_mode: bool = False
|
|
custom_colors: dict[str, Any] | None = None
|
|
custom_icon: str | None = None
|
|
cpu_count: int | None = None
|
|
cpu_model: str | None = None
|
|
ram_gb: float | None = None
|
|
disk_gb: float | None = None
|
|
show_hardware: bool = False
|
|
properties: list[Any] = []
|
|
width: float | None = None
|
|
height: float | None = None
|
|
bottom_handles: int = 1
|
|
pos_x: float = 0
|
|
pos_y: float = 0
|
|
|
|
|
|
class EdgeSave(BaseModel):
|
|
id: str
|
|
source: str
|
|
target: str
|
|
type: str = "ethernet"
|
|
label: str | None = None
|
|
vlan_id: int | None = None
|
|
speed: str | None = None
|
|
custom_color: str | None = None
|
|
path_style: str | None = None
|
|
animated: str = 'none'
|
|
source_handle: str | None = None
|
|
target_handle: str | None = None
|
|
waypoints: list[dict[str, float]] | None = None
|
|
|
|
@field_validator('animated', mode='before')
|
|
@classmethod
|
|
def validate_animated(cls, v: object) -> str:
|
|
return normalize_animated(v)
|
|
|
|
|
|
class CanvasSaveRequest(BaseModel):
|
|
nodes: list[NodeSave] = []
|
|
edges: list[EdgeSave] = []
|
|
viewport: dict[str, Any] = {}
|
|
custom_style: dict[str, Any] | None = None
|
|
design_id: str | None = None
|
|
|
|
|
|
class CanvasStateResponse(BaseModel):
|
|
nodes: list[NodeResponse]
|
|
edges: list[EdgeResponse]
|
|
viewport: dict[str, Any]
|
|
custom_style: dict[str, Any] | None = None
|