feat(zones): profile-scoped groups, zone modes, sequence brightness

- Optional profile_id on groups; UI and API for shared vs profile-only groups\n- Zone content_kind (presets vs sequences); edit modal shows matching sections; devices via groups only\n- Server sequence playback folds zone brightness into preset wire b (per MAC where needed)\n- Related preset/sequence/audio/beat-route and client updates

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-13 01:58:00 +12:00
parent c1c3e5d71b
commit 6c9e06f33b
21 changed files with 1034 additions and 604 deletions

View File

@@ -26,7 +26,8 @@ def test_sequence():
assert sequence["steps"] == []
assert sequence["lanes"] == [[]]
assert sequence.get("lanes_group_ids") == [[]]
assert sequence.get("advance_mode") == "time"
assert sequence.get("advance_mode") == "beats"
assert sequence.get("simulated_bpm") == 120
assert sequence["step_duration_ms"] == 3000
assert sequence["loop"] is True
assert sequence.get("sequence_transition") == 500
@@ -42,6 +43,7 @@ def test_sequence():
"step_duration_ms": 5000,
"loop": True,
"advance_mode": "beats",
"simulated_bpm": 128,
}
result = sequences.update(sequence_id, update_data)
assert result is True
@@ -56,6 +58,7 @@ def test_sequence():
assert len(updated["lanes"][0]) == 2
assert updated["lanes"][0][0]["beats"] == 2
assert updated.get("advance_mode") == "beats"
assert updated.get("simulated_bpm") == 128
assert updated["step_duration_ms"] == 5000
assert updated["loop"] is True