Add Pattern Templates for Key Colors targets with visual canvas editor
Introduce Pattern Template entity as a reusable rectangle layout that Key Colors targets reference via pattern_template_id. This replaces inline rectangle storage with a shared template system. Backend: - New PatternTemplate data model, store (JSON persistence), CRUD API - KC targets now reference pattern_template_id instead of inline rectangles - ProcessorManager resolves pattern template at KC processing start - Picture source test endpoint supports capture_duration=0 for single frame - Delete protection: 409 when template is referenced by a KC target Frontend: - Pattern Templates section in Key Colors sub-tab with card UI - Visual canvas editor with drag-to-move, 8-point resize handles - Background capture from any picture source for visual alignment - Precise coordinate list synced bidirectionally with canvas - Resizable editor container, viewport-constrained modal - KC target editor uses pattern template dropdown instead of inline rects - Localization (en/ru) for all new UI elements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
"""Pattern template data model for key color rectangle layouts."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from wled_controller.storage.key_colors_picture_target import KeyColorRectangle
|
||||
|
||||
|
||||
@dataclass
|
||||
class PatternTemplate:
|
||||
"""Pattern template containing a named layout of key color rectangles."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
rectangles: List[KeyColorRectangle]
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
description: Optional[str] = None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert to dictionary."""
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"rectangles": [r.to_dict() for r in self.rectangles],
|
||||
"created_at": self.created_at.isoformat(),
|
||||
"updated_at": self.updated_at.isoformat(),
|
||||
"description": self.description,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "PatternTemplate":
|
||||
"""Create from dictionary."""
|
||||
rectangles = [KeyColorRectangle.from_dict(r) for r in data.get("rectangles", [])]
|
||||
return cls(
|
||||
id=data["id"],
|
||||
name=data["name"],
|
||||
rectangles=rectangles,
|
||||
created_at=datetime.fromisoformat(data["created_at"])
|
||||
if isinstance(data.get("created_at"), str)
|
||||
else data.get("created_at", datetime.utcnow()),
|
||||
updated_at=datetime.fromisoformat(data["updated_at"])
|
||||
if isinstance(data.get("updated_at"), str)
|
||||
else data.get("updated_at", datetime.utcnow()),
|
||||
description=data.get("description"),
|
||||
)
|
||||
Reference in New Issue
Block a user