feat(ui): pattern modes, bundles, and zone content kind

Add profile/preset/sequence JSON import and export; map preset mode to
wire n6 with a mode dropdown for multi-mode patterns; zone edit shows
presets or sequences only with content_kind on save; update catalogue
and tests for merged pattern names.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-16 21:12:42 +12:00
parent 6286297646
commit 96d1e1b5fd
28 changed files with 1715 additions and 458 deletions

View File

@@ -46,6 +46,22 @@ class Zone(Model):
if changed:
self.save()
@staticmethod
def _normalized_content_kind(doc):
if not isinstance(doc, dict):
return None
kind = doc.get("content_kind")
return kind if kind in ("presets", "sequences") else None
def _enforce_content_kind_invariants(self, doc):
"""Presets-only zones hold no sequences; sequences-only hold no preset tiles."""
kind = self._normalized_content_kind(doc)
if kind == "presets":
doc["sequence_ids"] = []
elif kind == "sequences":
doc["presets"] = []
doc["presets_flat"] = []
def create(self, name="", names=None, presets=None, group_ids=None, content_kind=None):
next_id = self.get_next_id()
gid_list = []
@@ -62,6 +78,9 @@ class Zone(Model):
}
if content_kind in ("presets", "sequences"):
doc["content_kind"] = content_kind
if "sequence_ids" not in doc:
doc["sequence_ids"] = []
self._enforce_content_kind_invariants(doc)
self[next_id] = doc
self.save()
return next_id
@@ -74,7 +93,9 @@ class Zone(Model):
id_str = str(id)
if id_str not in self:
return False
self[id_str].update(data)
patch = data if isinstance(data, dict) else {}
self[id_str].update(patch)
self._enforce_content_kind_invariants(self[id_str])
self.save()
return True