Repository navigation
Pin a section, and pair sections with the loop - #624
Merged
Merged
Conversation
added 2 commits
September 13, 2026 10:39
A padlock beside the delete cross locks a section's position: drag and resize both refuse while it is set. The flag had to be declared on SectionItem to exist at all. That model takes Pydantic's default extra="ignore", so an undeclared `locked` sent by the editor was dropped on save and answered 200: locking would have looked right until the next load, with nothing in the response, the logs or metadata.json saying otherwise. Both new tests fail without the field. A locked block shows its padlock without being hovered. Hiding it would leave locked and unlocked identical at rest, and the only way to find a locked one would be to try to drag it. Addresses part of discussion #573.
Add now builds the section on the armed loop instead of hunting for the first gap. That was the complaint: you select a region, press Add, and a section appears at the start of the track with nothing saying why. With no loop armed the old gap search is unchanged. Clicking a section arms the loop over it. A press that never moved was already doing nothing, so the gesture was free. It is tracked apart from the drag so a locked section can still be looped: that reads the section without changing it. Sections cannot overlap, so a loop drawn across one is refused and says so beside the button that was pressed, rather than being trimmed to fit or displacing a neighbour. Either would hand back a different region than the one selected, and displacing could move a section just locked. Renaming was already broken on main, and this is where it surfaced. The drag calls setPointerCapture, which retargets the rest of the gesture to the capturing element, so the dblclick ending a real double-click was delivered to the block while the listener sat on the child label and never ran. Synthetic events do not capture, which is why dispatching the sequence by hand worked perfectly and every actual double-click did not. The listener moves to the block. Rename had no browser test at all. Lock now covers editing rather than position alone: drag, resize and rename all refuse, and the padlock turns red, using the same --danger the rest of the app uses to say no. Delete stays available, because the cross is an explicit press on one named target. sections.js deliberately does not import transport.js. transport reaches the DOM at import time through state.js, and pulling it in broke this module's Node test outright. main.js owns both and hands the two functions over instead, the same reason loopRegion.js is separate. Seventeen browser tests, where there were none for lock or rename. Each was confirmed to fail without the change it covers, including the pair that would otherwise let a drag retarget the loop on every move, and the one asserting an unlocked section still drags, without which the locked case proves nothing. Addresses discussion #573, and #474 asked for the loop pairing too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #621
Closes #622
Closes #623
Three changes to the sections ribbon, two asked for and one found on the way.
Pin a section against editing
A padlock sits beside the delete cross. While it is set, drag, resize and rename all refuse, and the padlock turns red so a locked section is obvious at rest rather than only once a drag fails.
Looping over a locked section still works. That reads the section without changing it, and it is the gesture most likely to be wanted on one pinned precisely because it matters. Delete stays available: the cross is an explicit press on one named target, not something a pointer does on the way past.
The flag had to be declared on
SectionItemto exist at all. That model takes Pydantic's defaultextra="ignore", so an undeclaredlockedwas dropped on save and answered 200. Locking would have looked right until the next load, with nothing in the response, the logs ormetadata.jsonsaying otherwise. Two backend tests cover the round trip and both fail without the field.A loop becomes a section, and a section becomes a loop
Add now builds the section on the armed loop instead of hunting for the first gap. With no loop armed the old gap search is unchanged.
Clicking a section arms the loop over it. A press that never moved was already doing nothing, so the gesture was free. Double-click stays rename.
A loop drawn across an existing section is refused, and says so beside the button that was pressed. Trimming it to fit or displacing the neighbours both hand back a different region than the one selected, and displacing could move a section just locked.
Renaming was broken on main
Double-clicking a label did nothing, for every section on every track.
The drag calls
setPointerCapture, and capture retargets the rest of the gesture to the capturing element. So thedblclickending a real double-click was delivered to the block while the listener sat on the child label, and never ran. Dispatching the events by hand works perfectly, which is why a console check would have cleared it. The listener moves to the block.Confirmed pre-existing by checking out
main'ssections.jsand watching the same test fail.A note on the module boundary
sections.jsdeliberately does not importtransport.js. The transport reaches the DOM at import time throughstate.js, and pulling it in broke this module's Node unit test outright.main.jsowns both and hands the two functions over instead, the same reasonloopRegion.jsis its own module.Testing
Seventeen browser tests, across lock, loop and rename. Lock and rename had none at all before this.
Each was confirmed to fail without the change it covers, including the three that exist to stop a passing test proving nothing:
Full suite: 170 passed, 0 failed.
uv.lockuntouched, i18n clean at 524 keys across 10 locales.Addresses discussion #573 in full, and the loop pairing in #474.