Files
CableGUI/web
mAi 7f0b6e4fab feat(ui): type-aware device creation + port rendering
Modal-driven +Dev (replaces the v3 inline namer):
- Tool armed → click on canvas captures the click position + frame_id
  from frameAt(p), then opens a #modal-new-device dialog.
- Dialog has a <select> grouped by `kind` for built-ins, then
  project-custom rows, then "Custom (no type)" at the bottom.
- Default selection is the first built-in (NAS). Name input is
  auto-pre-filled to <type-name>, bumping to <type-name>-N if a name
  collision is detected in the current device list.
- Submit POSTs name + type_id + x/y/w/h + frame_id. Server seeds the
  ports in the same transaction; we re-snapshot to pick them up.

Canvas:
- After each device's <rect> + label, render the device's ports as
  white-filled <circle>s with stroke = the port's cable_type colour.
- Position: (device.x + port.x_offset, device.y + port.y_offset). The
  seeder's "evenly along the edge" layout means ports already sit on
  the device's bottom edge by default and follow the device on drag
  (because they re-render from the same x/y on every renderCanvas).
- Ports themselves are `pointer-events: none` for slice 4 — selection
  remains device-level. Per-port click semantics ship in slice 7
  (manual cable draw).

Inspector device pane:
- New "type" row showing the type name + a "(custom)" badge for
  project-custom types, or "Custom (no type)" for freeform.
- New "Ports" section with one row per seeded port: cable-type-colour
  swatch, label, "unconnected" placeholder. Label falls back to the
  cable type's name when the seeded label_prefix was blank.

State + snapshot:
- state.ports populated from snap.ports; cleared on project switch /
  404.
- state.deviceTypes hydrated from GET /api/projects/:pid/device-types
  after the snapshot loads. Failure of that fetch is non-fatal — the
  +Dev modal just shows "Custom (no type)" only.
- Delete-device cleans up its ports from state.ports too (server-side
  CASCADE already handles persistence).
2026-05-16 00:31:55 +02:00
..