feat: manage canvases with custom name and icon

Make designs (canvases) fully user-manageable: create with a chosen name
and icon, rename, change icon, and delete. Replaces the hardcoded
"New Electrical Design" button with a generic "New Canvas" flow.

- Add Design.icon column + migration that backfills legacy rows
  (electrical -> zap, others -> dashboard)
- DesignModal: name input + curated lucide icon picker (create + edit)
- Sidebar switcher gains per-canvas edit/delete; delete guards the last
  canvas and confirms
- designStore: addDesign/updateDesign/removeDesign with active reassignment
- Fix data loss on design switch: abort load when the save fails and keep
  unsaved edits; skip the save-old step when the previous canvas was deleted
- designsApi create/update carry icon; design_type kept for back-compat

Tests: backend design CRUD (icon + cascade + last-canvas guard), designStore
actions, designIcons resolver, DesignModal create/edit/validation.

ha-relevant: yes
This commit is contained in:
Pouzor
2026-06-02 15:47:57 +02:00
parent eb7b0c6d38
commit 12d527aad6
15 changed files with 693 additions and 42 deletions
+15 -2
View File
@@ -183,6 +183,19 @@ async def init_db() -> None:
")",
label="designs.table",
)
# Add user-chosen icon to designs (idempotent), then backfill existing rows
# so legacy designs keep a sensible icon based on their original type.
await _try_migrate(
conn, "ALTER TABLE designs ADD COLUMN icon VARCHAR", label="designs.icon",
)
with suppress(OperationalError):
await conn.exec_driver_sql(
"UPDATE designs SET icon = 'zap' WHERE icon IS NULL AND design_type = 'electrical'"
)
with suppress(OperationalError):
await conn.exec_driver_sql(
"UPDATE designs SET icon = 'dashboard' WHERE icon IS NULL"
)
# Seed default Network Topology design if designs table is empty
_default_design_id = str(_uuid_mod.uuid4())
row = await conn.exec_driver_sql("SELECT COUNT(*) FROM designs")
@@ -190,8 +203,8 @@ async def init_db() -> None:
count = count_row[0] if count_row else 0
if count == 0:
await conn.exec_driver_sql(
"INSERT INTO designs (id, name, design_type, created_at, updated_at) "
"VALUES (?, 'Network Topology', 'network', datetime('now'), datetime('now'))",
"INSERT INTO designs (id, name, design_type, icon, created_at, updated_at) "
"VALUES (?, 'Network Topology', 'network', 'dashboard', datetime('now'), datetime('now'))",
(_default_design_id,),
)
else: