Playlists: move a playlist or folder between folders - #42
Conversation
Folder-drop and drag-between were listed as two gaps; they are one missing change kind. `PlaylistReorder` writes `djmdPlaylist.Seq` and puts the parent in its `WHERE` clause specifically so a reorder cannot restructure the tree — a good decision that means moving needs its own verb. `PlaylistMove` carries two refusals, because `djmdPlaylist` enforces neither and both corrupt the tree: - **The destination must be a folder.** Rekordbox nests under folders only; a playlist parented to a playlist is a shape nothing renders, so it would simply vanish from the sidebar. - **A folder cannot go inside itself or a descendant.** This is the one that matters: it does not error and it loses no data, it just detaches that entire subtree from the root. The playlists still exist in `djmdPlaylist` and there is no path to them from the tree, ever. Three smaller decisions: - **The UI mirrors both refusals** rather than letting the applier be the only guard. Duplication I would normally argue against, but without it the drop looks like it worked and the rejection surfaces only when the user opens the review table — by which point they have made several more drops on a tree that was lying to them. A folder highlights only when the drop is acceptable. - **The ancestor walk goes upward from the destination**, not downward from the dragged folder: a tree is far wider than it is deep. Both the Rust and the TypeScript version keep a `seen` set, because a database that already contains a cycle must not hang the sync or the render — and the move is not what created that problem, so it reports "not a descendant" and proceeds. - **`old_parent_id` rides on the change.** Without it `changes::undo` blocks the inverse and the tree cannot be put back, which for a drag — the easiest edit in the app to make by accident — is where undo actually matters. The rules live in `lib/playlist-tree.ts` rather than inside the drop handler, for the same reason `reorder.ts` exists: jsdom does not run drag events, so a rule that lives in a handler is a rule nothing tests. The move is staged, not written: the tree redraws from `master.db`, so the row does not appear to move until Sync applies it. Per docs/lexicon/02-library.md §Playlists.
|
Warning Review limit reached
Next review available in: 34 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (13)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Folder-drop and drag-between were listed as two gaps. They are one missing change kind. Playlists tree moves to
done.PlaylistReorderalready writesdjmdPlaylist.Seq, and its SQL puts the parent in theWHEREclause specifically so a reorder cannot move anything between folders. That was the right call — a reorder that restructured the tree would be a nasty surprise — and it means moving needs its own verb.Two refusals, because
djmdPlaylistenforces neitherdjmdPlaylist, and there is no path to them from the tree, ever. Silent and total.Three smaller decisions
seenset — a database that already contains a cycle must not hang the sync or the render, and the move is not what created that problem, so it reports "not a descendant" and lets the write through.old_parent_idrides on the change. Without itchanges::undoblocks the inverse and the tree cannot be put back — and for a drag, the easiest edit in the app to make by accident, that is exactly where undo matters.The rules live in
lib/playlist-tree.tsrather than inside the drop handler, for the same reasonreorder.tsexists: jsdom does not run drag events, so a rule that lives in a handler is a rule nothing tests.The move is staged, not written — the tree redraws from
master.db, so the row does not appear to move until Sync applies it. Honest behaviour for a change that has not happened yet.Verification
Matrix moves to 59 done / 21 partial / 14 missing / 2 blocked / 16 deferred; Library & browser is now 16 done / 1 partial, the remaining one being the track table's missing drag source.
Generated by Claude Code