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

@@ -3,11 +3,14 @@ from microdot.session import with_session
from models.sequence import Sequence
from models.profile import Profile
from models.transport import get_current_sender
from models.preset import Preset
from util.profile_bundle import export_sequence_bundle, import_sequence_bundle
import json
controller = Microdot()
sequences = Sequence()
profiles = Profile()
presets = Preset()
def get_current_profile_id(session=None):
@@ -39,6 +42,57 @@ async def list_sequences(request, session):
return json.dumps(scoped), 200, {"Content-Type": "application/json"}
@controller.get("/<id>/export")
@with_session
async def export_sequence(request, session, id):
"""Export a sequence and referenced presets as a JSON bundle."""
current_profile_id = get_current_profile_id(session)
if not current_profile_id:
return json.dumps({"error": "No profile available"}), 404, {"Content-Type": "application/json"}
try:
bundle = export_sequence_bundle(
id,
sequences,
presets,
profile_id=current_profile_id,
)
return json.dumps(bundle), 200, {"Content-Type": "application/json"}
except ValueError as e:
return json.dumps({"error": str(e)}), 404, {"Content-Type": "application/json"}
@controller.post("/import")
@with_session
async def import_sequence(request, session):
"""Import a sequence bundle into the current profile."""
try:
current_profile_id = get_current_profile_id(session)
if not current_profile_id:
return (
json.dumps({"error": "No profile available"}),
404,
{"Content-Type": "application/json"},
)
body = request.json or {}
bundle = body.get("bundle") if isinstance(body, dict) else body
if not isinstance(bundle, dict):
return (
json.dumps({"error": "Expected JSON bundle"}),
400,
{"Content-Type": "application/json"},
)
new_id, seq_data = import_sequence_bundle(bundle, sequences, presets, current_profile_id)
return (
json.dumps({new_id: seq_data}),
201,
{"Content-Type": "application/json"},
)
except ValueError as e:
return json.dumps({"error": str(e)}), 400, {"Content-Type": "application/json"}
except Exception as e:
return json.dumps({"error": str(e)}), 400, {"Content-Type": "application/json"}
@controller.get("/<id>")
@with_session
async def get_sequence(request, session, id):